class Listener{
    //关注的消息
    private _event: string = '';
    //消息对应的事件
    private _callback: Function = null;
    //回调函数的this指向
    private _callTarget: any = null;

    constructor(ev: string, callback: Function, target: any = null){
        this._event = ev;
        this._callback = callback;
        this._callTarget = target;
    }

    hasCallBack(func: Function){
        return this._callback === func;
    }

    callback(...args){
        this._callback.apply(this._callTarget,[...args]);
    }
}

class MessageMgr{

    static instance: MessageMgr = null;

    //考虑多个观察者 关注同一个消息的情况
    private _listeners: Map<string, Listener[]> = new Map();

    //注册消息
    addEvent(ev: string, callback: Function, target: any = null){
        const lis: Listener = new Listener(ev, callback, target);
        if(this._listeners.has(ev)){
            //如果消息已经被某个观察者关注了 那么找到那个数组 把新的观察者也存进去
            this._listeners.get(ev).push(lis);
            return;
        }

        //把消息和观察者对应存储
        //先创建一个Listener类型的数组
        const liss: Listener[] = [];
        //把第一个对应ev的观察者存储起来
        liss.push(lis);
        //把消息和存listener的数组 存到map 中
        this._listeners.set(ev, liss);
    }

    //激活消息
    dispatch(event: string, ...args){
        this._listeners.forEach((liss: Listener[], ev: string)=>{
            //遍历整个map 判断传递进来的消息 是否和某个键值对的键 相同
            if(event === ev){
                for(const lis of liss){
                    lis.callback(...args);
                }
            }
        })
    }

    //移除事件
    removeEvent(event: string | Function){
        if(typeof(event) === "string"){
            this._listeners.delete(event);
            return;
        }
        for(const liss of Array.from(this._listeners.values())){
            for(let i = 0; i < liss.length; i++){
                if(liss[i].hasCallBack(event)){
                    liss.splice(i , 1);
                    return;
                }
            }
        }
    }

    //移除所有事件
    removeAll(){
        this._listeners.clear();
    }

}

export const messageMgr: MessageMgr = MessageMgr.instance = new MessageMgr();