"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtHostQuickOpen = 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 BaseQuickInput {
    constructor(_id, proxy) {
        this._id = _id;
        this.proxy = proxy;
        this._disposed = false;
        this._pendingUpdate = {};
        this._busy = false;
        this._ignoreFocusOut = false;
    }
    get busy() {
        return this._busy;
    }
    set busy(busy) {
        this._busy = busy;
        this.update({ busy });
    }
    get ignoreFocusOut() {
        return this._ignoreFocusOut;
    }
    set ignoreFocusOut(ignoreFocusOut) {
        this._ignoreFocusOut = ignoreFocusOut;
        this.update({ ignoreFocusOut });
    }
    get enabled() {
        return this._enabled;
    }
    set enabled(enabled) {
        this._enabled = enabled;
        this.update({ enabled });
    }
    update(data) {
        if (this._disposed) {
            return;
        }
        for (const k of Object.keys(data)) {
            data[k] = data[k] === undefined ? null : data[k];
        }
        this._pendingUpdate = { ...this._pendingUpdate, ...data };
        if (!this._updateTimeout) {
            // Defer the update so that multiple changes to setters dont cause a redraw each
            this._updateTimeout = setTimeout(() => {
                this._updateTimeout = undefined;
                this.doUpdate();
            }, 0);
        }
    }
    doUpdate() {
        if (this.type === 'quickPick') {
            this.proxy.$updateQuickPick(this._pendingUpdate);
        }
        else {
            this.proxy.$createOrUpdateInputBox(this._id, this._pendingUpdate);
        }
        this._pendingUpdate = {};
    }
}
class ExtHostQuickOpen {
    constructor(rpc, workspace) {
        this.workspace = workspace;
        this.createdQuicks = new Map(); // Each quick will have a number so that we know where to fire events
        this.createdInputBoxes = new Map();
        this.currentQuick = 0;
        this.proxy = rpc.getProxy(vscode_1.MainThreadAPIIdentifier.MainThreadQuickOpen);
    }
    async showQuickPick(promiseOrItems, options, token = ide_core_common_1.CancellationToken.None) {
        var _a, _b;
        // clear state from last invocation
        this._onDidSelectItem = undefined;
        const sessionId = (_a = options === null || options === void 0 ? void 0 : options._sessionId) !== null && _a !== void 0 ? _a : ++this.currentQuick;
        const items = await promiseOrItems;
        // handle selection changes
        if (options && typeof options.onDidSelectItem === 'function') {
            this._onDidSelectItem = (handle) => {
                options.onDidSelectItem(items[handle]);
            };
        }
        const pickItems = [];
        const pendingGroupItem = [];
        for (const [index, item] of items.entries()) {
            if (typeof item === 'string') {
                pickItems.push({
                    label: item,
                    value: index,
                });
            }
            else {
                if (item.kind === ext_types_1.QuickPickItemKind.Separator) {
                    pendingGroupItem.push(item);
                }
                else {
                    // group label 取上一个 kind 为 Separator 的 item label
                    const groupLabel = (_b = pendingGroupItem.pop()) === null || _b === void 0 ? void 0 : _b.label;
                    pickItems.push({
                        label: item.label,
                        groupLabel,
                        iconPath: item.iconPath,
                        description: item.description,
                        detail: item.detail,
                        value: index, // handle
                        buttons: item.buttons,
                        showBorder: typeof groupLabel !== 'undefined',
                    });
                }
            }
        }
        const quickPickPromise = this.proxy.$showQuickPick(sessionId, pickItems, options && {
            canPickMany: options.canPickMany,
            placeholder: options.placeHolder,
            fuzzyMatchDescription: options.matchOnDescription,
            fuzzyMatchDetail: options.matchOnDetail,
            ignoreFocusOut: options.ignoreFocusOut,
            keepScrollPosition: options.keepScrollPosition,
            title: options.title,
            buttons: options.buttons,
            step: options.step,
            totalSteps: options.totalSteps,
            value: options.value,
            busy: options.busy,
            enabled: options.enabled,
            alwaysOpen: true, // 插件调用的 quick pick 不自动关闭，和 vscode 交互保持一致
        });
        const value = await (0, ide_core_common_1.hookCancellationToken)(token, quickPickPromise);
        if ((0, ide_core_common_1.isUndefined)(value)) {
            return;
        }
        return Array.isArray(value) ? value.map((index) => items[index]) : items[value];
    }
    $onItemSelected(handle) {
        if (this._onDidSelectItem) {
            this._onDidSelectItem(handle);
        }
    }
    async showWorkspaceFolderPick(options, token = ide_core_common_1.CancellationToken.None) {
        const workspaceFolders = await this.workspace.resolveWorkspaceFolder();
        if (!workspaceFolders) {
            return undefined;
        }
        const session = ++this.currentQuick;
        const pickItems = workspaceFolders.map((folder) => {
            const quickPickItem = {
                label: folder.name,
                value: folder.index, // handle
            };
            return quickPickItem;
        });
        const quickPickPromise = this.proxy.$showQuickPick(session, pickItems, options && {
            placeholder: options.placeHolder,
            ignoreFocusOut: options.ignoreFocusOut,
        });
        const value = await (0, ide_core_common_1.hookCancellationToken)(token, quickPickPromise);
        return workspaceFolders.find((folder) => folder.index === value);
    }
    hideQuickPick() {
        this.proxy.$hideQuickPick();
    }
    createQuickPick() {
        const session = ++this.currentQuick;
        const newQuickPick = new ExtQuickPick(session, this.proxy, this);
        this.createdQuicks.set(session, newQuickPick);
        return newQuickPick;
    }
    createInputBox() {
        const session = ++this.currentQuick;
        const newInputBox = new ExtInputBox(session, this.proxy, this, () => {
            this.createdInputBoxes.delete(session);
        });
        this.createdInputBoxes.set(session, newInputBox);
        return newInputBox;
    }
    $onDidChangeValue(sessionId, value) {
        const session = this.createdQuicks.get(sessionId);
        if (session) {
            session._fireDidChangeValue(value);
        }
    }
    $onCreatedInputBoxDidChangeValue(sessionId, value) {
        const session = this.createdInputBoxes.get(sessionId);
        if (session) {
            session._fireDidChangeValue(value);
        }
    }
    $onCreatedInputBoxDidAccept(sessionId) {
        const session = this.createdInputBoxes.get(sessionId);
        if (session) {
            session._fireDidAccept();
        }
    }
    $onCreatedInputBoxDidHide(sessionId) {
        const session = this.createdInputBoxes.get(sessionId);
        if (session) {
            session._fireDidHide();
        }
    }
    $onCreatedInputBoxDidTriggerButton(sessionId, btnHandler) {
        const session = this.createdInputBoxes.get(sessionId);
        if (session) {
            session._fireDidTriggerButton(btnHandler);
        }
    }
    $onDidTriggerButton(btnHandler) {
        var _a;
        return (_a = this.createdQuicks.get(this.currentQuick)) === null || _a === void 0 ? void 0 : _a.attachBtn(btnHandler);
    }
    $onDidTriggerItemButton(itemHandler, btnHandler) {
        var _a;
        return (_a = this.createdQuicks.get(this.currentQuick)) === null || _a === void 0 ? void 0 : _a.attachItemBtn(itemHandler, btnHandler);
    }
    showInputBox(options = {}, token = ide_core_common_1.CancellationToken.None) {
        // 校验函数需要运行在扩展进程中
        this.validateInputHandler = options && options.validateInput;
        this.hideInputBox();
        const promise = this.proxy.$showQuickInput(options, typeof this.validateInputHandler === 'function');
        return (0, ide_core_common_1.hookCancellationToken)(token, promise);
    }
    $validateInput(input) {
        if (this.validateInputHandler) {
            return this.validateInputHandler(input);
        }
        return undefined;
    }
    hideInputBox() {
        this.proxy.$hideQuickInput();
    }
}
exports.ExtHostQuickOpen = ExtHostQuickOpen;
class ExtQuickPick extends BaseQuickInput {
    constructor(quickPickIndex, proxy, quickOpen) {
        super(quickPickIndex, proxy);
        this.proxy = proxy;
        this.quickOpen = quickOpen;
        this.type = 'quickPick';
        this.value = '';
        this._buttons = [];
        this._items = [];
        this._handlesToItems = new Map();
        this._itemsToHandles = new Map();
        this._activeItems = [];
        this._placeholder = '';
        this.didShow = false;
        this.quickPickIndex = quickPickIndex;
        this.disposableCollection = new ide_core_common_1.DisposableCollection();
        this.disposableCollection.push((this._onDidHideEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidAcceptEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidChangeActiveEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidChangeSelectionEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidChangeValueEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidTriggerButtonEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidTriggerItemButtonEmitter = new ide_core_common_1.Emitter()));
    }
    get items() {
        return this._items;
    }
    set items(activeItems) {
        this._items = activeItems;
        this._handlesToItems.clear();
        this._itemsToHandles.clear();
        this._items.forEach((item, i) => {
            this._handlesToItems.set(i, item);
            this._itemsToHandles.set(item, i);
        });
        // 说明是先 show，再设置 item
        if (this.didShow) {
            this.show();
        }
    }
    get activeItems() {
        return this._activeItems;
    }
    set activeItems(activeItems) {
        this._activeItems = activeItems;
    }
    get onDidAccept() {
        return this._onDidAcceptEmitter.event;
    }
    get placeholder() {
        return this._placeholder;
    }
    set placeholder(placeholder) {
        this._placeholder = placeholder;
    }
    get onDidChangeActive() {
        return this._onDidChangeActiveEmitter.event;
    }
    get onDidChangeSelection() {
        return this._onDidChangeSelectionEmitter.event;
    }
    get onDidChangeValue() {
        return this._onDidChangeValueEmitter.event;
    }
    get buttons() {
        return this._buttons;
    }
    set buttons(buttons) {
        this._buttons = buttons;
    }
    get onDidTriggerButton() {
        return this._onDidTriggerButtonEmitter.event;
    }
    get onDidTriggerItemButton() {
        return this._onDidTriggerItemButtonEmitter.event;
    }
    _fireDidChangeValue(value) {
        this.value = value;
        this._onDidChangeValueEmitter.fire(value);
    }
    get onDidHide() {
        return this._onDidHideEmitter.event;
    }
    dispose() {
        this.disposableCollection.dispose();
        this.proxy.$hideQuickPick();
    }
    attachBtn(btnHandler) {
        const btn = this.buttons[btnHandler];
        return this._onDidTriggerButtonEmitter.fire(btn);
    }
    attachItemBtn(itemhandler, btnHandler) {
        const item = this._handlesToItems.get(itemhandler);
        if (!item || !item.buttons || !item.buttons.length) {
            return;
        }
        const button = item.buttons[btnHandler];
        if (button) {
            return this._onDidTriggerItemButtonEmitter.fire({
                button,
                item,
            });
        }
    }
    hide() {
        this.quickOpen.hideQuickPick();
    }
    show() {
        this.didShow = true;
        const hide = () => {
            this._onDidHideEmitter.fire(undefined);
        };
        const selectItem = (item) => {
            const selectedItems = Array.isArray(item) ? item : [item];
            this.selectedItems = this.activeItems = selectedItems;
            this._onDidChangeSelectionEmitter.fire(selectedItems);
            this._onDidAcceptEmitter.fire(undefined);
        };
        this.quickOpen
            .showQuickPick(this.items.map((item) => item), {
            canPickMany: this.canSelectMany,
            title: this.title,
            step: this.step,
            totalSteps: this.totalSteps,
            buttons: this.buttons,
            placeHolder: this.placeholder,
            ignoreFocusOut: this.ignoreFocusOut,
            _sessionId: this.quickPickIndex,
            keepScrollPosition: this.keepScrollPosition,
            value: this.value,
            busy: this.busy,
            enabled: this.enabled,
        })
            .then((item) => {
            if (!(0, ide_core_common_1.isUndefined)(item)) {
                selectItem(item);
            }
            hide();
        });
    }
}
class ExtQuickInput extends BaseQuickInput {
    constructor(_id, proxy, quickOpen, onDispose) {
        super(_id, proxy);
        this._id = _id;
        this.proxy = proxy;
        this.quickOpen = quickOpen;
        this._buttons = [];
        this._step = 0;
        this._title = '';
        this._totalSteps = 0;
        this._value = '';
        this._prompt = '';
        this._placeholder = '';
        this._password = false;
        this._hideOnDidAccept = true;
        this.disposableCollection = new ide_core_common_1.DisposableCollection();
        this.disposableCollection.push((this._onDidAcceptEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidChangeValueEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidTriggerButtonEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push((this._onDidHideEmitter = new ide_core_common_1.Emitter()));
        this.disposableCollection.push(ide_core_common_1.Disposable.create(onDispose));
    }
    get buttons() {
        return this._buttons;
    }
    set buttons(buttons) {
        // TODO: 可能是有问题的，但 MainThread 里可能是能 work 的。
        // 具体也不太好解决，涉及到：
        // - Uri 和 URI 类型不兼容
        // - iconPath, iconClass 要在这一层就拿到
        this._buttons = buttons;
        this.update({ buttons: buttons });
    }
    get title() {
        return this._title;
    }
    set title(title) {
        this._title = title;
        this.update({ title });
    }
    get password() {
        return this._password;
    }
    set password(password) {
        this._password = password;
        this.update({ password });
    }
    get value() {
        return this._value;
    }
    // 当前设计下，输入框还不能响应插件设置的 value 值，不影响一般使用。
    set value(value) {
        this._value = value;
        this.update({ value });
    }
    get valueSelection() {
        return this._valueSelection;
    }
    set valueSelection(valueSelection) {
        this._valueSelection = valueSelection;
        this.update({ valueSelection });
    }
    get totalSteps() {
        return this._totalSteps;
    }
    set totalSteps(totalSteps) {
        this._totalSteps = totalSteps;
        this.update({ totalSteps });
    }
    get step() {
        return this._step;
    }
    set step(step) {
        this._step = step;
        this.update({ step });
    }
    get prompt() {
        return this._prompt;
    }
    set prompt(prompt) {
        this._prompt = prompt;
        this.update({ prompt });
    }
    get placeholder() {
        return this._placeholder;
    }
    set placeholder(placeHolder) {
        this._placeholder = placeHolder;
        this.update({ placeHolder });
    }
    get validationMessage() {
        return this._validationMessage;
    }
    set validationMessage(validationMessage) {
        var _a;
        this._validationMessage = validationMessage;
        if (!validationMessage) {
            this.update({ validationMessage: undefined, severity: vscode_1.Severity.Ignore });
        }
        else if (typeof validationMessage === 'string') {
            this.update({ validationMessage, severity: vscode_1.Severity.Error });
        }
        else {
            this.update({
                validationMessage: validationMessage.message,
                severity: (_a = validationMessage.severity) !== null && _a !== void 0 ? _a : vscode_1.Severity.Error,
            });
        }
    }
    get hideOnDidAccept() {
        return this._hideOnDidAccept;
    }
    set hideOnDidAccept(hideOnDidAccept) {
        this._hideOnDidAccept = hideOnDidAccept;
        this.update({ hideOnDidAccept });
    }
    getOptions() {
        var _a;
        return {
            value: this.value,
            prompt: this.prompt,
            placeHolder: this.placeholder,
            password: this.password,
            ignoreFocusOut: this.ignoreFocusOut,
            title: this._title,
            totalSteps: this.totalSteps,
            step: this.step,
            validationMessage: typeof this.validationMessage === 'string' ? this.validationMessage : (_a = this.validationMessage) === null || _a === void 0 ? void 0 : _a.message,
            buttons: this.buttons,
            busy: this.busy,
            enabled: this.enabled,
            hideOnDidAccept: this.hideOnDidAccept,
        };
    }
    _fireDidChangeValue(value) {
        this.value = value;
        this._onDidChangeValueEmitter.fire(value);
    }
    _fireDidAccept() {
        this._onDidAcceptEmitter.fire();
    }
    _fireDidTriggerButton(btnHandler) {
        this._onDidTriggerButtonEmitter.fire(this.buttons[btnHandler]);
    }
    _fireDidHide() {
        this._onDidHideEmitter.fire();
    }
    get onDidChangeValue() {
        return this._onDidChangeValueEmitter.event;
    }
    get onDidAccept() {
        return this._onDidAcceptEmitter.event;
    }
    get onDidTriggerButton() {
        return this._onDidTriggerButtonEmitter.event;
    }
    get onDidHide() {
        return this._onDidHideEmitter.event;
    }
    show() {
        this.update(this.getOptions());
    }
    hide() {
        if (this.type === 'inputBox') {
            this.proxy.$hideInputBox(this._id);
        }
    }
    dispose() {
        if (this._disposed) {
            return;
        }
        this.disposableCollection.dispose();
        if (this._updateTimeout) {
            clearTimeout(this._updateTimeout);
            this._updateTimeout = undefined;
        }
        this.proxy.$disposeInputBox(this._id);
        this._disposed = true;
    }
}
class ExtInputBox extends ExtQuickInput {
    constructor() {
        super(...arguments);
        this.type = 'inputBox';
    }
}
//# sourceMappingURL=ext.host.quickopen.js.map