text: 'use strict';
  
  var _ = require('underscore');
  
  /*global _: false*/
  module.exports = function(AV) {
    /**
     * Routers map faux-URLs to actions, and fire events when routes are
     * matched. Creating a new one sets its `routes` hash, if not set statically.
     * @class
     *
     * <p>A fork of Backbone.Router, provided for your convenience.
     * For more information, see the
     * <a href="http://documentcloud.github.com/backbone/#Router">Backbone
     * documentation</a>.</p>
     * <p><strong><em>Available in the client SDK only.</em></strong></p>
     */
    AV.Router = function(options) {
      console.warn("AV.Router is deprecated, please don't use it anymore.");
      options = options || {};
      if (options.routes) {
        this.routes = options.routes;
      }
      this._bindRoutes();
      this.initialize.apply(this, arguments);
    };
  
    // Cached regular expressions for matching named param parts and splatted
    // parts of route strings.
    var namedParam    = /:\w+/g;
    var splatParam    = /\*\w+/g;
    var escapeRegExp  = /[\-\[\]{}()+?.,\\\^\$\|#\s]/g;
  
    // Set up all inheritable **AV.Router** properties and methods.
    _.extend(AV.Router.prototype, AV.Events,
             /** @lends AV.Router.prototype */ {
  
      /**
       * Initialize is an empty function by default. Override it with your own
       * initialization logic.
       */
      initialize: function(){},
  
      /**
       * Manually bind a single named route to a callback. For example:
       *
       * <pre>this.route('search/:query/p:num', 'search', function(query, num) {
       *       ...
       *     });</pre>
       */
      route: function(route, name, callback) {
        AV.history = AV.history || new AV.History();
        if (!_.isRegExp(route)) {
          route = this._routeToRegExp(route);
        }
        if (!callback) {
          callback = this[name];
        }
        AV.history.route(route, _.bind(function(fragment) {
          var args = this._extractParameters(route, fragment);
          if (callback) {
            callback.apply(this, args);
          }
          this.trigger.apply(this, ['route:' + name].concat(args));
          AV.history.trigger('route', this, name, args);
        }, this));
        return this;
      },
  
      /**
       * Whenever you reach a point in your application that you'd
       * like to save as a URL, call navigate in order to update the
       * URL. If you wish to also call the route function, set the
       * trigger option to true. To update the URL without creating
       * an entry in the browser's history, set the replace option
       * to true.
       */
      navigate: function(fragment, options) {
        AV.history.navigate(fragment, options);
      },
  
      // Bind all defined routes to `AV.history`. We have to reverse the
      // order of the routes here to support behavior where the most general
      // routes can be defined at the bottom of the route map.
      _bindRoutes: function() {
        if (!this.routes) {
          return;
        }
        var routes = [];
        for (var route in this.routes) {
          if (this.routes.hasOwnProperty(route)) {
            routes.unshift([route, this.routes[route]]);
          }
        }
        for (var i = 0, l = routes.length; i < l; i++) {
          this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
        }
      },
  
      // Convert a route string into a regular expression, suitable for matching
      // against the current location hash.
      _routeToRegExp: function(route) {
        route = route.replace(escapeRegExp, '\\$&')
                     .replace(namedParam, '([^\/]+)')
                     .replace(splatParam, '(.*?)');
        return new RegExp('^' + route + '$');
      },
  
      // Given a route, and a URL fragment that it matches, return the array of
      // extracted parameters.
      _extractParameters: function(route, fragment) {
        return route.exec(fragment).slice(1);
      }
    });
  
    /**
     * @function
     * @param {Object} instanceProps Instance properties for the router.
     * @param {Object} classProps Class properies for the router.
     * @return {Class} A new subclass of <code>AV.Router</code>.
     */
    AV.Router.extend = AV._extend;
  };
  