const DefaultTag = 'default';
const defaultPriority = 0;

const __ = {
    private: Symbol('private')
}


const controlClassMap = new Map();

/**
 * 层级控制器 (实例化THING.App时自动初始化)
 * @param {Object} app - 应用实例,包含 level、levelControlManager 等
 * @public
 *
 * 初始化行为:
 * - 启用默认控件
 * - 为已有控件动态定义访问属性(this[name] 可读写)
 */
class LevelControls {

    static setLevelControlClass(levelName, levelCondition, controlClass) {
        controlClassMap.set(levelName, { condition: levelCondition, cls: controlClass });
    };

    constructor(app) {
        this.app = app;
        let _private = this[__.private] = {};

        _private.controlsMap = new Map();

        _private.addControlProperty = (name, condition, control) => {
            let contorlOption = {
                control,
                condition,
                tag: DefaultTag
            };

            _private.controlsMap.set(name, contorlOption);

            Object.defineProperty(this, name, {
                get: () => {
                    const controlParam = _private.controlsMap.get(name);
                    if (controlParam) {
                        return controlParam.control;
                    } else {
                        return null;
                    }

                },
                set: (control) => {
                    const controlParam = _private.controlsMap.get(name);
                    if (controlParam) {
                        this.addControl(controlParam.condition, name, control);
                    }
                },
                configurable: true
            });
        };

        // Initialize the level control
        controlClassMap.forEach((val, key) => {
            app.level.levelControlManager.registerClass(val.cls, { condition: val.condition, name: key, tag: DefaultTag });
        });

        app.level.levelControlManager.enableControls(DefaultTag);

        // 兼容campus原来的接口
        const controls = app.level.levelControlManager.getControlsByTag(DefaultTag);
        for (let i = 0; i < controls.length; i++) {
            const control = controls[i];
            const options = control.options;
            _private.addControlProperty(options.name, options.condition, control);
        }
    }

    /**
     * 批量设置所有已注册控件的选项
     * @param {string} option - 要设置的选项名
     * @param {*} value - 要设置的值
     * @public
     *
     * 遍历 private.controlsMap,将每个控件的对应 option 设置为 value。
     */
    setControlOption(option, value) {
        let _private = this[__.private];
        _private.controlsMap.forEach((controlParam) => {
            controlParam.control[option] = value;
        })
    }

    /**
     * 添加(注册)控件实例到 level 管理器,并在当前实例上建立访问属性
     * @param {String} condition - 控件的启用条件
     * @param {string} name - 控件名称(用于在 this 上创建属性)
     * @param {DefaultLevelControl} control - 控件实例(需满足 isDefaultLevelControl)
     * @param {Object} [options] - 注册时的额外选项(会与默认 tag 和优先级合并)
     * @public
     *
     * 行为:
     * - 若 control 不合法则忽略
     * - 先注销同名控件(若存在)
     * - 调用 app.level.register 注册控件
     * - 在私有表中添加属性并在 this 上定义可访问属性
     */
    addControl(condition, name, control, options) {
        if (!control || !control.isDefaultLevelControl) {
            return;
        }

        // unregister
        this.removeControl(name);

        // register
        this.app.level.register(condition, control, { tag: DefaultTag, priority: defaultPriority, ...options });

        this[__.private].addControlProperty(name, condition, control);

    }

    /**
     * 移除(注销)指定名称的控件
     * @param {string} name - 要移除的控件名
     * @public
     *
     * 行为:
     * - 调用 app.level.unregister 注销控件实例
     * - 从私有映射中删除,并从 this 上移除对应属性
     */
    removeControl(name) {
        let _private = this[__.private];

        let controlParam = _private.controlsMap.get(name);
        if (!controlParam) {
            return;
        }

        this.app.level.unregister(controlParam.control);
        _private.controlsMap.delete(name);

        delete this[name];
    }

}

export { LevelControls }