'use strict' var url = require('url') var NotFoundError = require('./error').NotFound var RouteNode = require('./route-node') var utils = require('./utils') var assign = utils.assign var isArray = utils.isArray var isFunction = utils.isFunction var isString = utils.isString var noop = utils.noop function Router(options) { options = options || {} this.routes = new RouteNode() } assign(Router.prototype, { add: function add(path, handler) { return this.routes.add(this._uriToParts(path), handler) }, route: function route(path, options, done) { if (done == null && isFunction(options)) { done = options options = {} } options = options || {} var routeArray = this._uriToParts(path) done = done || noop function _routeCallback(err, func, context, args) { if (err) { return done(err) } else { if (isFunction(func)) { return done(null, func.apply(context, args)) } else { return done(new NotFoundError('not found', {location: path})) } } } return this.routes.get(routeArray, (options.args || []), _routeCallback) }, _uriToParts: function _uriToParts(uri) { if (isString(uri)) { return url.parse(uri) .pathname .split('/') .filter(function (str) { return str !== ''}) } else if (isArray(uri)) { return uri.reduce(this._uriToPartsReducer.bind(this), []) } }, _uriToPartsReducer: function _uriToPartsReducer(memo, item) { if (isArray(item)) { return memo.concat(item) } else if (isString(item)) { return memo.concat(this._uriToParts(item)) } else { return memo.concat(item) } } }) Router.isNotFound = function isNotFound(err) { return err instanceof NotFoundError } module.exports = Router