'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

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; }; }();

var _RawMap = require('./RawMap');

var _RawMap2 = _interopRequireDefault(_RawMap);

var _TimeoutMap = require('./TimeoutMap');

var _TimeoutMap2 = _interopRequireDefault(_TimeoutMap);

var _TriggerMap = require('./TriggerMap');

var _TriggerMap2 = _interopRequireDefault(_TriggerMap);

var _AsyncMap = require('./AsyncMap');

var _AsyncMap2 = _interopRequireDefault(_AsyncMap);

var _PromiseMap = require('./PromiseMap');

var _PromiseMap2 = _interopRequireDefault(_PromiseMap);

var _Sequence = require('../chains/Sequence');

var _Sequence2 = _interopRequireDefault(_Sequence);

var _Parallel = require('../chains/Parallel');

var _Parallel2 = _interopRequireDefault(_Parallel);

var _Loop = require('../chains/Loop');

var _Loop2 = _interopRequireDefault(_Loop);

var _Limiter = require('../chains/Limiter');

var _Limiter2 = _interopRequireDefault(_Limiter);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

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

/**
 * Tasks and Collections Factory
 *
 * It's a static class - do not instantiate with new
 *
 * @static
 */
var Factory = function () {
  function Factory() {
    _classCallCheck(this, Factory);
  }

  _createClass(Factory, null, [{
    key: 'task',


    /**
     * Gets a task by registered map match
     *
     * @param {any} args parameters depend on installed maps
     * @return {Task} task matching the parameters
     */


    /**
     * Attached variables
     *
     * @param {object} attached collection of any attachments
     */

    /**
     * Predefined name for a chain in attached task
     *
     * @param {string} _CHAIN_ predefined name
     */
    value: function task() {
      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      Factory.initialize();

      var match = void 0;
      Factory.maps.forEach(function (item) {
        var result = item.match.apply(item, args);

        if (result !== undefined) {
          if (match === undefined) {
            match = result;
          } else if (match.percentage <= result.percentage) {
            match = result;
          }
        }
      });

      return match !== undefined ? match.instance : undefined;
    }

    /**
     * Gets a sequence
     *
     * @param {Function} complete function to be called on complete
     * @param {Function} recover function to be called on recover
     * @return {Sequence} new sequence
     */


    /**
     * Initialized status
     *
     * @param {boolean} initialized initialized status
     */


    /**
     * Maps collection for task matching
     *
     * @param {Array<Map>} maps list of all maps
     */

  }, {
    key: 'sequence',
    value: function sequence(complete, recover) {
      Factory.initialize();

      return new _Sequence2.default(complete, recover);
    }

    /**
     * Gets a parallel
     *
     * @param {Function} complete function to be called on complete
     * @param {Function} recover function to be called on recover
     * @param {boolean} completeOnFirst completes on last or on first
     * @return {Parallel} new sequence
     */

  }, {
    key: 'parallel',
    value: function parallel(complete, recover, completeOnFirst) {
      Factory.initialize();

      return new _Parallel2.default(complete, recover, completeOnFirst);
    }

    /**
     * Gets a loop
     *
     * @param {number} repeats number of repeats, 0 for infinite
     * @param {Function} repeat function to be called on repeat
     * @param {Function} recover function to be called on recover
     * @return {Loop} new loop
     */

  }, {
    key: 'loop',
    value: function loop(repeats, repeat, recover) {
      Factory.initialize();

      return new _Loop2.default(repeats, repeat, recover);
    }

    /**
     * Gets a limiter
     *
     * @param {number} limit max running tasks
     * @param {Function} complete function to be called on complete
     * @param {Function} recover function to be called on recover
     * @param {boolean} completeOnFirst completes on last or on first
     * @return {Limiter} new limiter
     */

  }, {
    key: 'limiter',
    value: function limiter(limit, complete, recover, completeOnFirst) {
      Factory.initialize();

      return new _Limiter2.default(limit, complete, recover, completeOnFirst);
    }

    /**
     * Initializes the factory.
     *
     * Initializes the factory. Will be called automatically on first task
     * or sequence call. Can be called explicitly with *force*
     *
     * @param {boolean} force reinitialize if true
     */

  }, {
    key: 'initialize',
    value: function initialize() {
      var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;

      if (!Factory.initialized || force) {
        Factory.initialized = true;

        Factory.maps = [new _RawMap2.default(), new _TimeoutMap2.default(), new _TriggerMap2.default(), new _AsyncMap2.default(), new _PromiseMap2.default()];
      }
    }

    /**
     * Adds new map for tasks matching
     *
     * @param {Map} map map for tasks matching
     */

  }, {
    key: 'map',
    value: function map(_map) {
      if (Factory.maps.indexOf(_map) === -1) {
        Factory.maps.push(_map);
      }
    }

    /**
     * Removes map from tasks matching
     *
     * @param {Map} map map to remove from tasks matching
     */

  }, {
    key: 'unmap',
    value: function unmap(map) {
      var index = Factory.maps.indexOf(map);
      if (index !== -1) {
        Factory.maps.splice(index, 1);
      }
    }

    /**
     * Removes all maps
     */

  }, {
    key: 'unmapAll',
    value: function unmapAll() {
      Factory.maps = [];
    }

    /**
     * Attaches variable to the factory
     *
     * Useful to store your collections and access them
     * later on from anywhere. Or store anything you want
     * in this predefined place
     *
     * @param {string} key accessor for the variable
     * @param {any} value variable value
     */

  }, {
    key: 'attach',
    value: function attach(key, value) {
      Factory.attached[key] = value;
    }

    /**
     * Detaches variable by name
     *
     * @param {string} key accessor for the variable
     */

  }, {
    key: 'detach',
    value: function detach(key) {
      delete Factory.attached[key];
    }

    /**
     * Gets variable by name
     *
     * @param {string} key accessor for the variable
     * @return {any} variable value
     */

  }, {
    key: 'get',
    value: function get(key) {
      return Factory.attached[key];
    }
  }]);

  return Factory;
}();

Factory._CHAIN_ = '_chain_';
Factory.maps = [];
Factory.attached = {};
Factory.initialized = false;
exports.default = Factory;