'use strict';

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

var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var _createClass = require('@babel/runtime/helpers/createClass');
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var utils = require('@teclone/utils');
var Wrapper = require('./Wrapper');
var nodeUtils = require('@teclone/node-utils');
var Constants = require('./Constants');
var Utils = require('./Utils');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var _classCallCheck__default = /*#__PURE__*/_interopDefaultLegacy(_classCallCheck);
var _createClass__default = /*#__PURE__*/_interopDefaultLegacy(_createClass);
var _defineProperty__default = /*#__PURE__*/_interopDefaultLegacy(_defineProperty);

function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
var Router = /*#__PURE__*/function () {
  /**
   *
   * @param inheritMiddlewares - boolean indicating if parent middlewares should be inherited, defaults to true.
   */
  function Router() {
    var inheritMiddlewares = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;

    _classCallCheck__default['default'](this, Router);

    _defineProperty__default['default'](this, "basePath", '');

    _defineProperty__default['default'](this, "routes", {
      options: [],
      head: [],
      get: [],
      post: [],
      put: [],
      "delete": []
    });

    _defineProperty__default['default'](this, "middlewares", []);

    _defineProperty__default['default'](this, "inheritMiddlewares", void 0);

    this.inheritMiddlewares = inheritMiddlewares;
  }
  /**
   * resolves the url route by joining it to the base path
   */


  _createClass__default['default'](Router, [{
    key: "resolveUrl",
    value: function resolveUrl(url) {
      url = nodeUtils.joinPaths(this.basePath, utils.stripSlashes(url));
      return url !== '.' ? url : '';
    }
    /**
     * resolves a route callback options
     */

  }, {
    key: "resolveCallbackOptions",
    value: function resolveCallbackOptions(options) {
      var resolvedOptions = null;

      if (utils.isCallable(options) || Array.isArray(options)) {
        resolvedOptions = {
          use: utils.makeArray(options)
        };
      } else if (utils.isObject(options)) {
        resolvedOptions = {
          use: utils.makeArray(options.use),
          options: options.options
        };
      }

      return resolvedOptions;
    }
    /**
     * resolves a use middleware options
     */

  }, {
    key: "resolveMiddlewareOptions",
    value: function resolveMiddlewareOptions() {
      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '*';
      var resolvedOptions = null;

      if (utils.isString(options) || Array.isArray(options)) {
        resolvedOptions = {
          method: Utils.getRouteKeys(options)
        };
      } else if (utils.isObject(options)) {
        resolvedOptions = {
          method: Utils.getRouteKeys(options.method || '*'),
          options: options.options
        };
      }

      return resolvedOptions;
    }
    /**
     * sets the route rule for a given http method
     *
     * @param method - the http method
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "set",
    value: function set(method, url, callback, options) {
      var routeId = Constants.assignRouteId();
      var resolvedOptions = this.resolveCallbackOptions(options);
      var resolvedUrl = this.resolveUrl(url);

      var _iterator = _createForOfIteratorHelper(Utils.getRouteKeys(method)),
          _step;

      try {
        for (_iterator.s(); !(_step = _iterator.n()).done;) {
          var routeKey = _step.value;
          this.routes[routeKey].push([routeId, resolvedUrl, callback, resolvedOptions]);
        }
      } catch (err) {
        _iterator.e(err);
      } finally {
        _iterator.f();
      }

      return routeId;
    }
    /**
     * returns the routes.
     */

  }, {
    key: "getRoutes",
    value: function getRoutes() {
      return this.routes;
    }
    /**
     * returns the middlewares
     */

  }, {
    key: "getMiddlewares",
    value: function getMiddlewares() {
      return this.middlewares;
    }
    /**
     * returns routing base path that gets prepended to all route and middleware urls
     */

  }, {
    key: "getBasePath",
    value: function getBasePath() {
      return this.basePath;
    }
    /**
     * sets routing base path that gets prepended to all route and middleware urls
     */

  }, {
    key: "setBasePath",
    value: function setBasePath(basePath) {
      this.basePath = utils.stripSlashes(basePath);
      return this;
    }
    /**
     * stores route rules for http OPTIONS method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "options",
    value: function options(url, callback, _options) {
      return this.set('options', url, callback, _options);
    }
    /**
     * stores route rules for http HEAD method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "head",
    value: function head(url, callback, options) {
      return this.set('head', url, callback, options);
    }
    /**
     * stores route rules for http GET method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "get",
    value: function get(url, callback, options) {
      return this.set('get', url, callback, options);
    }
    /**
     * stores route rules for http POST method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "post",
    value: function post(url, callback, options) {
      return this.set('post', url, callback, options);
    }
    /**
     * stores route rules for http PUT method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "put",
    value: function put(url, callback, options) {
      return this.set('put', url, callback, options);
    }
    /**
     * stores route rules for http DELETE method
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "delete",
    value: function _delete(url, callback, options) {
      return this.set('delete', url, callback, options);
    }
    /**
     * stores route rules for all http methods
     *
     * @param url - route url
     * @param callback - route callback handler
     * @param options - route configuration object or middleware or array of middlewares
     */

  }, {
    key: "any",
    value: function any(url, callback, options) {
      return this.set('*', url, callback, options);
    }
    /**
     * creates and returns a route wrapper for the given url
     */

  }, {
    key: "route",
    value: function route(url) {
      return new Wrapper.Wrapper(this, url);
    }
    /**
     * registers a middleware to be called whenever the given url is visited
     *
     * @param url - url to apply middleware to. use * to appy to all urls
     * @param middleware - the middleware or array of middlewares
     * @param options - middleware configuration option. here, you can specify the http method
     * that the middleware will run against
     *@returns {MiddlewareId} returns the middleware id, can be used to delete the middleware.
     */

  }, {
    key: "use",
    value: function use(url, middleware, options) {
      middleware = utils.makeArray(middleware);
      var resolvedOptions = this.resolveMiddlewareOptions(options);
      var middlewareId = Constants.assignMiddlewareId();
      this.middlewares.push([middlewareId, this.resolveUrl(url), middleware, resolvedOptions]);
      return middlewareId;
    }
    /**
     * sets or gets the inherit parent's middlewares flag.
     * @param status - if given, it sets this value
     */

  }, {
    key: "shouldInheritMiddlewares",
    value: function shouldInheritMiddlewares(status) {
      if (utils.isBoolean(status)) {
        this.inheritMiddlewares = status;
      }

      return this.inheritMiddlewares;
    }
    /**
     * removes a given route
     * @param id route id
     */

  }, {
    key: "removeRoute",
    value: function removeRoute(id) {
      var _this = this;

      var findIndex = function findIndex(routeInstance) {
        return routeInstance[0] === id;
      };

      var found = false;
      Constants.ROUTE_KEYS.forEach(function (key) {
        var route = _this.routes[key];
        var index = route.findIndex(findIndex);

        if (index !== -1) {
          route.splice(index, 1);
          found = true;
        }
      });
      return found;
    }
    /**
     * removes a given middleware. returns true if it succeeds, otherwise, it returns false
     * @param id middleware id
     */

  }, {
    key: "removeMiddleware",
    value: function removeMiddleware(id) {
      var findIndex = function findIndex(instance) {
        return instance[0] === id;
      };

      var middlewares = this.middlewares;
      var index = middlewares.findIndex(findIndex);

      if (index !== -1) {
        middlewares.splice(index, 1);
        return true;
      }

      return false;
    }
  }]);

  return Router;
}();

exports.Router = Router;
//# sourceMappingURL=Router.js.map
