'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

// Import

var _require = require('events');

var EventEmitter = _require.EventEmitter;

var _require2 = require('taskgroup');

var TaskGroup = _require2.TaskGroup;

var ambi = require('ambi');

/**
Events EventEmitter to allow you to execute events in serial or parallel.
Made possible thanks to TaskGroup.

Inherits from https://nodejs.org/dist/latest/docs/api/events.html#events_class_eventemitter

Uses https://github.com/bevry/taskgroup

@class EventEmitterGrouped
@extends EventEmitter
@constructor
@access public
*/

var EventEmitterGrouped = function (_EventEmitter) {
	_inherits(EventEmitterGrouped, _EventEmitter);

	function EventEmitterGrouped() {
		_classCallCheck(this, EventEmitterGrouped);

		return _possibleConstructorReturn(this, Object.getPrototypeOf(EventEmitterGrouped).apply(this, arguments));
	}

	_createClass(EventEmitterGrouped, [{
		key: 'getListenerGroup',


		/**
  Get a TaskGroup for a particular event.
  For each listener, treat them as Tasks within a TaskGroup, and return the TaskGroup.
  @param {string} eventName
  @param {...*} args - the arguments to forward to each task, with the last one being a completion callback with signature `error, results`
  @returns {TaskGroup}
  @access public
  */
		value: function getListenerGroup(eventName) {
			for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
				args[_key - 1] = arguments[_key];
			}

			// Get listeners
			var next = args.pop();
			var me = this;

			// Prepare tasks
			var tasks = new TaskGroup('EventEmitterGrouped for ' + eventName).done(next);

			// Convert the listeners into objects that we can use
			var listenerObjects = this.listeners(eventName).slice().map(function (listener) {
				// Prepare
				var listenerObject = {};

				// The `once` method will actually wrap around the original listener, which isn't what we want for the introspection
				// So we must pass fireWithOptionalCallback an array of the method to fire, and the method to introspect
				// https://github.com/bevry/docpad/issues/462
				// https://github.com/joyent/node/commit/d1b4dcd6acb1d1c66e423f7992dc6eec8a35c544
				if (listener.listener) {
					// this is a `once` thing
					listenerObject.actual = listener.listener;
					listenerObject.fire = [listener.bind(me), listener.listener];
				} else {
					listenerObject.actual = listener;
					listenerObject.fire = listener.bind(me);
				}

				// Defaults
				listenerObject.priority = listenerObject.actual.priority || 0;
				listenerObject.name = listenerObject.name || 'Untitled listener for [' + eventName + '] with priority [' + listenerObject.priority + ']';

				// Return the new listenerObject
				return listenerObject;
			});

			// Sort the listeners by highest priority first
			listenerObjects.sort(function (a, b) {
				return b.priority - a.priority;
			});

			// Add the tasks for the listeners
			listenerObjects.forEach(function (listenerObject) {
				// Bind to the task
				tasks.addTask(listenerObject.name, function (complete) {
					// Fire the listener, treating the callback as optional
					ambi.apply(undefined, [listenerObject.fire].concat(args, [complete]));
				});
			});

			// Return
			return tasks;
		}

		/**
  Refer to EventEmitter#removeListener
  https://nodejs.org/dist/latest/docs/api/events.html#events_emitter_removelistener_eventname_listener
  @returns {*} whatever removeListener returns
  @access public
  */

	}, {
		key: 'off',
		value: function off() {
			return this.removeListener.apply(this, arguments);
		}

		/**
  Runs the listener group for the event in serial mode (one at a time)
  @param {...*} args - forwarded to {@link EventEmitterGrouped#getListenerGroup}
  @returns {TaskGroup}
  */

	}, {
		key: 'emitSerial',
		value: function emitSerial() {
			return this.getListenerGroup.apply(this, arguments).run();
		}

		/**
  Runs the listener group for the event in parallel mode (multiple at a time)
  @param {...*} args - forwarded to {@link EventEmitterGrouped#getListenerGroup}
  @returns {TaskGroup}
  */

	}, {
		key: 'emitParallel',
		value: function emitParallel() {
			return this.getListenerGroup.apply(this, arguments).setConfig({ concurrency: 0 }).run();
		}
	}]);

	return EventEmitterGrouped;
}(EventEmitter);

// Export


EventEmitterGrouped.EventEmitterGrouped = EventEmitterGrouped; // backwards compatability
module.exports = EventEmitterGrouped;