"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TreeStateManager = exports.Operation = void 0;
const ide_utils_1 = require("@opensumi/ide-utils");
const types_1 = require("../../../types");
const TreeNode_1 = require("../../TreeNode");
const { Path } = ide_utils_1.path;
var Operation;
(function (Operation) {
    Operation[Operation["SetExpanded"] = 1] = "SetExpanded";
    Operation[Operation["SetCollapsed"] = 2] = "SetCollapsed";
    Operation[Operation["SetActive"] = 3] = "SetActive";
})(Operation = exports.Operation || (exports.Operation = {}));
var StashKeyFrameFlag;
(function (StashKeyFrameFlag) {
    StashKeyFrameFlag[StashKeyFrameFlag["Expanded"] = 1] = "Expanded";
    StashKeyFrameFlag[StashKeyFrameFlag["Collapsed"] = 2] = "Collapsed";
    StashKeyFrameFlag[StashKeyFrameFlag["Disabled"] = 4] = "Disabled";
})(StashKeyFrameFlag || (StashKeyFrameFlag = {}));
class TreeStateManager {
    constructor(root) {
        this.expandedDirectories = new Map();
        this._scrollOffset = 0;
        this.stashing = false;
        this.stashLockingItems = new Set();
        this.onDidLoadStateEmitter = new ide_utils_1.Emitter();
        this.onChangeScrollOffsetEmitter = new ide_utils_1.Emitter();
        this.onDidChangeExpansionStateEmitter = new ide_utils_1.Emitter();
        this.onDidChangeRelativePathEmitter = new ide_utils_1.Emitter();
        /**
         * 处理展开状态的变更
         * @private
         * @memberof TreeStateManager
         */
        this.handleExpansionChange = (target, isExpanded, isVisibleAtSurface) => {
            var _a;
            if (this.stashing && this.stashKeyframes) {
                this.stashKeyframes.set(target.id, isExpanded ? StashKeyFrameFlag.Expanded : StashKeyFrameFlag.Collapsed);
            }
            if (this.stashKeyframes && !this.stashing) {
                // 如果用户通过交互手动修改了展开属性，则需要在记录结束后将其父节点从撤销队列中移除
                if (isExpanded) {
                    let p = target;
                    while (p) {
                        if (this.stashKeyframes.has(p.id)) {
                            let flags = this.stashKeyframes.get(p.id);
                            flags = flags | StashKeyFrameFlag.Disabled;
                            this.stashKeyframes.set(p.id, flags);
                        }
                        p = p.parent;
                    }
                    this.stashLockingItems.add(target);
                }
                if (this.stashLockingItems && this.stashLockingItems.has(target) && !isExpanded) {
                    let p = target;
                    while (p) {
                        if (this.stashKeyframes.has(p.id)) {
                            let flags = this.stashKeyframes.get(p.id);
                            flags &= ~StashKeyFrameFlag.Disabled;
                            this.stashKeyframes.set(p.id, flags);
                        }
                        p = p.parent;
                    }
                    this.stashLockingItems.delete(target);
                }
            }
            let relativePath = this.expandedDirectories.get(target);
            if (isExpanded && !relativePath) {
                relativePath = (_a = new Path(this.root.path).relative(new Path(target.path))) === null || _a === void 0 ? void 0 : _a.toString();
                this.expandedDirectories.set(target, relativePath);
                this.onDidChangeExpansionStateEmitter.fire({ relativePath, isExpanded, isVisibleAtSurface });
            }
            else if (!isExpanded && relativePath) {
                this.expandedDirectories.delete(target);
                this.onDidChangeExpansionStateEmitter.fire({ relativePath, isExpanded, isVisibleAtSurface });
            }
        };
        this.handleDidChangePath = (target) => {
            var _a;
            if (this.expandedDirectories.has(target)) {
                const prevPath = this.expandedDirectories.get(target);
                const newPath = (_a = new Path(this.root.path).relative(new Path(target.path))) === null || _a === void 0 ? void 0 : _a.toString();
                this.expandedDirectories.set(target, newPath);
                this.onDidChangeRelativePathEmitter.fire({ prevPath, newPath });
            }
        };
        this.root = root;
        // 监听节点的折叠展开状态变化
        this.root.watcher.on(types_1.TreeNodeEvent.DidChangeExpansionState, this.handleExpansionChange);
        this.root.watcher.on(types_1.TreeNodeEvent.DidChangePath, this.handleDidChangePath);
    }
    get scrollOffset() {
        return this._scrollOffset;
    }
    saveScrollOffset(scrollOffset) {
        this._scrollOffset = scrollOffset;
        this.onChangeScrollOffsetEmitter.fire(scrollOffset);
    }
    get onDidLoadState() {
        return this.onDidLoadStateEmitter.event;
    }
    get onChangeScrollOffset() {
        return this.onChangeScrollOffsetEmitter.event;
    }
    get onDidChangeExpansionState() {
        return this.onDidChangeExpansionStateEmitter.event;
    }
    get onDidChangeRelativePath() {
        return this.onDidChangeRelativePathEmitter.event;
    }
    async loadTreeState(state) {
        if (state) {
            for (const relPath of state.expandedDirectories.buried) {
                try {
                    const node = await this.root.loadTreeNodeByPath(relPath);
                    if (!node) {
                        break;
                    }
                    if (node && TreeNode_1.CompositeTreeNode.is(node)) {
                        node.setCollapsed();
                    }
                }
                catch (error) { }
            }
            for (const relPath of state.expandedDirectories.atSurface) {
                try {
                    const node = await this.root.loadTreeNodeByPath(relPath, true);
                    if (!node) {
                        break;
                    }
                }
                catch (error) { }
            }
            this._scrollOffset =
                typeof state.scrollPosition === 'number' && state.scrollPosition > -1
                    ? state.scrollPosition
                    : this._scrollOffset;
            this.root.watcher.notifyDidUpdateBranch();
            this.onDidLoadStateEmitter.fire();
        }
    }
    /**
     * 确保在调用`reverseStash`时，目录扩展不会被更改，以免导致节点内文件被排除
     */
    excludeFromStash(file) {
        if (this.stashKeyframes && !this.stashing) {
            this.handleExpansionChange(!TreeNode_1.CompositeTreeNode.is(file) ? file.parent : file, true, this.root.isItemVisibleAtSurface(file));
        }
    }
    /**
     * 开始记录点
     */
    beginStashing() {
        this.stashing = true;
        this.stashKeyframes = new Map();
    }
    /**
     * 结束记录点
     */
    endStashing() {
        this.stashing = false;
        this.stashLockingItems.clear();
    }
    /**
     * 反转记录的所有折叠/展开状态
     * 用于实现一些临时的查看操作
     * 例如：
     * 调用beginStashing ==> 展开/折叠某个目录 ==> 调用endStashing ==> 处理完毕后调用reverseStash，回到原来的状态
     */
    async reverseStash() {
        if (!this.stashKeyframes) {
            return;
        }
        this.endStashing();
        const keyframes = Array.from(this.stashKeyframes);
        this.stashKeyframes = null;
        for (const [targetID, flags] of keyframes) {
            const frameDisabled = (flags & StashKeyFrameFlag.Disabled) === StashKeyFrameFlag.Disabled;
            const target = TreeNode_1.TreeNode.getTreeNodeById(targetID);
            // 判断当前操作对象是否有效，无效则做下一步操作
            if (!target || frameDisabled) {
                continue;
            }
            if ((flags & StashKeyFrameFlag.Expanded) === StashKeyFrameFlag.Expanded) {
                target.setCollapsed();
            }
            else if ((flags & StashKeyFrameFlag.Collapsed) === StashKeyFrameFlag.Collapsed) {
                await target.setExpanded();
            }
        }
    }
}
exports.TreeStateManager = TreeStateManager;
//# sourceMappingURL=TreeStateManager.js.map