'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 _Task = require('../tasks/Task');

var _Task2 = _interopRequireDefault(_Task);

var _Factory = require('../factory/Factory');

var _Factory2 = _interopRequireDefault(_Factory);

var _Injector = require('../tasks/Injector');

var _Injector2 = _interopRequireDefault(_Injector);

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

/**
 * Collection. Abstract class.
 *
 * Basic collection class. Do NOT instantiate directly.
 *
 * @param {Function} complete function to be called on complete
 * @param {Function} recover function to be called on recover
 */
var Collection = function () {
  /**
   * Task constructor
   *
   * @param {Function} complete function to be called on complete
   * @param {Function} recover function to be called on recover
   */
  function Collection(complete, recover) {
    _classCallCheck(this, Collection);

    this.tasks = [];

    this._autoRun = false;
    this._running = false;

    this._attached = {};

    this.__complete = new _Task2.default(undefined, complete, undefined);
    this.__recover = new _Task2.default(undefined, undefined, recover);

    this.__complete.attach(_Factory2.default._CHAIN_, this);
    this.__recover.attach(_Factory2.default._CHAIN_, this);

    _Injector2.default.addChainGetter(this.__complete);
    _Injector2.default.addChainGetter(this.__recover);
  }

  /**
   * Attaches variable with a key
   *
   * Used to avoid using global variables or trying to scope
   * in some way. After attach() you can get().
   * Attach will also keep the variable from GC.
   *
   * @param {string} key accessor for the variable
   * @param {any} value variable value
   */


  _createClass(Collection, [{
    key: 'attach',
    value: function attach(key, value) {
      this._attached[key] = value;
    }

    /**
     * Detaches variable with a key
     *
     * @param {string} key accessor for the variable
     */

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

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

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

    /**
     * Pushes task to the collection
     *
     * @param {Task} task task to push
     * @return {Collection} collection current collection
     */

  }, {
    key: 'push',
    value: function push(task) {
      this._chainTask(task);
      this.tasks.push(task);

      this._postTaskAdds();

      return this;
    }

    /**
     * Unshifts task to the collection
     *
     * @param {Task} task task to push
     * @return {Collection} collection current collection
     */

  }, {
    key: 'unshift',
    value: function unshift(task) {
      this._chainTask(task);
      this.tasks.unshift(task);

      this._postTaskAdds();

      return this;
    }

    /**
     * Removes task from the collection
     *
     * @param {Task} task task to push
     * @return {Collection} collection current collection
     */

  }, {
    key: 'remove',
    value: function remove(task) {
      var index = this.tasks.indexOf(task);
      if (index !== -1) {
        this._unchainTask(task);
        this.tasks.splice(index, 1);
      }

      return this;
    }

    /**
     * Runs all tasks in the collection
     */

  }, {
    key: 'run',
    value: function run() {
      this._running = true;
    }

    /**
     * Stops all tasks in the collection
     *
     * @return {boolean} stopped stopped status
     */

  }, {
    key: 'stop',
    value: function stop() {
      return false;
    }

    /**
     * Resets a stopped collection
     *
     * @return {boolean} reset reset status
     */

  }, {
    key: 'reset',
    value: function reset() {
      if (!this._running) {
        this._attached = {};
        while (this.tasks.length > 0) {
          this.remove(this.tasks[0]);
        }

        return true;
      } else {
        return false;
      }
    }

    /**
     * Complete
     *
     * Runs complete task
     *
     * @protected
     */

  }, {
    key: '_complete',
    value: function _complete() {
      this._running = false;

      this.__complete.run();
    }

    /**
     * Recover
     *
     * Runs recover task
     *
     * @protected
     */

  }, {
    key: '_recover',
    value: function _recover(error) {
      this._running = false;

      this.__recover.recover(error);
    }

    /**
     * Chain task
     *
     * Attach the chain to the task
     *
     * @param {Task} task task to chain
     *
     * @protected
     */

  }, {
    key: '_chainTask',
    value: function _chainTask(task) {
      task.attach(_Factory2.default._CHAIN_, this);
      _Injector2.default.addChainGetter(task);
    }

    /**
     * Unchain task
     *
     * Detach the chain from the task
     *
     * @param {Task} task task to chain
     *
     * @protected
     */

  }, {
    key: '_unchainTask',
    value: function _unchainTask(task) {
      _Injector2.default.removeChainGetter(task);
      task.detach(_Factory2.default._CHAIN_);
    }

    /**
     * Probe post add actions
     *
     * Try all post add triggers
     *
     * @protected
     */

  }, {
    key: '_postTaskAdds',
    value: function _postTaskAdds() {
      if (this.autoRun) {
        this.run();
      }
    }

    /**
     * Gets the running status
     *
     * @return {boolean} running running status
     */

  }, {
    key: 'running',
    get: function get() {
      return this._running;
    }

    /**
     * Gets the current task(s)
     *
     * @return {Task|Array<Task>} task current task(s)
     */

  }, {
    key: 'current',
    get: function get() {
      return undefined;
    }

    /**
     * Gets the passed task(s)
     *
     * @return {Array<Task>} task passed task(s)
     */

  }, {
    key: 'passed',
    get: function get() {
      return undefined;
    }

    /**
     * Sets autoRun
     *
     * Will autorun on push or unshift
      * @param {boolean} autoRun auto runs on push or unshift
     */

  }, {
    key: 'autoRun',
    set: function set(value) {
      this._autoRun = value;
    }

    /**
     * Gets autoRun
     *
     * @return {boolean} autoStart auto start on push or unshift
     */
    ,
    get: function get() {
      return this._autoRun;
    }
  }]);

  return Collection;
}();

exports.default = Collection;