/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { addDisposableListener } from '../../../../base/browser/dom.js';
import { createCancelablePromise } from '../../../../base/common/async.js';
import { createStringDataTransferItem } from '../../../../base/common/dataTransfer.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { Mimes } from '../../../../base/common/mime.js';
import { generateUuid } from '../../../../base/common/uuid.js';
import { toVSDataTransfer } from '../../../browser/dnd.js';
import { IBulkEditService, ResourceEdit } from '../../../browser/services/bulkEditService.js';
import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
import { EditorStateCancellationTokenSource } from '../../editorState/browser/editorState.js';
import { performSnippetEdit } from '../../snippet/browser/snippetController2.js';
import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
const vscodeClipboardMime = 'application/vnd.code.copyId';
const defaultPasteEditProvider = new class {
    provideDocumentPasteEdits(model, selection, dataTransfer, _token) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const textDataTransfer = (_a = dataTransfer.get(Mimes.text)) !== null && _a !== void 0 ? _a : dataTransfer.get('text');
            if (textDataTransfer) {
                const text = yield textDataTransfer.asString();
                return {
                    edits: [{
                            resource: model.uri,
                            edit: { range: selection, text },
                        }]
                };
            }
            return undefined;
        });
    }
};
let CopyPasteController = class CopyPasteController extends Disposable {
    constructor(editor, _bulkEditService, _clipboardService, _configurationService, _languageFeaturesService) {
        super();
        this._bulkEditService = _bulkEditService;
        this._clipboardService = _clipboardService;
        this._configurationService = _configurationService;
        this._languageFeaturesService = _languageFeaturesService;
        this._editor = editor;
        const container = editor.getContainerDomNode();
        this._register(addDisposableListener(container, 'copy', (e) => {
            var _a;
            if (!e.clipboardData) {
                return;
            }
            const model = editor.getModel();
            const selection = this._editor.getSelection();
            if (!model || !selection) {
                return;
            }
            if (!this.arePasteActionsEnabled(model)) {
                return;
            }
            const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model).filter(x => !!x.prepareDocumentPaste);
            if (!providers.length) {
                return;
            }
            const dataTransfer = toVSDataTransfer(e.clipboardData);
            // Save off a handle pointing to data that VS Code maintains.
            const handle = generateUuid();
            e.clipboardData.setData(vscodeClipboardMime, handle);
            const promise = createCancelablePromise((token) => __awaiter(this, void 0, void 0, function* () {
                const results = yield Promise.all(providers.map(provider => {
                    return provider.prepareDocumentPaste(model, selection, dataTransfer, token);
                }));
                for (const result of results) {
                    result === null || result === void 0 ? void 0 : result.forEach((value, key) => {
                        dataTransfer.replace(key, value);
                    });
                }
                return dataTransfer;
            }));
            (_a = this._currentClipboardItem) === null || _a === void 0 ? void 0 : _a.dataTransferPromise.cancel();
            this._currentClipboardItem = { handle: handle, dataTransferPromise: promise };
        }));
        this._register(addDisposableListener(container, 'paste', (e) => __awaiter(this, void 0, void 0, function* () {
            var _a, _b;
            const selection = this._editor.getSelection();
            if (!e.clipboardData || !selection || !editor.hasModel()) {
                return;
            }
            const model = editor.getModel();
            if (!this.arePasteActionsEnabled(model)) {
                return;
            }
            const originalDocVersion = model.getVersionId();
            const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model);
            if (!providers.length) {
                return;
            }
            const handle = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData(vscodeClipboardMime);
            if (typeof handle !== 'string') {
                return;
            }
            e.preventDefault();
            e.stopImmediatePropagation();
            const tokenSource = new EditorStateCancellationTokenSource(editor, 1 /* CodeEditorStateFlag.Value */ | 2 /* CodeEditorStateFlag.Selection */);
            try {
                const dataTransfer = toVSDataTransfer(e.clipboardData);
                if (handle && ((_b = this._currentClipboardItem) === null || _b === void 0 ? void 0 : _b.handle) === handle) {
                    const toMergeDataTransfer = yield this._currentClipboardItem.dataTransferPromise;
                    toMergeDataTransfer.forEach((value, key) => {
                        dataTransfer.append(key, value);
                    });
                }
                if (!dataTransfer.has(Mimes.uriList)) {
                    const resources = yield this._clipboardService.readResources();
                    if (resources.length) {
                        const value = resources.join('\n');
                        dataTransfer.append(Mimes.uriList, createStringDataTransferItem(value));
                    }
                }
                dataTransfer.delete(vscodeClipboardMime);
                for (const provider of [...providers, defaultPasteEditProvider]) {
                    const edit = yield provider.provideDocumentPasteEdits(model, selection, dataTransfer, tokenSource.token);
                    if (originalDocVersion !== model.getVersionId()) {
                        return;
                    }
                    if (edit) {
                        if (edit.edits) {
                            yield this._bulkEditService.apply(ResourceEdit.convert(edit), { editor });
                        }
                        else {
                            performSnippetEdit(editor, edit);
                        }
                        return;
                    }
                }
            }
            finally {
                tokenSource.dispose();
            }
        }), true));
    }
    arePasteActionsEnabled(model) {
        return this._configurationService.getValue('editor.experimental.pasteActions.enabled', {
            resource: model.uri
        });
    }
};
CopyPasteController.ID = 'editor.contrib.copyPasteActionController';
CopyPasteController = __decorate([
    __param(1, IBulkEditService),
    __param(2, IClipboardService),
    __param(3, IConfigurationService),
    __param(4, ILanguageFeaturesService)
], CopyPasteController);
export { CopyPasteController };
