"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DecorationsManager = void 0;
const ide_utils_1 = require("@opensumi/ide-utils");
const types_1 = require("../../types");
const TreeNode_1 = require("../TreeNode");
const CompositeDecoration_1 = require("./CompositeDecoration");
class DecorationsManager {
    constructor(root) {
        this.root = root;
        this.decorations = new Map();
        this.decorationsMeta = new WeakMap();
        this.disposables = new ide_utils_1.DisposableCollection();
        this.disposed = false;
        this.targetDecoration = (event) => {
            const { decoration, target } = event;
            const decorationData = this.getDecorationData(target);
            if (decorationData) {
                const { applicable, inheritable } = decorationData;
                applicable.add(decoration);
                if (inheritable) {
                    inheritable.add(decoration);
                }
            }
        };
        this.updateTarget = () => {
            for (const [decoration] of this.decorations) {
                for (const [target, flag] of Array.from(decoration.appliedTargets)) {
                    decoration.removeTarget(target);
                    const newTarget = this.root.getTreeNodeByPath(target.path);
                    if (newTarget) {
                        decoration.addTarget(newTarget, flag);
                    }
                }
            }
        };
        this.unTargetDecoration = (event) => {
            const { decoration, target } = event;
            const decorationData = this.getDecorationData(target);
            if (decorationData) {
                const { applicable, inheritable } = decorationData;
                applicable.remove(decoration);
                if (inheritable) {
                    inheritable.remove(decoration);
                }
            }
        };
        this.negateDecoration = (event) => {
            const { decoration, target } = event;
            const decorationData = this.getDecorationData(target);
            if (decorationData) {
                const { applicable, inheritable } = decorationData;
                applicable.negate(decoration);
                if (inheritable) {
                    inheritable.negate(decoration);
                }
            }
        };
        this.unNegateDecoration = (event) => {
            const { decoration, target } = event;
            const decorationData = this.getDecorationData(target);
            if (decorationData) {
                const { applicable, inheritable } = decorationData;
                applicable.unNegate(decoration);
                if (inheritable) {
                    inheritable.unNegate(decoration);
                }
            }
        };
        this.switchParent = (target, prevParent, newParent) => {
            const ownMeta = this.decorationsMeta.get(target);
            if (!ownMeta) {
                return;
            }
            const newParentMeta = this.getDecorationData(newParent);
            if (newParentMeta) {
                ownMeta.applicable.changeParent(newParentMeta.inheritable);
                if (ownMeta.inheritable) {
                    ownMeta.inheritable.changeParent(newParentMeta.inheritable);
                }
            }
        };
        this.decorationsMeta.set(root, {
            applicable: new CompositeDecoration_1.CompositeDecoration(root, CompositeDecoration_1.CompositeDecorationType.Applicable),
            inheritable: new CompositeDecoration_1.CompositeDecoration(root, CompositeDecoration_1.CompositeDecorationType.Inheritable),
        });
        this.disposables.push(root.watcher.on(types_1.TreeNodeEvent.DidChangeParent, this.switchParent));
        this.disposables.push(root.watcher.on(types_1.TreeNodeEvent.DidDispose, (target) => this.decorationsMeta.delete(target)));
        this.disposables.push(root.watcher.on(types_1.TreeNodeEvent.BranchDidUpdate, this.updateTarget));
    }
    dispose() {
        for (const [decoration] of this.decorations) {
            this.removeDecoration(decoration);
        }
        this.disposables.dispose();
        this.disposed = true;
    }
    addDecoration(decoration) {
        if (this.disposed) {
            throw new Error('DecorationManager disposed');
        }
        if (this.decorations.has(decoration)) {
            return;
        }
        const disposable = new ide_utils_1.DisposableCollection();
        disposable.push(decoration.onDidAddTarget(this.targetDecoration));
        disposable.push(decoration.onDidRemoveTarget(this.unTargetDecoration));
        disposable.push(decoration.onDidNegateTarget(this.negateDecoration));
        disposable.push(decoration.onDidUnNegateTarget(this.unNegateDecoration));
        this.decorations.set(decoration, disposable);
        for (const [target] of decoration.appliedTargets) {
            this.targetDecoration({ decoration, target });
        }
        for (const [target] of decoration.negatedTargets) {
            this.negateDecoration({ decoration, target });
        }
    }
    removeDecoration(decoration) {
        const decorationSubscriptions = this.decorations.get(decoration);
        if (!decorationSubscriptions) {
            return;
        }
        for (const [target] of decoration.appliedTargets) {
            const meta = this.decorationsMeta.get(target);
            if (meta) {
                meta.applicable.remove(decoration);
                if (meta.inheritable) {
                    meta.inheritable.remove(decoration);
                }
            }
        }
        for (const [target] of decoration.negatedTargets) {
            const meta = this.decorationsMeta.get(target);
            if (meta) {
                meta.applicable.unNegate(decoration);
                if (meta.inheritable) {
                    meta.inheritable.unNegate(decoration);
                }
            }
        }
        decorationSubscriptions.dispose();
        this.decorations.delete(decoration);
    }
    getDecorations(item) {
        if (!item || !TreeNode_1.TreeNode.is(item)) {
            return;
        }
        const decMeta = this.getDecorationData(item);
        if (decMeta) {
            return decMeta.applicable.compositeCssClasslist;
        }
        return;
    }
    getDecorationData(item) {
        if (this.disposed) {
            return;
        }
        const meta = this.decorationsMeta.get(item);
        if (meta) {
            return meta;
        }
        // 执行到这里说明该节点不是直接节点，而是需要从父级节点继承装饰器属性
        if (!item || !item.parent) {
            return;
        }
        const parentMeta = this.getDecorationData(item.parent);
        if (parentMeta) {
            const ownMeta = {
                applicable: new CompositeDecoration_1.CompositeDecoration(item, CompositeDecoration_1.CompositeDecorationType.Applicable, parentMeta.inheritable),
                inheritable: TreeNode_1.CompositeTreeNode.is(item)
                    ? new CompositeDecoration_1.CompositeDecoration(item, CompositeDecoration_1.CompositeDecorationType.Inheritable, parentMeta.inheritable)
                    : undefined,
            };
            this.decorationsMeta.set(item, ownMeta);
            return ownMeta;
        }
        return;
    }
}
exports.DecorationsManager = DecorationsManager;
//# sourceMappingURL=DecorationManager.js.map