"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtHostCustomEditorImpl = void 0;
const ide_core_common_1 = require("@opensumi/ide-core-common");
const vscode_1 = require("../../../common/vscode");
const ext_types_1 = require("../../../common/vscode/ext-types");
class ExtHostCustomEditorImpl {
    constructor(rpcProtocol, webview, extDocuments) {
        this.webview = webview;
        this.extDocuments = extDocuments;
        this.providers = new Map();
        this.customDocuments = new Map();
        this.proxy = rpcProtocol.getProxy(vscode_1.MainThreadAPIIdentifier.MainThreadCustomEditor);
    }
    registerCustomEditorProvider(viewType, provider, options, extensionInfo) {
        const type = getEditorType(provider);
        this.proxy.$registerCustomEditor(viewType, type, options, extensionInfo);
        this.providers.set(viewType, {
            type,
            provider: provider,
        });
        if (type === vscode_1.CustomEditorType.FullEditor || type === vscode_1.CustomEditorType.ReadonlyEditor) {
            this.customDocuments.set(viewType, {
                provider: provider,
                documents: new Map(),
            });
        }
        return {
            dispose: () => {
                this.providers.delete(viewType);
                this.customDocuments.delete(viewType);
                this.proxy.$unregisterCustomEditor(viewType);
            },
        };
    }
    async $saveCustomDocument(viewType, uriComp, token) {
        var _a, _b;
        const uri = ext_types_1.Uri.revive(uriComp);
        const document = (_b = (_a = this.customDocuments.get(viewType)) === null || _a === void 0 ? void 0 : _a.documents) === null || _b === void 0 ? void 0 : _b.get(uri.toString());
        if (document) {
            await document.save(token);
        }
    }
    async $revertCustomDocument(viewType, uriComp, token) {
        var _a, _b;
        const uri = ext_types_1.Uri.revive(uriComp);
        const document = (_b = (_a = this.customDocuments.get(viewType)) === null || _a === void 0 ? void 0 : _a.documents) === null || _b === void 0 ? void 0 : _b.get(uri.toString());
        if (document) {
            await document.revert(token);
        }
    }
    async $resolveCustomTextEditor(viewType, uriParts, webviewPanelId, token) {
        var _a, _b;
        const provider = this.providers.get(viewType);
        if (!provider) {
            throw new Error(`no custom editor provider for ${viewType}`);
        }
        const webviewPanel = this.webview.getWebviewPanel(webviewPanelId);
        if (!webviewPanel) {
            throw new Error(`no webview ${webviewPanelId} for custom editor ${viewType}`);
        }
        const uri = ext_types_1.Uri.revive(uriParts);
        if (provider.type === vscode_1.CustomEditorType.TextEditor) {
            const document = this.extDocuments.getDocument(uri);
            if (!document) {
                throw new Error(`no document ${uri.toString()} for custom editor ${viewType}`);
            }
            provider.provider.resolveCustomTextEditor(document, webviewPanel, token);
        }
        else {
            let document = (_a = this.getCustomDocument(viewType, uri)) === null || _a === void 0 ? void 0 : _a.document;
            if (!document) {
                const openContext = {};
                if (uri.scheme === ide_core_common_1.Schemes.untitled) {
                    const untitledDoc = this.extDocuments.getDocument(uri);
                    // untitled 默认都是 utf8 编码
                    openContext.untitledDocumentData = untitledDoc && (0, ide_core_common_1.iconvEncode)(untitledDoc.getText(), 'utf-8');
                }
                document = await provider.provider.openCustomDocument(uri, openContext, token);
                if (!document) {
                    return;
                }
                const data = new CustomDocumentHostData(document, provider.provider);
                (_b = this.customDocuments.get(viewType)) === null || _b === void 0 ? void 0 : _b.documents.set(uri.toString(), data);
                data.onDidChange(() => {
                    this.proxy.$acceptCustomDocumentDirty(uri, data.dirty);
                });
                if (token.isCancellationRequested) {
                    return;
                }
            }
            provider.provider.resolveCustomEditor(document, webviewPanel, token);
        }
    }
    getCustomDocument(viewType, uri) {
        var _a, _b;
        return (_b = (_a = this.customDocuments.get(viewType)) === null || _a === void 0 ? void 0 : _a.documents) === null || _b === void 0 ? void 0 : _b.get(uri.toString());
    }
    async $undo(viewType, uriParts) {
        const uri = ext_types_1.Uri.revive(uriParts);
        const document = this.getCustomDocument(viewType, uri);
        if (document) {
            await document.undo();
        }
    }
    async $redo(viewType, uriParts) {
        const uri = ext_types_1.Uri.revive(uriParts);
        const document = this.getCustomDocument(viewType, uri);
        if (document) {
            await document.redo();
        }
    }
}
exports.ExtHostCustomEditorImpl = ExtHostCustomEditorImpl;
function getEditorType(provider) {
    if (typeof provider.saveCustomDocument === 'function') {
        return vscode_1.CustomEditorType.FullEditor;
    }
    else if (typeof provider.openCustomDocument === 'function') {
        return vscode_1.CustomEditorType.ReadonlyEditor;
    }
    else {
        return vscode_1.CustomEditorType.TextEditor;
    }
}
class CustomDocumentHostData {
    constructor(_document, provider) {
        this._document = _document;
        this.provider = provider;
        this.edits = [];
        this.currentIndex = -1;
        this.savePoint = -1;
        this._onDidChange = new ide_core_common_1.Emitter();
        this.onDidChange = this._onDidChange.event;
        this._forceDirty = false;
        if (isNotReadonlyProvider(this.provider)) {
            this.provider.onDidChangeCustomDocument((e) => {
                if (e.document !== this.document) {
                    return;
                }
                if (isEditEvent(e)) {
                    this.addEdit(e);
                }
                else {
                    this._forceDirty = true;
                    this._onDidChange.fire();
                }
            });
        }
    }
    addEdit(edit) {
        if (this.currentIndex !== this.edits.length - 1) {
            this.edits.splice(this.currentIndex + 1, this.edits.length - this.currentIndex - 1);
        }
        this.edits.push(edit);
        this.currentIndex = this.edits.length - 1;
        // 添加编辑后，如果 savePoint 在 currentIndex 之后，说明这个savePoint 永远无法再达到了，设置为 -1
        if (this.savePoint >= this.currentIndex) {
            this.savePoint = -2;
        }
        this._onDidChange.fire();
    }
    get document() {
        return this._document;
    }
    async undo() {
        if (this.edits[this.currentIndex]) {
            const edit = this.edits[this.currentIndex];
            this.currentIndex--;
            await edit.undo();
            this._onDidChange.fire();
        }
    }
    async redo() {
        if (this.edits[this.currentIndex + 1]) {
            const edit = this.edits[this.currentIndex + 1];
            this.currentIndex++;
            await edit.redo();
            this._onDidChange.fire();
        }
    }
    async save(token) {
        if (isNotReadonlyProvider(this.provider)) {
            await this.provider.saveCustomDocument(this.document, token);
            this.savePoint = this.currentIndex;
            this._forceDirty = false;
            this._onDidChange.fire();
        }
    }
    async revert(token) {
        if (isNotReadonlyProvider(this.provider)) {
            await this.provider.revertCustomDocument(this.document, token);
            this.currentIndex = this.savePoint;
            this._forceDirty = false;
            this._onDidChange.fire();
        }
    }
    get dirty() {
        if (this._forceDirty) {
            return true;
        }
        return this.currentIndex !== this.savePoint;
    }
}
function isNotReadonlyProvider(provider) {
    return typeof provider.saveCustomDocument === 'function';
}
function isEditEvent(e) {
    return e.undo !== undefined && e.redo !== undefined;
}
//# sourceMappingURL=ext.host.custom-editor.js.map