'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 _Launcher = require('../types/Launcher');

var _Launcher2 = _interopRequireDefault(_Launcher);

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

/**
 * Injector
 *
 * Contains inject and cleanup methods
 *
 * @static
 */
var Injector = function () {
  function Injector() {
    _classCallCheck(this, Injector);
  }

  _createClass(Injector, null, [{
    key: 'injectBefore',


    /**
     * Inject before
     *
     * @param {Function} method original method or launch method
     * @param {Function} inject inject method
     * @return {Function} launch launch method
     * @static
     */


    /**
     * Predefined inject after
     *
     * @param {int} INJECT_AFTER predefined value
     * @static
     */
    value: function injectBefore(method, inject) {
      return Injector.inject(method, inject, Injector.INJECT_BEFORE);
    }

    /**
     * Inject after
     *
     * @param {Function} method original method or launch method
     * @param {Function} inject inject method
     * @return {Function} launch launch method
     * @static
     */


    /**
     * All launchers
     *
     * @param {Array<Launcher>} _launchers all launchers
     * @static
     * @private
     */

    /**
     * Predefined inject before
     *
     * @param {int} INJECT_BEFORE predefined value
     * @static
     */

  }, {
    key: 'injectAfter',
    value: function injectAfter(method, inject) {
      return Injector.inject(method, inject, Injector.INJECT_AFTER);
    }

    /**
     * Inject before or after
     *
     * @param {Function} method original method or launch method
     * @param {Function} inject inject method
     * @param {int} beforeOrAfter 0 - before, 1 - is after
     * @return {Function} launch launch method
     * @static
     */

  }, {
    key: 'inject',
    value: function inject(method, _inject) {
      var beforeOrAfter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;

      var launcher = Injector._toLauncher(method);
      var collection = beforeOrAfter === Injector.INJECT_BEFORE ? launcher.before : beforeOrAfter === Injector.INJECT_AFTER ? launcher.after : [];
      collection.push(_inject);
      return launcher.launch;
    }

    /**
     * Remove injection
     *
     * @param {Function} launch method
     * @param {Function} inject inject method
     * @return {Function} launch launch method
     * @static
     */

  }, {
    key: 'remove',
    value: function remove(method, _remove) {
      var launcher = Injector._toLauncher(method);
      if (launcher.before.indexOf(_remove) !== -1) {
        launcher.before.splice(launcher.before.indexOf(_remove), 1);
      } else if (launcher.after.indexOf(_remove) !== -1) {
        launcher.after.splice(launcher.after.indexOf(_remove), 1);
      }
      return method;
    }

    /**
     * Resets launch and all injections
     *
     * @param {Function} launch launch method
     * @return {Function} original original method
     * @static
     */

  }, {
    key: 'reset',
    value: function reset(method) {
      var launcher = Injector._locate(method);
      if (launcher !== undefined) {
        Injector._launchers.splice(Injector._launchers.indexOf(launcher), 1);
        return launcher.original;
      } else {
        return method;
      }
    }

    /**
     * Converts original to launch
     *
     * @param {Function} method original method or launch method
     * @return {Launcher} launcher launcher
     * @static
     * @protected
     */

  }, {
    key: '_toLauncher',
    value: function _toLauncher(method) {
      var located = Injector._locate(method);
      if (located === undefined) {
        var launcher = new _Launcher2.default(method);
        Injector._launchers.push(launcher);
        return launcher;
      } else {
        return located;
      }
    }

    /**
     * Locates launcher by launch method
     *
     * @param {Function} method launch method
     * @return {Launcher} launcher launcher
     * @static
     * @protected
     */

  }, {
    key: '_locate',
    value: function _locate(method) {
      var launchers = Injector._launchers;
      var length = launchers.length;
      var located = undefined;
      for (var i = 0; i < length; ++i) {
        if (launchers[i].launch === method) {
          located = launchers[i];
          break;
        }
      }
      return located;
    }
  }]);

  return Injector;
}();

Injector.INJECT_BEFORE = 0;
Injector.INJECT_AFTER = 1;
Injector._launchers = [];
exports.default = Injector;