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

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

/**
 * Task
 *
 * Basic task with run, complete and recover
 *
 * run function can return nothing(undefined) and it will
 * call complete instantly. if run returns anything it will
 * NOT call complete automatically and it's up to you to
 * trigger complete.
 * @example run = () => { console.log('next thing is complete'); }
 * @example run = (self) => {
 *   console.log('will manually call complete()');
 *   // some logic to call self.complete() later
 *   // or call complete() from outside to make a trigger waiter
 *   return 1; // or whatever you want but undefined
 * }
 *
 * @param {Function} run function to be called on run
 * @param {Function} complete function to be called on complete
 * @param {Function} recover function to be called on recover
 */
var Task = function () {
  /**
   * Task constructor
   *
   * @param {Function} run function to be called on run
   * @param {Function} complete function to be called on complete
   * @param {Function} recover function to be called on recover
   */
  function Task(run, complete, recover) {
    _classCallCheck(this, Task);

    this._run = run;
    this._complete = complete;
    this._recover = recover;

    this._running = false;
    this._done = false;

    this._attached = {};

    this._exceptions = {
      run: undefined,
      complete: undefined,
      recover: undefined
    };
  }

  /**
   * Attaches variable to the task
   *
   * @param {string} key accessor for the variable
   * @param {any} value variable value
   */


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

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

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

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

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

    /**
     * Runs a task
     *
     * Executes the run function if defined. All arguments will be
     * passed to it.
     *
     * @param {any} args any arguments
     */

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

      if (this._run !== undefined) {
        try {
          for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }

          if (this._run.apply(this, [this].concat(args)) === undefined) {
            this.complete();
          }
        } catch (error) {
          this._exceptions.run = error;

          this.complete(error);
        }
      } else {
        this.complete();
      }
    }

    /**
     * Completes a task
     *
     * Executes the complete function if defined. All arguments will be
     * passed to it.
     *
     * @param {any} args any arguments
     */

  }, {
    key: "complete",
    value: function complete() {
      this._running = false;
      this._done = true;

      if (this._complete !== undefined) {
        try {
          for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
            args[_key2] = arguments[_key2];
          }

          this._complete.apply(this, [this].concat(args));
        } catch (error) {
          this._exceptions.complete = error;
        }
      }
    }

    /**
     * Recovers a task
     *
     * Executes the recover function if defined. All arguments will be
     * passed to it.
     *
     * @param {any} args any arguments
     */

  }, {
    key: "recover",
    value: function recover() {
      if (this._recover !== undefined) {
        try {
          for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
            args[_key3] = arguments[_key3];
          }

          var recovered = this._recover.apply(this, [this].concat(args));
          if (recovered !== undefined) {
            this.run(recovered);
          }
        } catch (error) {
          this._exceptions.recover = error;
        }
      }
    }

    /**
     * Stops a task
     *
     * @return {boolean} success
     */

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

    /**
     * Restarts a task
     *
     * If stopped will start it
     * If running will respect stop()
     *
     * @return {boolean} success
     */

  }, {
    key: "restart",
    value: function restart() {
      if (this.running) {
        if (this.stop()) {
          this.run.apply(this, arguments);

          return true;
        } else {
          return false;
        }
      } else {
        this.run.apply(this, arguments);

        return true;
      }
    }

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

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

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

  }, {
    key: "done",
    get: function get() {
      return this._done;
    }

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

  }, {
    key: "failed",
    get: function get() {
      return this._exceptions.run !== undefined || this._exceptions.complete !== undefined || this._exceptions.recover !== undefined;
    }

    /**
     * Gets the exceptions if any
     *
     * @return {Object} exceptions
     */

  }, {
    key: "exceptions",
    get: function get() {
      return this._exceptions;
    }
  }]);

  return Task;
}();

exports.default = Task;