interface MEventData<T> {
    callback: T,
    thisObj: any,
    bindFunc?: any
}
export default class MEvent<T extends Function>{
    private list: MEventData<T>[] = [];
    private isTraversing = false;
    private deleteList: MEventData<T>[] = [];
    public add(callback: T, thisObj?: any) {
        this.list.push({
            callback: callback,
            thisObj: thisObj,
            bindFunc: thisObj ? callback.bind(thisObj) : undefined
        });
    }

    public clear() {
        if (this.isTraversing) {
            this.deleteList.concat(this.list);
        } else {
            this.list = [];
        }
    }

    public remove(callback: T, thisObj?: any) {
        if (this.isTraversing) {
            this.deleteList.push({
                callback: callback,
                thisObj: thisObj
            });
        } else {
            this.list = this.list.filter(e => e.callback !== callback || e.thisObj !== thisObj);
        }
    }

    public call(...args: any[]) {
        this.isTraversing = true;
        let item: MEventData<T> = null;
        for (let i = 0; i < this.list.length; i++) {
            item = this.list[i];
            if (item.bindFunc) {
                item.bindFunc(...args);
            } else {
                item.callback(...args);
            }
        }
        for (let i = 0; i < this.deleteList.length; i++) {
            this.list = this.list.filter(e => e.callback !== this.deleteList[i].callback || e.thisObj !== this.deleteList[i].thisObj);
        }
        this.deleteList = [];
        this.isTraversing = false;
    }
} 