/**
 * @Describe: 全局消息管理(增强版)   先发布, 后订阅一样可以得到对应消息, 需要注意的是, 未订阅前发布的消息会在第一个订阅时销毁
 * 简单来说, 就是发布一个NoListen类型的消息, 如果没有监听者, 那么此消息会被保留, 等到有监听者监听此消息时, 将消息发送给监听者, 然后将Nolisten消息删除
 */
export default class EventManager {
    private static _eventMap: { [key: string]: Array<ElementEvent> } = {};
    private static _bufferEventMap: { [key: string]: Array<any> } = {};          // 缓存的消息

    /**
     * 发布一个事件
     * @param eventName 
     * @param parameter 
     */
    public static emit(eventName: string, parameter: any) {
        let array = this._eventMap[eventName];
        if (array === undefined) {
            // 将消息存入
            if (this._bufferEventMap[eventName] === undefined) {
                this._bufferEventMap[eventName] = [];
            }
            this._bufferEventMap[eventName].push(parameter);
            return;
        }
        for (let i = 0; i < array.length; i++) {
            let element = array[i];
            if (element) element.callback.call(element.target, parameter);
        }
    }

    /**
     * 订阅一个事件
     * @param eventName 事件标记
     * @param callback 回调方法
     * @param target 订阅源对象
     */
    public static addListener(eventName: string, callback: Function, target: any) {
        if (this._eventMap[eventName] === undefined) {
            this._eventMap[eventName] = [];
        }
        this._eventMap[eventName].push({ callback: callback, target: target });

        // 新订阅一个事件, 那么看看是不是有缓存的消息, 发布出去
        if (this._bufferEventMap[eventName] != undefined) {
            for (let i = 0; i < this._bufferEventMap[eventName].length; i++) {
                callback.call(target, this._bufferEventMap[eventName][i]);
            }
            this._bufferEventMap[eventName] = undefined;
        }
    }

    /**
     * 取消监听一个事件
     * @param eventName 
     * @param callback 
     * @param target 
     */
    public static removeListener(eventName: string, callback: Function, target: any) {
        let array = this._eventMap[eventName];
        if (array === undefined) return;
        for (let i = 0; i < array.length; i++) {
            let element = array[i];
            if (element && element.callback === callback && element.target === target) {
                array[i] = undefined;
                break;
            }
        }
    }
}

export class ElementEvent {
    callback: Function;
    target: any;
}