"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompositeDecoration = exports.ChangeReason = exports.CompositeDecorationType = exports.ClasslistComposite = void 0;
const ide_utils_1 = require("@opensumi/ide-utils");
const Decoration_1 = require("./Decoration");
class ClasslistComposite {
    constructor(
    /**
     * 注册样式变化监听函数
     */
    addChangeListener, 
    /**
     * 注销样式变化监听函数
     */
    removeChangeListener) {
        this.addChangeListener = addChangeListener;
        this.removeChangeListener = removeChangeListener;
    }
}
exports.ClasslistComposite = ClasslistComposite;
var CompositeDecorationType;
(function (CompositeDecorationType) {
    CompositeDecorationType[CompositeDecorationType["Applicable"] = 1] = "Applicable";
    CompositeDecorationType[CompositeDecorationType["Inheritable"] = 2] = "Inheritable";
})(CompositeDecorationType = exports.CompositeDecorationType || (exports.CompositeDecorationType = {}));
var ChangeReason;
(function (ChangeReason) {
    ChangeReason[ChangeReason["UnTargetDecoration"] = 1] = "UnTargetDecoration";
    ChangeReason[ChangeReason["TargetDecoration"] = 2] = "TargetDecoration";
})(ChangeReason = exports.ChangeReason || (exports.ChangeReason = {}));
class CompositeDecoration {
    constructor(target, type, parent) {
        this.handleDecorationDidAddClassname = (event) => {
            const { classname } = event;
            if (!this.selfOwned || !classname) {
                return;
            }
            this.compositeCssClasslist.classlist.push(classname);
            this.notifyClasslistChange();
        };
        this.handleDecorationDidRemoveClassname = (event) => {
            const { classname } = event;
            if (!this.selfOwned || !classname) {
                return;
            }
            const idx = this.compositeCssClasslist.classlist.indexOf(classname);
            if (idx > -1) {
                this.compositeCssClasslist.classlist.splice(idx, 1);
                this.notifyClasslistChange();
            }
        };
        this.mergeDecorationClasslist = (event) => {
            const { decoration } = event;
            if (!this.selfOwned) {
                return;
            }
            this.compositeCssClasslist.classlist.push(...decoration.cssClassList);
            this.notifyClasslistChange();
        };
        this.handleDecorationDisable = (event) => {
            const { decoration } = event;
            this.removeDecorationClasslist(decoration);
        };
        this.target = target;
        this.type = type;
        this.linkedComposites = new Set();
        this.classlistChangeCallbacks = new Set();
        this.compositeCssClasslist = new ClasslistComposite(this.classlistChangeCallbacks.add.bind(this.classlistChangeCallbacks), this.classlistChangeCallbacks.delete.bind(this.classlistChangeCallbacks));
        if (parent) {
            this.selfOwned = false;
            this.parent = parent;
            this.renderedDecorations = parent.renderedDecorations;
            this.compositeCssClasslist.classlist = parent.compositeCssClasslist.classlist;
            parent.linkedComposites.add(this);
        }
        else {
            this.renderedDecorations = new Map();
            this.targetedDecorations = new Set();
            this.negatedDecorations = new Set();
            this.compositeCssClasslist.classlist = [];
            this.selfOwned = true;
        }
    }
    changeParent(newParent) {
        if (!newParent) {
            return;
        }
        if (!this.selfOwned) {
            return this.parentOwn(newParent);
        }
        // 清除所有除了匹配的装饰器属性
        for (const [decoration] of this.renderedDecorations) {
            this.recursiveRefresh(this, false, ChangeReason.UnTargetDecoration, decoration, false);
        }
        if (this.parent !== newParent) {
            this.parent.linkedComposites.delete(this);
            this.parent = newParent;
            newParent.linkedComposites.add(this);
        }
        // 然后添加所有除了不适用的继承装饰器
        for (const [decoration] of newParent.renderedDecorations) {
            this.recursiveRefresh(this, false, ChangeReason.TargetDecoration, decoration, false);
        }
    }
    add(decoration) {
        const applicationMode = decoration.appliedTargets.get(this.target);
        const applicableToSelf = applicationMode &&
            (applicationMode === Decoration_1.TargetMatchMode.Self || applicationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
        const applicableToChildren = applicationMode &&
            (applicationMode === Decoration_1.TargetMatchMode.Children || applicationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
        if (this.type === CompositeDecorationType.Applicable && !applicableToSelf) {
            return;
        }
        if (this.type === CompositeDecorationType.Inheritable && !applicableToChildren) {
            return;
        }
        if (!this.selfOwned) {
            this.selfOwn(ChangeReason.TargetDecoration, decoration);
            this.targetedDecorations.add(decoration);
            return;
        }
        if (this.targetedDecorations.has(decoration)) {
            return;
        }
        this.targetedDecorations.add(decoration);
        this.recursiveRefresh(this, false, ChangeReason.TargetDecoration, decoration);
    }
    remove(decoration) {
        if (!this.selfOwned) {
            return;
        }
        if (this.targetedDecorations.delete(decoration)) {
            if (this.negatedDecorations.size === 0 && this.targetedDecorations.size === 0 && this.parent) {
                return this.parentOwn(undefined, ChangeReason.UnTargetDecoration, decoration);
            }
            this.recursiveRefresh(this, false, ChangeReason.UnTargetDecoration, decoration);
        }
    }
    negate(decoration) {
        const negationMode = decoration.negatedTargets.get(this.target);
        const negatedOnSelf = negationMode && (negationMode === Decoration_1.TargetMatchMode.Self || negationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
        const negatedOnChildren = negationMode && (negationMode === Decoration_1.TargetMatchMode.Children || negationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
        if (this.type === CompositeDecorationType.Applicable && !negatedOnSelf) {
            return;
        }
        if (this.type === CompositeDecorationType.Inheritable && !negatedOnChildren) {
            return;
        }
        if (!this.selfOwned) {
            this.selfOwn(ChangeReason.UnTargetDecoration, decoration);
            this.negatedDecorations.add(decoration);
            return;
        }
        if (this.negatedDecorations.has(decoration)) {
            return;
        }
        this.negatedDecorations.add(decoration);
        if (this.renderedDecorations.has(decoration)) {
            this.removeDecorationClasslist(decoration);
        }
    }
    unNegate(decoration) {
        if (!this.selfOwned) {
            return;
        }
        if (this.negatedDecorations.delete(decoration)) {
            if (this.negatedDecorations.size === 0 && this.targetedDecorations.size === 0 && this.parent) {
                return this.parentOwn();
            }
            // 当前非父节点并且其父节点和其本身均不含有该装饰器
            if (!this.renderedDecorations.has(decoration) &&
                (this.parent.renderedDecorations.has(decoration) || decoration.appliedTargets.has(this.target))) {
                this.recursiveRefresh(this, false, ChangeReason.TargetDecoration, decoration);
            }
        }
    }
    selfOwn(reason, decoration) {
        if (this.selfOwned) {
            throw new Error('CompositeDecoration is already self owned');
        }
        const parent = this.parent;
        this.selfOwned = true;
        this.compositeCssClasslist.classlist = [];
        this.renderedDecorations = new Map();
        this.targetedDecorations = new Set();
        this.negatedDecorations = new Set();
        // 首先处理所有继承的装饰器
        for (const [inheritedDecoration] of parent.renderedDecorations) {
            if (inheritedDecoration !== decoration) {
                this.processCompositeAlteration(ChangeReason.TargetDecoration, inheritedDecoration);
            }
        }
        // 当触发的为:not类型装饰器变化
        if (reason === ChangeReason.UnTargetDecoration &&
            // 父节点装饰器拥有此装饰器
            this.parent.renderedDecorations.has(decoration) &&
            // 本身不包含此装饰器
            !this.renderedDecorations.has(decoration)) {
            // 通知ClassList变化
            this.notifyClasslistChange(false);
        }
        this.recursiveRefresh(this, true, reason, decoration);
    }
    parentOwn(newParent, reason, decoration) {
        this.selfOwned = false;
        this.targetedDecorations && this.targetedDecorations.clear();
        this.negatedDecorations && this.negatedDecorations.clear();
        if (newParent && this.parent !== newParent) {
            if (this.parent) {
                this.parent.linkedComposites.delete(this);
            }
            newParent.linkedComposites.add(this);
            this.parent = newParent;
        }
        this.recursiveRefresh(this, true, reason, decoration);
    }
    processCompositeAlteration(reason, decoration) {
        if (!this.selfOwned) {
            throw new Error('CompositeDecoration is not self owned');
        }
        if (reason === ChangeReason.UnTargetDecoration) {
            const disposable = this.renderedDecorations.get(decoration);
            if (disposable) {
                const applicationMode = decoration.appliedTargets.get(this.target);
                const applicableToSelf = applicationMode &&
                    (applicationMode === Decoration_1.TargetMatchMode.Self || applicationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
                const applicableToChildren = applicationMode &&
                    (applicationMode === Decoration_1.TargetMatchMode.Children || applicationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
                if (applicableToSelf && this.type === CompositeDecorationType.Applicable) {
                    return false;
                }
                if (applicableToChildren && this.type === CompositeDecorationType.Inheritable) {
                    return false;
                }
                this.removeDecorationClasslist(decoration, false);
                if (disposable) {
                    disposable.dispose();
                }
                return this.renderedDecorations.delete(decoration);
            }
            return false;
        }
        if (reason === ChangeReason.TargetDecoration) {
            const negationMode = decoration.negatedTargets.get(this.target);
            const negatedOnSelf = negationMode && (negationMode === Decoration_1.TargetMatchMode.Self || negationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
            const negatedOnChildren = negationMode && (negationMode === Decoration_1.TargetMatchMode.Children || negationMode === Decoration_1.TargetMatchMode.SelfAndChildren);
            if (negatedOnSelf && this.type === CompositeDecorationType.Applicable) {
                return false;
            }
            if (negatedOnChildren && this.type === CompositeDecorationType.Inheritable) {
                return false;
            }
            if (!this.renderedDecorations.has(decoration)) {
                const disposables = new ide_utils_1.DisposableCollection();
                disposables.push(decoration.onDidAddCSSClassname(this.handleDecorationDidAddClassname));
                disposables.push(decoration.onDidRemoveCSSClassname(this.handleDecorationDidRemoveClassname));
                disposables.push(decoration.onDidDisableDecoration(this.handleDecorationDisable));
                disposables.push(decoration.onDidEnableDecoration(this.mergeDecorationClasslist));
                this.renderedDecorations.set(decoration, disposables);
                if (!decoration.disabled) {
                    this.compositeCssClasslist.classlist.push(...decoration.cssClassList);
                    return true;
                }
                return false;
            }
        }
        return false;
    }
    recursiveRefresh(origin, updateReferences, reason, decoration, notifyListeners = true) {
        // 更改当前manager引用的renderedDecorations及compositeCssClasslist.classlist
        if (!this.selfOwned && updateReferences) {
            this.renderedDecorations = this.parent.renderedDecorations;
            this.compositeCssClasslist.classlist = this.parent.compositeCssClasslist.classlist;
        }
        if (this.selfOwned && updateReferences && origin !== this) {
            // 清理所有装饰器逻辑
            for (const [renderedDecoration] of this.renderedDecorations) {
                this.processCompositeAlteration(ChangeReason.UnTargetDecoration, renderedDecoration);
            }
            // 添加继承的装饰器逻辑
            for (const [inheritedDecoration] of this.parent.renderedDecorations) {
                this.processCompositeAlteration(ChangeReason.TargetDecoration, inheritedDecoration);
            }
            if (notifyListeners) {
                this.notifyClasslistChange(false);
            }
        }
        else if (this.selfOwned &&
            reason === ChangeReason.UnTargetDecoration &&
            decoration &&
            this.renderedDecorations.has(decoration)) {
            this.processCompositeAlteration(reason, decoration);
            if (notifyListeners) {
                this.notifyClasslistChange(false);
            }
        }
        else if (this.selfOwned &&
            reason === ChangeReason.TargetDecoration &&
            decoration &&
            this.processCompositeAlteration(reason, decoration) &&
            notifyListeners) {
            this.notifyClasslistChange(false);
        }
        else if (!this.selfOwned && notifyListeners) {
            this.notifyClasslistChange(false);
        }
        for (const linkedComposite of this.linkedComposites) {
            linkedComposite.recursiveRefresh(origin, updateReferences, reason, decoration, notifyListeners);
        }
    }
    removeDecorationClasslist(decoration, notifyAll = true) {
        if (!this.selfOwned) {
            return;
        }
        for (const classname of decoration.cssClassList) {
            const idx = this.compositeCssClasslist.classlist.indexOf(classname);
            if (idx > -1) {
                this.compositeCssClasslist.classlist.splice(idx, 1);
            }
        }
        if (notifyAll) {
            this.notifyClasslistChange();
        }
    }
    notifyClasslistChange(recursive = true) {
        for (const cb of [...this.classlistChangeCallbacks]) {
            cb();
        }
        if (recursive) {
            for (const linkedComposite of this.linkedComposites) {
                if (!linkedComposite.selfOwned) {
                    linkedComposite.notifyClasslistChange();
                }
            }
        }
    }
}
exports.CompositeDecoration = CompositeDecoration;
//# sourceMappingURL=CompositeDecoration.js.map