// Copyright (c) Trung Le
// Distributed under the terms of the Modified BSD License.
import { IUpdateManagerToken } from './types';
const PLUGIN_ID = 'ipecharts:updateManager';
class UpdateManager {
    constructor() {
        this._modelMap = new WeakMap();
    }
    sendUpdateSignal(model) {
        const roots = this.findRoot(model);
        roots.forEach(m => {
            m.trigger('change');
        });
    }
    findRoot(model) {
        var _a;
        const result = [];
        let parentAtThatlevel = (_a = this._modelMap.get(model)) !== null && _a !== void 0 ? _a : new Set();
        parentAtThatlevel = new Set([...parentAtThatlevel]);
        while (parentAtThatlevel.size > 0) {
            const cloned = new Set([...parentAtThatlevel]);
            cloned.forEach(it => {
                parentAtThatlevel.delete(it);
                if (this._modelMap.has(it)) {
                    const nextLevel = this._modelMap.get(it);
                    nextLevel === null || nextLevel === void 0 ? void 0 : nextLevel.forEach(el => {
                        parentAtThatlevel.add(el);
                    });
                }
                else {
                    result.push(it);
                }
            });
        }
        return result;
    }
    registerModel(model) {
        const setParentId = (m) => {
            if (m === null || m === void 0 ? void 0 : m['model_id']) {
                this.registerChildModel({ child: m, parent: model });
            }
            else if (Array.isArray(m)) {
                m.forEach(c => setParentId(c));
            }
        };
        Object.values(model.attributes).forEach(m => setParentId(m));
    }
    registerChildModel(options) {
        const { child, parent } = options;
        if ((child === null || child === void 0 ? void 0 : child.model_id) && (parent === null || parent === void 0 ? void 0 : parent.model_id)) {
            if (this._modelMap.has(child)) {
                const currentSet = this._modelMap.get(child);
                currentSet === null || currentSet === void 0 ? void 0 : currentSet.add(parent);
            }
            else {
                this._modelMap.set(child, new Set([parent]));
            }
        }
    }
    unregisterModel(model) {
        this._modelMap.delete(model);
    }
}
/**
 * Activate the widget extension.
 */
function activate(app) {
    return new UpdateManager();
}
/**
 * The example plugin.
 */
export const updateManagerPlugin = {
    id: PLUGIN_ID,
    description: 'A JupyterLab extension.',
    requires: [],
    provides: IUpdateManagerToken,
    activate: activate,
    autoStart: true
};
