/**
 * Created by rockyl on 2018-11-27.
 */

/**
 * 单一事件类
 * 一对多形式的订阅分发机制
 */
export class ScillaEvent {
	private _subscribers: any[];

	constructor() {
		this._subscribers = [];
	}

	private findListener(callback) {
		const {_subscribers} = this;

		let result;
		for (let i = 0, li = _subscribers.length; i < li; i++) {
			const subscriber = _subscribers[i];

			if (subscriber.callback == callback) {
				result = {
					subscriber,
					index: i,
				};
				break;
			}
		}

		return result;
	}

	/**
	 * 添加侦听
	 * @param callback
	 * @param thisObj
	 * @param priority
	 * @param params
	 */
	addListener(callback, thisObj?, priority = 0, ...params) {
		if (!callback) {
			return;
		}

		const {_subscribers} = this;

		const listener = this.findListener(callback);
		if (!listener) {
			_subscribers.push({
				callback,
				thisObj,
				priority,
				params,
			});
		}
	}

	/**
	 * 添加单次侦听
	 * @param callback
	 * @param thisObj
	 * @param priority
	 * @param params
	 */
	once(callback, thisObj?, priority = 0, ...params) {
		if (!callback) {
			return;
		}

		const {_subscribers} = this;

		const listener = this.findListener(callback);
		if (!listener) {
			_subscribers.push({
				callback,
				thisObj,
				priority,
				params,
				once: true,
			});
		}
	}

	/**
	 * 移除侦听
	 * @param callback
	 */
	removeListener(callback) {
		if (!callback) {
			return;
		}

		const {_subscribers} = this;

		const listener = this.findListener(callback);
		if (listener) {
			_subscribers.splice(listener.index, 1);
		}
	}

	/**
	 * 是否已经侦听
	 * @param callback
	 */
	hasListener(callback) {
		return !!this.findListener(callback);
	}

	/**
	 * 调用派发
	 * @param paramsNew
	 */
	invoke(...paramsNew) {
		const {_subscribers} = this;

		//按优先级降序
		_subscribers.sort((a, b) => {
			return a.priority - b.priority;
		});

		for (const subscriber of _subscribers) {
			if(subscriber){
				const {callback, thisObj, once, params}= subscriber;
				const allParams = params.concat(paramsNew);

				try {
					callback.apply(thisObj, allParams);
				}catch (e) {
					console.log(e);
				}

				if(once){
					this.removeListener(callback);
				}
			}
		}
	}
}
