import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { localizeWithPath } from '../../../../nls.js';
import '../../../services/editor/common/editorGroupsService.js';
import { Emitter } from '../../../../base/common/event.js';
import { DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
import { MainEditorPart } from './editorPart.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { distinct, firstOrDefault } from '../../../../base/common/arrays.js';
import { AuxiliaryEditorPart } from './auxiliaryEditorPart.js';
import { MultiWindowParts } from '../../part.js';
import { DeferredPromise } from '../../../../base/common/async.js';
import { IStorageService } from '../../../../platform/storage/common/storage.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
import { getWindow } from '../../../../base/browser/dom.js';
import { getZoomLevel } from '../../../../base/browser/browser.js';
var EditorParts_1;
let EditorParts = class EditorParts extends MultiWindowParts {
    static { EditorParts_1 = this; }
    constructor(instantiationService, storageService, themeService) {
        super('workbench.editorParts', themeService, storageService);
        this.instantiationService = instantiationService;
        this.mainPart = this._register(this.createMainEditorPart());
        this.mostRecentActiveParts = [this.mainPart];
        this._onDidCreateAuxiliaryEditorPart = this._register(( new Emitter()));
        this.onDidCreateAuxiliaryEditorPart = this._onDidCreateAuxiliaryEditorPart.event;
        this.workspaceMemento = this.getMemento(1 , 0 );
        this._isReady = false;
        this.whenReadyPromise = ( new DeferredPromise());
        this.whenReady = this.whenReadyPromise.p;
        this.whenRestoredPromise = ( new DeferredPromise());
        this.whenRestored = this.whenRestoredPromise.p;
        this._onDidActiveGroupChange = this._register(( new Emitter()));
        this.onDidChangeActiveGroup = this._onDidActiveGroupChange.event;
        this._onDidAddGroup = this._register(( new Emitter()));
        this.onDidAddGroup = this._onDidAddGroup.event;
        this._onDidRemoveGroup = this._register(( new Emitter()));
        this.onDidRemoveGroup = this._onDidRemoveGroup.event;
        this._onDidMoveGroup = this._register(( new Emitter()));
        this.onDidMoveGroup = this._onDidMoveGroup.event;
        this._onDidActivateGroup = this._register(( new Emitter()));
        this.onDidActivateGroup = this._onDidActivateGroup.event;
        this._onDidChangeGroupIndex = this._register(( new Emitter()));
        this.onDidChangeGroupIndex = this._onDidChangeGroupIndex.event;
        this._onDidChangeGroupLocked = this._register(( new Emitter()));
        this.onDidChangeGroupLocked = this._onDidChangeGroupLocked.event;
        this._onDidChangeGroupMaximized = this._register(( new Emitter()));
        this.onDidChangeGroupMaximized = this._onDidChangeGroupMaximized.event;
        this._register(this.registerPart(this.mainPart));
        this.restoreParts();
        this.registerListeners();
    }
    registerListeners() {
        this._register(this.onDidChangeMementoValue(1 , this._store)(e => this.onDidChangeMementoState(e)));
    }
    createMainEditorPart() {
        return this.instantiationService.createInstance(MainEditorPart, this);
    }
    async createAuxiliaryEditorPart(options) {
        const { part, instantiationService, disposables } = await this.instantiationService.createInstance(AuxiliaryEditorPart, this).create(this.getGroupsLabel(this._parts.size), options);
        this._onDidAddGroup.fire(part.activeGroup);
        const eventDisposables = disposables.add(( new DisposableStore()));
        this._onDidCreateAuxiliaryEditorPart.fire({ part, instantiationService, disposables: eventDisposables });
        return part;
    }
    registerPart(part) {
        const disposables = this._register(( new DisposableStore()));
        disposables.add(super.registerPart(part));
        this.registerEditorPartListeners(part, disposables);
        return disposables;
    }
    unregisterPart(part) {
        super.unregisterPart(part);
        this.parts.forEach((part, index) => {
            if (part === this.mainPart) {
                return;
            }
            part.notifyGroupsLabelChange(this.getGroupsLabel(index));
        });
    }
    registerEditorPartListeners(part, disposables) {
        disposables.add(part.onDidFocus(() => {
            this.doUpdateMostRecentActive(part, true);
            if (this._parts.size > 1) {
                this._onDidActiveGroupChange.fire(this.activeGroup);
            }
        }));
        disposables.add(toDisposable(() => this.doUpdateMostRecentActive(part)));
        disposables.add(part.onDidChangeActiveGroup(group => this._onDidActiveGroupChange.fire(group)));
        disposables.add(part.onDidAddGroup(group => this._onDidAddGroup.fire(group)));
        disposables.add(part.onDidRemoveGroup(group => this._onDidRemoveGroup.fire(group)));
        disposables.add(part.onDidMoveGroup(group => this._onDidMoveGroup.fire(group)));
        disposables.add(part.onDidActivateGroup(group => this._onDidActivateGroup.fire(group)));
        disposables.add(part.onDidChangeGroupMaximized(maximized => this._onDidChangeGroupMaximized.fire(maximized)));
        disposables.add(part.onDidChangeGroupIndex(group => this._onDidChangeGroupIndex.fire(group)));
        disposables.add(part.onDidChangeGroupLocked(group => this._onDidChangeGroupLocked.fire(group)));
    }
    doUpdateMostRecentActive(part, makeMostRecentlyActive) {
        const index = this.mostRecentActiveParts.indexOf(part);
        if (index !== -1) {
            this.mostRecentActiveParts.splice(index, 1);
        }
        if (makeMostRecentlyActive) {
            this.mostRecentActiveParts.unshift(part);
        }
    }
    getGroupsLabel(index) {
        return ( localizeWithPath(
            'vs/workbench/browser/parts/editor/editorParts',
            'groupLabel',
            "Window {0}",
            index + 1
        ));
    }
    getPart(groupOrElement) {
        if (this._parts.size > 1) {
            if (groupOrElement instanceof HTMLElement) {
                const element = groupOrElement;
                return this.getPartByDocument(element.ownerDocument);
            }
            else {
                const group = groupOrElement;
                let id;
                if (typeof group === 'number') {
                    id = group;
                }
                else {
                    id = group.id;
                }
                for (const part of this._parts) {
                    if (part.hasGroup(id)) {
                        return part;
                    }
                }
            }
        }
        return this.mainPart;
    }
    static { this.EDITOR_PARTS_UI_STATE_STORAGE_KEY = 'editorparts.state'; }
    get isReady() { return this._isReady; }
    async restoreParts() {
        await this.mainPart.whenReady;
        if (this.mainPart.willRestoreState) {
            const state = this.loadState();
            if (state) {
                await this.restoreState(state);
            }
        }
        const mostRecentActivePart = firstOrDefault(this.mostRecentActiveParts);
        mostRecentActivePart?.activeGroup.focus();
        this._isReady = true;
        this.whenReadyPromise.complete();
        await Promise.allSettled(( this.parts.map(part => part.whenRestored)));
        this.whenRestoredPromise.complete();
    }
    loadState() {
        return this.workspaceMemento[EditorParts_1.EDITOR_PARTS_UI_STATE_STORAGE_KEY];
    }
    saveState() {
        const state = this.createState();
        if (state.auxiliary.length === 0) {
            delete this.workspaceMemento[EditorParts_1.EDITOR_PARTS_UI_STATE_STORAGE_KEY];
        }
        else {
            this.workspaceMemento[EditorParts_1.EDITOR_PARTS_UI_STATE_STORAGE_KEY] = state;
        }
    }
    createState() {
        return {
            auxiliary: ( this.parts.filter(part => part !== this.mainPart).map(part => {
                return {
                    state: part.createState(),
                    bounds: (() => {
                        const auxiliaryWindow = getWindow(part.getContainer());
                        if (auxiliaryWindow) {
                            return {
                                x: auxiliaryWindow.screenX,
                                y: auxiliaryWindow.screenY,
                                width: auxiliaryWindow.outerWidth,
                                height: auxiliaryWindow.outerHeight
                            };
                        }
                        return undefined;
                    })(),
                    zoomLevel: (() => {
                        const auxiliaryWindow = getWindow(part.getContainer());
                        if (auxiliaryWindow) {
                            return getZoomLevel(auxiliaryWindow);
                        }
                        return undefined;
                    })()
                };
            })),
            mru: ( this.mostRecentActiveParts.map(part => this.parts.indexOf(part)))
        };
    }
    async restoreState(state) {
        if (state.auxiliary.length) {
            const auxiliaryEditorPartPromises = [];
            for (const auxiliaryEditorPartState of state.auxiliary) {
                auxiliaryEditorPartPromises.push(this.createAuxiliaryEditorPart({
                    bounds: auxiliaryEditorPartState.bounds,
                    state: auxiliaryEditorPartState.state,
                    zoomLevel: auxiliaryEditorPartState.zoomLevel
                }));
            }
            await Promise.allSettled(auxiliaryEditorPartPromises);
            if (state.mru.length === this.parts.length) {
                this.mostRecentActiveParts = ( state.mru.map(index => this.parts[index]));
            }
            else {
                this.mostRecentActiveParts = [...this.parts];
            }
            await Promise.allSettled(( this.parts.map(part => part.whenReady)));
        }
    }
    get hasRestorableState() {
        return ( this.parts.some(part => part.hasRestorableState));
    }
    onDidChangeMementoState(e) {
        if (e.external && e.scope === 1 ) {
            this.reloadMemento(e.scope);
            const state = this.loadState();
            if (state) {
                this.applyState(state);
            }
        }
    }
    async applyState(state) {
        for (const part of this.parts) {
            if (part === this.mainPart) {
                continue;
            }
            for (const group of part.getGroups(1 )) {
                const closed = await group.closeAllEditors();
                if (!closed) {
                    return false;
                }
            }
            part.close();
        }
        await this.restoreState(state);
        return true;
    }
    get activeGroup() {
        return this.activePart.activeGroup;
    }
    get sideGroup() {
        return this.activePart.sideGroup;
    }
    get groups() {
        return this.getGroups();
    }
    get count() {
        return this.groups.length;
    }
    getGroups(order = 0 ) {
        if (this._parts.size > 1) {
            let parts;
            switch (order) {
                case 2 :
                case 0 :
                    parts = this.parts;
                    break;
                case 1 :
                    parts = distinct([...this.mostRecentActiveParts, ...this.parts]);
                    break;
            }
            return ( parts.map(part => part.getGroups(order))).flat();
        }
        return this.mainPart.getGroups(order);
    }
    getGroup(identifier) {
        if (this._parts.size > 1) {
            for (const part of this._parts) {
                const group = part.getGroup(identifier);
                if (group) {
                    return group;
                }
            }
        }
        return this.mainPart.getGroup(identifier);
    }
    assertGroupView(group) {
        let groupView;
        if (typeof group === 'number') {
            groupView = this.getGroup(group);
        }
        else {
            groupView = group;
        }
        if (!groupView) {
            throw new Error('Invalid editor group provided!');
        }
        return groupView;
    }
    activateGroup(group) {
        return this.getPart(group).activateGroup(group);
    }
    getSize(group) {
        return this.getPart(group).getSize(group);
    }
    setSize(group, size) {
        this.getPart(group).setSize(group, size);
    }
    arrangeGroups(arrangement, group) {
        (group !== undefined ? this.getPart(group) : this.activePart).arrangeGroups(arrangement, group);
    }
    toggleMaximizeGroup(group) {
        (group !== undefined ? this.getPart(group) : this.activePart).toggleMaximizeGroup(group);
    }
    toggleExpandGroup(group) {
        (group !== undefined ? this.getPart(group) : this.activePart).toggleExpandGroup(group);
    }
    restoreGroup(group) {
        return this.getPart(group).restoreGroup(group);
    }
    applyLayout(layout) {
        this.activePart.applyLayout(layout);
    }
    getLayout() {
        return this.activePart.getLayout();
    }
    get orientation() {
        return this.activePart.orientation;
    }
    setGroupOrientation(orientation) {
        this.activePart.setGroupOrientation(orientation);
    }
    findGroup(scope, source = this.activeGroup, wrap) {
        const sourcePart = this.getPart(source);
        if (this._parts.size > 1) {
            const groups = this.getGroups(2 );
            if (scope.location === 0  || scope.location === 1 ) {
                return scope.location === 0  ? groups[0] : groups[groups.length - 1];
            }
            const group = sourcePart.findGroup(scope, source, false);
            if (group) {
                return group;
            }
            if (scope.location === 2  || scope.location === 3 ) {
                const sourceGroup = this.assertGroupView(source);
                const index = groups.indexOf(sourceGroup);
                if (scope.location === 2 ) {
                    let nextGroup = groups[index + 1];
                    if (!nextGroup && wrap) {
                        nextGroup = groups[0];
                    }
                    return nextGroup;
                }
                else {
                    let previousGroup = groups[index - 1];
                    if (!previousGroup && wrap) {
                        previousGroup = groups[groups.length - 1];
                    }
                    return previousGroup;
                }
            }
        }
        return sourcePart.findGroup(scope, source, wrap);
    }
    addGroup(location, direction) {
        return this.getPart(location).addGroup(location, direction);
    }
    removeGroup(group) {
        this.getPart(group).removeGroup(group);
    }
    moveGroup(group, location, direction) {
        return this.getPart(group).moveGroup(group, location, direction);
    }
    mergeGroup(group, target, options) {
        return this.getPart(group).mergeGroup(group, target, options);
    }
    mergeAllGroups(target) {
        return this.activePart.mergeAllGroups(target);
    }
    copyGroup(group, location, direction) {
        return this.getPart(group).copyGroup(group, location, direction);
    }
    createEditorDropTarget(container, delegate) {
        return this.getPart(container).createEditorDropTarget(container, delegate);
    }
    get partOptions() { return this.mainPart.partOptions; }
    get onDidChangeEditorPartOptions() { return this.mainPart.onDidChangeEditorPartOptions; }
};
EditorParts = EditorParts_1 = ( __decorate([
    ( __param(0, IInstantiationService)),
    ( __param(1, IStorageService)),
    ( __param(2, IThemeService))
], EditorParts));
export { EditorParts };
