import { addDisposableListener, getDomNodePagePosition } from '../../../../../../base/browser/dom.js';
import { Action } from '../../../../../../base/common/actions.js';
import { DisposableStore } from '../../../../../../base/common/lifecycle.js';
import { Position } from '../../../../../common/core/position.js';
import { Range } from '../../../../../common/core/range.js';
import { localize } from '../../../../../../nls.js';

/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
function enableCopySelection(options) {
    const { domNode, getViewZoneId, diffEntry, originalModel, editorLineHeight, viewLineCounts, editor, showContextMenu, clipboardService, } = options;
    let lastMouseDownPosition;
    const viewZoneDisposable = new DisposableStore();
    viewZoneDisposable.add(editor.onMouseDown(e => {
        if (!e.event.leftButton) {
            return;
        }
        if (e.target.type !== 8 /* MouseTargetType.CONTENT_VIEW_ZONE */ &&
            e.target.type !== 5 /* MouseTargetType.GUTTER_VIEW_ZONE */) {
            return;
        }
        if (e.target.detail.viewZoneId !== getViewZoneId()) {
            return;
        }
        const lineNumberOffset = calculateLineNumberOffset(e.event.browserEvent.y, domNode, editorLineHeight, viewLineCounts);
        const lineNumber = diffEntry.original.startLineNumber + lineNumberOffset;
        lastMouseDownPosition = new Position(lineNumber, getRealColumnNumber(e.target.mouseColumn, lineNumber, originalModel));
    }));
    viewZoneDisposable.add(editor.onMouseUp(e => {
        if (!lastMouseDownPosition) {
            return;
        }
        const mouseDownPosition = lastMouseDownPosition;
        lastMouseDownPosition = undefined;
        if (!e.event.leftButton) {
            return;
        }
        if ((e.target.type !== 8 /* MouseTargetType.CONTENT_VIEW_ZONE */ &&
            e.target.type !== 5 /* MouseTargetType.GUTTER_VIEW_ZONE */) ||
            e.target.detail.viewZoneId !== getViewZoneId()) {
            return;
        }
        const lineNumberOffset = calculateLineNumberOffset(e.event.browserEvent.y, domNode, editorLineHeight, viewLineCounts);
        const lineNumber = diffEntry.original.startLineNumber + lineNumberOffset;
        const mouseUpPosition = new Position(lineNumber, getRealColumnNumber(e.target.mouseColumn, lineNumber, originalModel));
        const range = mouseUpPosition.isBefore(mouseDownPosition) ?
            Range.fromPositions(mouseUpPosition, mouseDownPosition) :
            Range.fromPositions(mouseDownPosition, mouseUpPosition);
        const selectedText = originalModel.getValueInRange(range);
        const onCopy = viewZoneDisposable.add(addDisposableListener(domNode, 'copy', (e) => {
            e.preventDefault();
            clipboardService.writeText(selectedText);
        }));
        showContextMenu({ x: e.event.posx, y: e.event.posy + editorLineHeight }, selectedText ?
            [new Action('diff.clipboard.copySelectedDeletedContent', localize(114, 'Copy Selection'), undefined, true, async () => clipboardService.writeText(selectedText))] :
            [], () => {
            onCopy.dispose();
        });
    }));
    return viewZoneDisposable;
}
/**
 * Calculate the line number offset of the given browser event y-coordinate in a
 * view zone.
 *
 * @param y The y-coordinate position of the browser event.
 * @param viewZoneNode The view zone HTML element.
 * @param editorLineHeight The line height of the editor.
 * @param viewLineCounts The actual view lines for each editor line (considers
 *     line-wrapping).
 * @return The line number offset in the given view zone.
 */
function calculateLineNumberOffset(y, viewZoneNode, editorLineHeight, viewLineCounts) {
    const { top } = getDomNodePagePosition(viewZoneNode);
    const offset = y - top;
    const lineNumberOffset = Math.floor(offset / editorLineHeight);
    let acc = 0;
    for (let i = 0; i < viewLineCounts.length; i++) {
        acc += viewLineCounts[i];
        if (lineNumberOffset < acc) {
            return i;
        }
    }
    return lineNumberOffset;
}
/**
 * Get the real column number of the given mouse column in a view zone. This
 * compensates for different tab sizes.
 *
 * @param mouseColumn The mouse column position of the browser event.
 * @param lineNumber The line number of the original text model.
 * @param textModel The original text model.
 * @return The real column number of the given mouse column in the view zone.
 */
function getRealColumnNumber(mouseColumn, lineNumber, textModel) {
    const lineContent = textModel.getLineContent(lineNumber);
    let i = 0;
    while (i < lineContent.length && lineContent[i] === '\t') {
        i++;
    }
    return Math.max(1, mouseColumn - i * (textModel.getOptions().tabSize - 1));
}

export { enableCopySelection };
