"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MainThreadSCM = void 0;
const tslib_1 = require("tslib");
const di_1 = require("@opensumi/di");
const ide_connection_1 = require("@opensumi/ide-connection");
const ide_core_browser_1 = require("@opensumi/ide-core-browser");
const ide_core_common_1 = require("@opensumi/ide-core-common");
const common_1 = require("@opensumi/ide-scm/lib/common");
const vscode_1 = require("../../../common/vscode");
class MainThreadSCMResourceGroup {
    get hideWhenEmpty() {
        return !!this.features.hideWhenEmpty;
    }
    constructor(sourceControlHandle, handle, provider, features, label, id) {
        this.sourceControlHandle = sourceControlHandle;
        this.handle = handle;
        this.provider = provider;
        this.features = features;
        this.label = label;
        this.id = id;
        this.elements = [];
        this._onDidSplice = new ide_core_common_1.Emitter();
        this.onDidSplice = this._onDidSplice.event;
        this._onDidChange = new ide_core_common_1.Emitter();
        this.onDidChange = this._onDidChange.event;
    }
    toJSON() {
        return {
            $mid: 4,
            sourceControlHandle: this.sourceControlHandle,
            groupHandle: this.handle,
        };
    }
    splice(start, deleteCount, toInsert) {
        if (deleteCount === 0) {
            // 部分情况下 SCM Provider 会重复调用该方法，导致 elements 被重复添加，导致重复渲染
            // 所以这里需要先判断 toInsert 是否已经在 elements 中，如果不在，则添加，否则不添加
            const uniqueResourcesToInsert = [];
            for (const resource of toInsert) {
                const hasInserted = this.elements.some((r) => r.sourceUri.toString() === resource.sourceUri.toString() &&
                    r.resourceGroup.id === resource.resourceGroup.id);
                if (!hasInserted) {
                    uniqueResourcesToInsert.push(resource);
                }
            }
            if (uniqueResourcesToInsert.length > 0) {
                this.elements.splice(start, deleteCount, ...uniqueResourcesToInsert);
                this._onDidSplice.fire({ start, deleteCount, toInsert: uniqueResourcesToInsert });
            }
        }
        else {
            this.elements.splice(start, deleteCount, ...toInsert);
            this._onDidSplice.fire({ start, deleteCount, toInsert });
        }
    }
    $updateGroup(features) {
        this.features = Object.assign(this.features, features);
        this._onDidChange.fire();
    }
    $updateGroupLabel(label) {
        this.label = label;
        this._onDidChange.fire();
    }
}
class MainThreadSCMResource {
    constructor(proxy, sourceControlHandle, groupHandle, handle, sourceUri, resourceGroup, decorations, contextValue, command) {
        this.proxy = proxy;
        this.sourceControlHandle = sourceControlHandle;
        this.groupHandle = groupHandle;
        this.handle = handle;
        this.sourceUri = sourceUri;
        this.resourceGroup = resourceGroup;
        this.decorations = decorations;
        this.contextValue = contextValue;
        this.command = command;
    }
    open(preserveFocus) {
        return this.proxy.$executeResourceCommand(this.sourceControlHandle, this.groupHandle, this.handle, preserveFocus);
    }
    toJSON() {
        return {
            $mid: 3,
            sourceControlHandle: this.sourceControlHandle,
            groupHandle: this.groupHandle,
            handle: this.handle,
        };
    }
}
function getSCMHistoryItemIcon(historyItem) {
    if (!historyItem.icon) {
        return undefined;
    }
    else if (ide_core_common_1.Uri.isUri(historyItem.icon)) {
        return ide_core_common_1.Uri.revive(historyItem.icon);
    }
    else {
        const icon = historyItem.icon;
        return { light: ide_core_common_1.Uri.revive(icon.light), dark: ide_core_common_1.Uri.revive(icon.dark) };
    }
}
class MainThreadSCMHistoryProvider {
    get actionButton() {
        return this._actionButton;
    }
    set actionButton(actionButton) {
        this._actionButton = actionButton;
        this._onDidChangeActionButton.fire();
    }
    get currentHistoryItemGroup() {
        return this._currentHistoryItemGroup;
    }
    set currentHistoryItemGroup(historyItemGroup) {
        this._currentHistoryItemGroup = historyItemGroup;
        this._onDidChangeCurrentHistoryItemGroup.fire();
    }
    constructor(proxy, handle) {
        this.proxy = proxy;
        this.handle = handle;
        this._onDidChangeActionButton = new ide_core_common_1.Emitter();
        this.onDidChangeActionButton = this._onDidChangeActionButton.event;
        this._onDidChangeCurrentHistoryItemGroup = new ide_core_common_1.Emitter();
        this.onDidChangeCurrentHistoryItemGroup = this._onDidChangeCurrentHistoryItemGroup.event;
    }
    async resolveHistoryItemGroupBase(historyItemGroupId) {
        return this.proxy.$resolveHistoryItemGroupBase(this.handle, historyItemGroupId, ide_core_common_1.CancellationToken.None);
    }
    async resolveHistoryItemGroupCommonAncestor(historyItemGroupId1, historyItemGroupId2) {
        return this.proxy.$resolveHistoryItemGroupCommonAncestor(this.handle, historyItemGroupId1, historyItemGroupId2, ide_core_common_1.CancellationToken.None);
    }
    async provideHistoryItems(historyItemGroupId, options) {
        const historyItems = await this.proxy.$provideHistoryItems(this.handle, historyItemGroupId, options, ide_core_common_1.CancellationToken.None);
        return historyItems === null || historyItems === void 0 ? void 0 : historyItems.map((historyItem) => ({ ...historyItem, icon: getSCMHistoryItemIcon(historyItem) }));
    }
    async provideHistoryItemChanges(historyItemId) {
        const changes = await this.proxy.$provideHistoryItemChanges(this.handle, historyItemId, ide_core_common_1.CancellationToken.None);
        return changes === null || changes === void 0 ? void 0 : changes.map((change) => ({
            uri: ide_core_common_1.Uri.revive(change.uri),
            originalUri: change.originalUri && ide_core_common_1.Uri.revive(change.originalUri),
            modifiedUri: change.modifiedUri && ide_core_common_1.Uri.revive(change.modifiedUri),
            renameUri: change.renameUri && ide_core_common_1.Uri.revive(change.renameUri),
        }));
    }
}
class MainThreadSCMProvider {
    get id() {
        return this._id;
    }
    get handle() {
        return this._handle;
    }
    get label() {
        return this._label;
    }
    get rootUri() {
        return this._rootUri;
    }
    get contextValue() {
        return this._contextValue;
    }
    get commitTemplate() {
        return this.features.commitTemplate;
    }
    get acceptInputCommand() {
        return this.features.acceptInputCommand;
    }
    get statusBarCommands() {
        return this.features.statusBarCommands;
    }
    get count() {
        return this.features.count;
    }
    get actionButton() {
        return this.features.actionButton;
    }
    get historyProvider() {
        return this._historyProvider;
    }
    get onDidChangeStatusBarCommands() {
        return this._onDidChangeStatusBarCommands.event;
    }
    constructor(proxy, _handle, _contextValue, _label, _rootUri) {
        this.proxy = proxy;
        this._handle = _handle;
        this._contextValue = _contextValue;
        this._label = _label;
        this._rootUri = _rootUri;
        this._id = `scm${MainThreadSCMProvider.ID_HANDLE++}`;
        this.groups = new ide_core_common_1.Sequence();
        this._groupsByHandle = Object.create(null);
        this._onDidChangeResources = new ide_core_common_1.Emitter();
        this.onDidChangeResources = this._onDidChangeResources.event;
        this.features = {};
        this._onDidChangeCommitTemplate = new ide_core_common_1.Emitter();
        this.onDidChangeCommitTemplate = this._onDidChangeCommitTemplate.event;
        this._onDidChangeStatusBarCommands = new ide_core_common_1.Emitter();
        this._onDidChangeHistoryProvider = new ide_core_common_1.Emitter();
        this.onDidChangeHistoryProvider = this._onDidChangeHistoryProvider.event;
        this._onDidChange = new ide_core_common_1.Emitter();
        this.onDidChange = this._onDidChange.event;
    }
    $updateSourceControl(features) {
        this.features = Object.assign(this.features, features);
        this._onDidChange.fire();
        if (typeof features.commitTemplate !== 'undefined') {
            this._onDidChangeCommitTemplate.fire(this.commitTemplate);
        }
        if (typeof features.statusBarCommands !== 'undefined') {
            this._onDidChangeStatusBarCommands.fire(this.statusBarCommands);
        }
        if (features.hasHistoryProvider && !this._historyProvider) {
            this._historyProvider = new MainThreadSCMHistoryProvider(this.proxy, this.handle);
            this._onDidChangeHistoryProvider.fire();
        }
        else if (features.hasHistoryProvider === false && this._historyProvider) {
            this._historyProvider = undefined;
            this._onDidChangeHistoryProvider.fire();
        }
    }
    $registerGroup(handle, id, label) {
        const group = new MainThreadSCMResourceGroup(this.handle, handle, this, {}, label, id);
        this._groupsByHandle[handle] = group;
        this.groups.splice(this.groups.elements.length, 0, [group]);
    }
    $updateGroup(handle, features) {
        const group = this._groupsByHandle[handle];
        if (!group) {
            return;
        }
        group.$updateGroup(features);
    }
    $updateGroupLabel(handle, label) {
        const group = this._groupsByHandle[handle];
        if (!group) {
            return;
        }
        group.$updateGroupLabel(label);
    }
    $spliceGroupResourceStates(splices) {
        for (const [groupHandle, groupSlices] of splices) {
            const group = this._groupsByHandle[groupHandle];
            if (!group) {
                this.logger.warn(`SCM group ${groupHandle} not found in provider ${this.label}`);
                continue;
            }
            // reverse the splices sequence in order to apply them correctly
            groupSlices.reverse();
            for (const [start, deleteCount, rawResources] of groupSlices) {
                const resources = rawResources.map((rawResource) => {
                    const [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue, command] = rawResource;
                    const icon = icons[0];
                    const iconDark = icons[1] || icon;
                    const decorations = {
                        icon: icon ? ide_core_common_1.Uri.parse(icon) : undefined,
                        iconDark: iconDark ? ide_core_common_1.Uri.parse(iconDark) : undefined,
                        tooltip,
                        strikeThrough,
                        faded,
                    };
                    return new MainThreadSCMResource(this.proxy, this.handle, groupHandle, handle, ide_core_common_1.Uri.revive(sourceUri), group, decorations, contextValue || undefined, command);
                });
                group.splice(start, deleteCount, resources);
            }
        }
        this._onDidChangeResources.fire();
    }
    $unregisterGroup(handle) {
        const group = this._groupsByHandle[handle];
        if (!group) {
            return;
        }
        delete this._groupsByHandle[handle];
        this.groups.splice(this.groups.elements.indexOf(group), 1);
        this._onDidChangeResources.fire();
    }
    $onDidChangeHistoryProviderActionButton(actionButton) {
        if (!this._historyProvider) {
            return;
        }
        this._historyProvider.actionButton = actionButton !== null && actionButton !== void 0 ? actionButton : undefined;
    }
    $onDidChangeHistoryProviderCurrentHistoryItemGroup(currentHistoryItemGroup) {
        if (!this._historyProvider) {
            return;
        }
        this._historyProvider.currentHistoryItemGroup = currentHistoryItemGroup !== null && currentHistoryItemGroup !== void 0 ? currentHistoryItemGroup : undefined;
    }
    async getOriginalResource(uri) {
        if (!this.features.hasQuickDiffProvider) {
            return null;
        }
        const result = await this.proxy.$provideOriginalResource(this.handle, uri, ide_core_common_1.CancellationToken.None);
        return result && ide_core_common_1.Uri.revive(result);
    }
    toJSON() {
        return {
            $mid: 5,
            handle: this.handle,
        };
    }
    dispose() { }
}
MainThreadSCMProvider.ID_HANDLE = 0;
tslib_1.__decorate([
    (0, di_1.Autowired)(ide_core_browser_1.ILogger),
    tslib_1.__metadata("design:type", Object)
], MainThreadSCMProvider.prototype, "logger", void 0);
let MainThreadSCM = class MainThreadSCM extends ide_core_common_1.Disposable {
    constructor(rpcProtocol) {
        super();
        this.rpcProtocol = rpcProtocol;
        this._repositories = new Map();
        this._inputDisposables = new Map();
        this._proxy = this.rpcProtocol.getProxy(vscode_1.ExtHostAPIIdentifier.ExtHostSCM);
        ide_core_common_1.Event.debounce(this.scmService.onDidChangeSelectedRepositories, (_, e) => e, 100)(this.onDidChangeSelectedRepositories, this, this.disposables);
    }
    dispose() {
        this._repositories.forEach((r) => r.dispose());
        this._repositories.clear();
        this._inputDisposables.forEach((d) => d.dispose());
        this._inputDisposables.clear();
        super.dispose();
    }
    $registerSourceControl(handle, id, label, rootUri) {
        const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri && ide_core_common_1.Uri.revive(rootUri));
        const repository = this.scmService.registerSCMProvider(provider);
        this._repositories.set(handle, repository);
        const inputDisposable = repository.input.onDidChange((value) => this._proxy.$onInputBoxValueChange(handle, value));
        this._inputDisposables.set(handle, inputDisposable);
        this.addDispose(ide_core_common_1.Disposable.create(() => {
            this.$unregisterSourceControl(handle);
        }));
    }
    $updateSourceControl(handle, features) {
        const repository = this._repositories.get(handle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$updateSourceControl(features);
    }
    $unregisterSourceControl(handle) {
        const repository = this._repositories.get(handle);
        if (!repository) {
            return;
        }
        this._inputDisposables.get(handle).dispose();
        this._inputDisposables.delete(handle);
        repository.dispose();
        this._repositories.delete(handle);
    }
    $registerGroup(sourceControlHandle, groupHandle, id, label) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$registerGroup(groupHandle, id, label);
        this.addDispose(ide_core_common_1.Disposable.create(() => {
            provider.$unregisterGroup(groupHandle);
        }));
    }
    $updateGroup(sourceControlHandle, groupHandle, features) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$updateGroup(groupHandle, features);
    }
    $updateGroupLabel(sourceControlHandle, groupHandle, label) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$updateGroupLabel(groupHandle, label);
    }
    $spliceResourceStates(sourceControlHandle, splices) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$spliceGroupResourceStates(splices);
    }
    $unregisterGroup(sourceControlHandle, handle) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$unregisterGroup(handle);
    }
    $setInputBoxValue(sourceControlHandle, value) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        repository.input.value = value;
    }
    $setInputBoxPlaceholder(sourceControlHandle, placeholder) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        repository.input.placeholder = placeholder;
    }
    $setInputBoxEnablement(sourceControlHandle, enabled) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        repository.input.enabled = enabled;
    }
    $setInputBoxVisibility(sourceControlHandle, visible) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        repository.input.visible = visible;
    }
    $setValidationProviderIsEnabled(sourceControlHandle, enabled) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        if (enabled) {
            repository.input.validateInput = async (value, pos) => {
                const result = await this._proxy.$validateInput(sourceControlHandle, value, pos);
                return result && { message: result[0], type: result[1] };
            };
        }
        else {
            repository.input.validateInput = async () => undefined;
        }
    }
    $onDidChangeHistoryProviderActionButton(sourceControlHandle, actionButton) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$onDidChangeHistoryProviderActionButton(actionButton);
    }
    $onDidChangeHistoryProviderCurrentHistoryItemGroup(sourceControlHandle, historyItemGroup) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        const provider = repository.provider;
        provider.$onDidChangeHistoryProviderCurrentHistoryItemGroup(historyItemGroup);
    }
    $setInputBoxActionButton(sourceControlHandle, actionButton) {
        const repository = this._repositories.get(sourceControlHandle);
        if (!repository) {
            return;
        }
        repository.input.actionButton = actionButton
            ? { ...actionButton, icon: getSCMInputBoxActionButtonIcon(actionButton) }
            : undefined;
    }
    onDidChangeSelectedRepositories(repositories) {
        const handles = repositories
            .filter((r) => r.provider instanceof MainThreadSCMProvider)
            .map((r) => r.provider.handle);
        // 跟 SCM 插件进程通信
        this._proxy.$setSelectedSourceControls(handles);
    }
};
exports.MainThreadSCM = MainThreadSCM;
tslib_1.__decorate([
    (0, di_1.Autowired)(common_1.SCMService),
    tslib_1.__metadata("design:type", common_1.SCMService)
], MainThreadSCM.prototype, "scmService", void 0);
exports.MainThreadSCM = MainThreadSCM = tslib_1.__decorate([
    (0, di_1.Injectable)({ multiple: true }),
    tslib_1.__param(0, (0, di_1.Optional)(ide_connection_1.IRPCProtocol)),
    tslib_1.__metadata("design:paramtypes", [Object])
], MainThreadSCM);
function getSCMInputBoxActionButtonIcon(actionButton) {
    if (!actionButton.icon) {
        return undefined;
    }
    else if (ide_core_common_1.Uri.isUri(actionButton.icon)) {
        return ide_core_common_1.Uri.revive(actionButton.icon);
    }
    else {
        const icon = actionButton.icon;
        return { light: ide_core_common_1.Uri.revive(icon.light), dark: ide_core_common_1.Uri.revive(icon.dark) };
    }
}
//# sourceMappingURL=main.thread.scm.js.map