export default class EventEmitter {
	constructor(listeners = []) {
		this._listeners = new Map(listeners);
		this._middlewares = new Map();
	}

	listenerCount(eventName) {
		if (!this._listeners.has(eventName)) {
			return 0;
		}

		const eventListeners = this._listeners.get(eventName);
		return eventListeners.length;
	}

	removeListeners(eventName = null, middleware = false) {
		if (eventName !== null) {
			if (Array.isArray(eventName)) {
				name.forEach(e => this.removeListeners(e, middleware));
			} else {
				this._listeners.delete(eventName);

				if (middleware) {
					this.removeMiddleware(eventName);
				}
			}
		} else {
			this._listeners = new Map();
		}
	}

	middleware(eventName, fn) {
		if (Array.isArray(eventName)) {
			name.forEach(e => this.middleware(e, fn));
		} else {
			if (!Array.isArray(this._middlewares.get(eventName))) {
				this._middlewares.set(eventName, []);
			}

			(this._middlewares.get(eventName)).push(fn);
		}
	}

	removeMiddleware(eventName = null) {
		if (eventName !== null) {
			if (Array.isArray(eventName)) {
				name.forEach(e => this.removeMiddleware(e));
			} else {
				this._middlewares.delete(eventName);
			}
		} else {
			this._middlewares = new Map();
		}
	}

	on(name, callback, once = false) {
		if (Array.isArray(name)) {
			name.forEach(e => this.on(e, callback));
		} else {
			name = name.toString();
			const split = name.split(/,|, | /);

			if (split.length > 1) {
				split.forEach(e => this.on(e, callback));
			} else {
				if (!Array.isArray(this._listeners.get(name))) {
					this._listeners.set(name, []);
				}

				(this._listeners.get(name)).push({once: once, callback: callback});
			}
		}
	}

	once(name, callback) {
		this.on(name, callback, true);
	}

	emit(name, data, silent = false) {
		name = name.toString();
		let listeners = this._listeners.get(name);
		let middlewares = null;
		let doneCount = 0;
		let execute = silent;

		if (Array.isArray(listeners)) {
			listeners.forEach((listener, index) => {
				// Start Middleware checks unless we're doing a silent emit
				if (!silent) {
					middlewares = this._middlewares.get(name);
					// Check and execute Middleware
					if (Array.isArray(middlewares)) {
						middlewares.forEach(middleware => {
							middleware(data, (newData = null) => {
								if (newData !== null) {
									data = newData;
								}
								doneCount++;
							}, name);
						});

						if (doneCount >= middlewares.length) {
							execute = true;
						}
					} else {
						execute = true;
					}
				}

				// If Middleware checks have been passed, execute
				if (execute) {
					if (listener.once) {
						listeners[index] = null;
					}
					listener.callback(data);
				}
			});

			// Dirty way of removing used Events
			while (listeners.indexOf(null) !== -1) {
				listeners.splice(listeners.indexOf(null), 1);
			}
		}
	}
}
