import { excludedInJSON } from '../decorators';

export type EventListener = (...args: Array<any>) => any;

export class EventEmitter {
    @excludedInJSON()
    private readonly _events: { [name: string]: Array<EventListener> } = {};
    /**
     * 监听事件
     * @param eventName 事件名
     * @param listener 监听器
     */
    on(eventName: string, listener: EventListener) {
        let listeners = this._events[eventName];
        if (!listeners)
            listeners = this._events[eventName] = [];

        const index = listeners.indexOf(listener);
        !~index && listeners.push(listener);
    }
    /**
     * 取消监听事件
     * @param eventName 事件名
     * @param listener 监听器
     */
    off(eventName: string, listener: EventListener) {
        const listeners = this._events[eventName];
        if (listeners) {
            const index = listeners.indexOf(listener);
            ~index && listeners.splice(index, 1);
        }
    }
    /**
     * 只监听一次事件
     * @param eventName 事件名
     * @param listener 监听器
     */
    once(eventName: string, listener: EventListener) {
        const temp = (...args: Array<any>) => {
            this.off(eventName, temp);
            listener.apply(this, args);
        };
        this.on(eventName, temp);
    }
    /**
     * 触发事件
     * @param eventName 事件名
     * @param args 事件参数
     */
    emit(eventName: string, ...args: Array<any>) {
        const listeners = this._events[eventName];
        listeners && listeners.forEach((listener) => listener.apply(this, args));
    }
}

export default EventEmitter;
