class Event
{
    listeners:any = {};
    //监听事件
    on(eventname:string, cb:any, cbthis:any)
    {
        if( !this.listeners ) this.listeners = {};
        let evtListeners = this.listeners[eventname];
        if( !evtListeners ) {
            evtListeners = [];
            this.listeners[eventname] = evtListeners;
        }
        
        let existL =  evtListeners.filter((item:any)=>item.cb == cb);
        if( existL && existL.length > 0  ) {
            existL[0].cbthis = cbthis;
            return;
        }
        evtListeners.push({cb,cbthis});

        let scope = this;
        return {
            off(){
                scope.off(eventname, cb);
            }
        }
    }

    //取消监听
    off(eventname:string, cb:any)
    {
        if( !this.listeners ) return;

        let evtListeners = this.listeners[eventname];
        if( !evtListeners ) return;
        if( !cb ) {
            this.listeners[eventname] = [];
            return ;
        }
        let n = evtListeners.length;
        while( n-- ) {
            if( evtListeners[n].cb == cb){
                evtListeners.splice(n,1);
                break;
            }
        }
    }
    //触发事件
    emit(eventname:any, ...args:any[])
    {
        if( !this.listeners ) return;
        let evtListeners = this.listeners[eventname];
        if( !evtListeners || evtListeners.length < 1) return;
        let copyed = evtListeners.slice(0);
        let n = copyed.length;
        
        for(let i=0;i<n;i++) {
            let item  = copyed[i];
            if( !item.cbthis ) item.cbthis = this;
            item.cb.call(item.cbthis, ...args);
        }
    }

    async awaitEmit(eventname:any, ...args:any[])
    {
        if( !this.listeners ) return;
        let evtListeners = this.listeners[eventname];
        if( !evtListeners || evtListeners.length < 1) return;
        let copyed = evtListeners.slice(0);
        let n = copyed.length;
        
        let objs = [];
        for(let i=0;i<n;i++) {
            let item  = copyed[i];
            if( !item.cbthis ) item.cbthis = this;
            
            let ret = item.cb.call(item.cbthis, ...args);
            if( ret ) {
                objs.push( ret );
            }
        }
        if( objs.length < 1 ) return;

        let ret = await Promise.all( objs );
        
        return ret;
    }
}

export default Event;