var Promise = require('es6-promise').Promise;
var _merge = require('lodash-node/modern/objects/merge');
var _isFunction = require('lodash-node/modern/objects/isFunction');
var _isArray = require('lodash-node/modern/objects/isArray');
var _map   = require('lodash-node/modern/collections/map');
var _forEach  = require('lodash-node/modern/collections/forEach');

/**
* Dispatcher
*/
function Dispatcher(){
	this._registry = {};
}

Dispatcher.prototype = _merge(Dispatcher.prototype, {
	
	/**
	* Registry of callbacks, waitFor, promises, etc
	* each constant has it's own array of callbacks, waitFor, promises, etc
	*/
	_registry: {},

	/**
	* Registers a callback
	* @param {string} constant
	* @param {function} callback
	* @param {array|null} waitFor Array indexes to callbacks 
	*/
	register: function(constant, callback, waitForIndexes){
		waitForIndexes = waitForIndexes || null;
		
		if( !_isFunction(callback) ){
			throw new Error('Dispatcher.register expects second parameter to be a callback');
		}
		
		if( waitForIndexes !== null && !_isArray(waitForIndexes) ){
			throw new Error('Dispatcher.register expects third parameter to be null or an array');
		}

		var registry = this._getRegistry(constant);
		registry.callbacks.push(callback);
		registry.waitFor.push(waitForIndexes);
		return registry.callbacks.length - 1;
	},


	/**
	* Dispatch
	* @param {string} constant
	* @param {object} payload
	*/
	dispatch: function(constant, payload){
		var registry = this._getRegistry(constant);
		registry.dispatchQueue.push({
			constant: constant,
			payload: payload
		});
		this._dispatch(registry);
	},

	_dispatch: function(registry){

		if( registry.isDispatching || registry.dispatchQueue.length == 0 ) {
			return;
		}

		registry.isDispatching = true;
		var job = registry.dispatchQueue.shift();

		this._createDispatchPromises(registry);

		_forEach(registry.callbacks, function(callback, idx){

			var resolve = (function(registry, idx, payload){
				return function(){
					Promise.resolve(registry.callbacks[idx](payload)).then(function(){
						registry.resolves[idx](payload)
					}, function(){
						registry.rejects[idx](new Error('Dispatch callback error'))
					});
				};
			}.bind(this))(registry, idx, job.payload);

			var waitFor = registry.waitFor[idx];
			if( !waitFor ){
				resolve();
			}
			else{
				var promisesToWaitFor = this._getPromisesByIndexes(registry, waitFor);
				Promise.all(promisesToWaitFor).then(
					resolve, 
					resolve  //Should we really resolve the callback here?
									 // Some of the WaitForStores callbacks rejected the request
									 );
			}
		}.bind(this));//_forEach(registry.callbacks,

		Promise.all(registry.promises).then(function(){
			this._onDispatchEnd(registry);
		}.bind(this), function(){
			this._onDispatchEnd(registry);
		});

	},//dispatch


	/**
	* Gets a registry for a constant
	* @param {string} constant
	*/
	_getRegistry: function(constant){
		if( typeof this._registry[constant] == "undefined" ){
			this._registry[constant] = {
				callbacks: [],
				waitFor: [],
				promises: [],
				resolves: [],
				rejects: [],
				dispatchQueue: [],
				isDispatching: false
			};
		}
		return this._registry[constant];
	},

	/**
	* @param {object} registry
	* @param {array} callbacks 
	*/
	_getPromisesByIndexes: function(registry, indexes){
		return indexes.map(function(idx){
			return registry.promises[idx];
		});
	},

	/**
	* Create promises for all callbacks in this registry
	* @param {object} registry
	*/
	_createDispatchPromises: function(registry){
		registry.promises = [];
		registry.resolves = [];
		registry.rejects = [];
		_forEach(registry.callbacks, function(callback, i){
			registry.promises[i] = new Promise(function(resolve, reject){
				registry.resolves[i] = resolve;
				registry.rejects[i] = reject;
			});
		});
	},


	/**
	* Clean registry
	* @param {object} registry
	*/
	_onDispatchEnd: function(registry){
		registry.promises = [];
		registry.resolves = [];
		registry.rejects = [];
		registry.isDispatching = false;
		this._dispatch(registry);
	}

});

module.exports = Dispatcher;
@@ -1919,16 +1919,17 @@
  resolve
+r
  = (func
@@ -2002,16 +2002,17 @@
 resolve(
+ 
 registry
@@ -2035,16 +2035,17 @@
 payload)
+ 
 ).then(f
@@ -2199,27 +2199,16 @@
 %09%7D;%0A%09%09%09%7D
-.bind(this)
 )(regist
@@ -2301,16 +2301,17 @@
 %09resolve
+r
 ();%0A%09%09%09%7D
@@ -2448,16 +2448,17 @@
 %09resolve
+r
 , %0A%09%09%09%09%09
@@ -2464,16 +2464,17 @@
 %09resolve
+r
   //Shou
@@ -2519,20 +2519,16 @@
 ?%0A%09%09%09%09%09%09
-%09%09%09 
 // Some 
@@ -2587,14 +2587,8 @@
 %09%09%09%09
-%09%09%09%09%09 
 );%0A%09
@@ -4079,8 +4079,9 @@
 patcher;
+%0A

Update dispatcher.js