(function () {

/* Imports */
var Meteor = Package.meteor.Meteor;
var _ = Package.underscore._;

/* Package-scope variables */
var RoutePolicyTest, RoutePolicy;

(function(){

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                             //
// packages/routepolicy/routepolicy.js                                                                         //
//                                                                                                             //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                               //
// In addition to listing specific files to be cached, the browser                                             // 1
// application cache manifest allows URLs to be designated as NETWORK                                          // 2
// (always fetched from the Internet) and FALLBACK (which we use to                                            // 3
// serve app HTML on arbitrary URLs).                                                                          // 4
//                                                                                                             // 5
// The limitation of the manifest file format is that the designations                                         // 6
// are by prefix only: if "/foo" is declared NETWORK then "/foobar"                                            // 7
// will also be treated as a network route.                                                                    // 8
//                                                                                                             // 9
// RoutePolicy is a low-level API for declaring the route type of URL prefixes:                                // 10
//                                                                                                             // 11
// "network": for network routes that should not conflict with static                                          // 12
// resources.  (For example, if "/sockjs/" is a network route, we                                              // 13
// shouldn't have "/sockjs/red-sock.jpg" as a static resource).                                                // 14
//                                                                                                             // 15
// "static-online": for static resources which should not be cached in                                         // 16
// the app cache.  This is implemented by also adding them to the                                              // 17
// NETWORK section (as otherwise the browser would receive app HTML                                            // 18
// for them because of the FALLBACK section), but static-online routes                                         // 19
// don't need to be checked for conflict with static resources.                                                // 20
                                                                                                               // 21
// The route policy is a singleton in a running application, but we                                            // 22
// can't unit test the real singleton because messing with the real                                            // 23
// routes would break tinytest... so allow policy instances to be                                              // 24
// constructed for testing.                                                                                    // 25
                                                                                                               // 26
RoutePolicyTest = {};                                                                                          // 27
                                                                                                               // 28
var RoutePolicyConstructor = RoutePolicyTest.Constructor = function () {                                       // 29
  var self = this;                                                                                             // 30
  self.urlPrefixTypes = {};                                                                                    // 31
};                                                                                                             // 32
                                                                                                               // 33
_.extend(RoutePolicyConstructor.prototype, {                                                                   // 34
                                                                                                               // 35
  urlPrefixMatches: function (urlPrefix, url) {                                                                // 36
    return url.substr(0, urlPrefix.length) === urlPrefix;                                                      // 37
  },                                                                                                           // 38
                                                                                                               // 39
  checkType: function (type) {                                                                                 // 40
    if (! _.contains(['network', 'static-online'], type))                                                      // 41
      return 'the route type must be "network" or "static-online"';                                            // 42
    return null;                                                                                               // 43
  },                                                                                                           // 44
                                                                                                               // 45
  checkUrlPrefix: function (urlPrefix, type) {                                                                 // 46
    var self = this;                                                                                           // 47
                                                                                                               // 48
    if (urlPrefix.charAt(0) !== '/')                                                                           // 49
      return 'a route URL prefix must begin with a slash';                                                     // 50
                                                                                                               // 51
    if (urlPrefix === '/')                                                                                     // 52
      return 'a route URL prefix cannot be /';                                                                 // 53
                                                                                                               // 54
    var existingType = self.urlPrefixTypes[urlPrefix];                                                         // 55
    if (existingType && existingType !== type)                                                                 // 56
      return 'the route URL prefix ' + urlPrefix + ' has already been declared to be of type ' + existingType;
                                                                                                               // 58
    return null;                                                                                               // 59
  },                                                                                                           // 60
                                                                                                               // 61
  checkForConflictWithStatic: function (urlPrefix, type, _testManifest) {                                      // 62
    var self = this;                                                                                           // 63
    if (type === 'static-online')                                                                              // 64
      return null;                                                                                             // 65
    if (!Package.webapp || !Package.webapp.WebApp                                                              // 66
        || !Package.webapp.WebApp.clientPrograms                                                               // 67
        || !Package.webapp.WebApp.clientPrograms[Package.webapp.WebApp.defaultArch].manifest) {                // 68
      // Hack: If we don't have a manifest, deal with it                                                       // 69
      // gracefully. This lets us load livedata into a nodejs                                                  // 70
      // environment that doesn't have a HTTP server (eg, a                                                    // 71
      // command-line tool).                                                                                   // 72
      return null;                                                                                             // 73
    }                                                                                                          // 74
    var manifest = _testManifest ||                                                                            // 75
      Package.webapp.WebApp.clientPrograms[Package.webapp.WebApp.defaultArch].manifest;                        // 76
    var conflict = _.find(manifest, function (resource) {                                                      // 77
      return (resource.type === 'static' &&                                                                    // 78
              resource.where === 'client' &&                                                                   // 79
              self.urlPrefixMatches(urlPrefix, resource.url));                                                 // 80
    });                                                                                                        // 81
    if (conflict)                                                                                              // 82
      return ('static resource ' + conflict.url + ' conflicts with ' +                                         // 83
              type + ' route ' + urlPrefix);                                                                   // 84
    else                                                                                                       // 85
      return null;                                                                                             // 86
  },                                                                                                           // 87
                                                                                                               // 88
  declare: function (urlPrefix, type) {                                                                        // 89
    var self = this;                                                                                           // 90
    var problem = self.checkType(type) ||                                                                      // 91
                  self.checkUrlPrefix(urlPrefix, type) ||                                                      // 92
                  self.checkForConflictWithStatic(urlPrefix, type);                                            // 93
    if (problem)                                                                                               // 94
      throw new Error(problem);                                                                                // 95
    // TODO overlapping prefixes, e.g. /foo/ and /foo/bar/                                                     // 96
    self.urlPrefixTypes[urlPrefix] = type;                                                                     // 97
  },                                                                                                           // 98
                                                                                                               // 99
  isValidUrl: function (url) {                                                                                 // 100
    return url.charAt(0) === '/';                                                                              // 101
  },                                                                                                           // 102
                                                                                                               // 103
  classify: function (url) {                                                                                   // 104
    var self = this;                                                                                           // 105
    if (url.charAt(0) !== '/')                                                                                 // 106
      throw new Error('url must be a relative URL: ' + url);                                                   // 107
    var prefix = _.find(_.keys(self.urlPrefixTypes), function (_prefix) {                                      // 108
      return self.urlPrefixMatches(_prefix, url);                                                              // 109
    });                                                                                                        // 110
    if (prefix)                                                                                                // 111
      return self.urlPrefixTypes[prefix];                                                                      // 112
    else                                                                                                       // 113
      return null;                                                                                             // 114
  },                                                                                                           // 115
                                                                                                               // 116
  urlPrefixesFor: function (type) {                                                                            // 117
    var self = this;                                                                                           // 118
    var prefixes = [];                                                                                         // 119
    _.each(self.urlPrefixTypes, function (_type, _prefix) {                                                    // 120
      if (_type === type)                                                                                      // 121
        prefixes.push(_prefix);                                                                                // 122
    });                                                                                                        // 123
    return prefixes.sort();                                                                                    // 124
  }                                                                                                            // 125
});                                                                                                            // 126
                                                                                                               // 127
RoutePolicy = new RoutePolicyConstructor();                                                                    // 128
                                                                                                               // 129
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);


/* Exports */
if (typeof Package === 'undefined') Package = {};
Package.routepolicy = {
  RoutePolicy: RoutePolicy,
  RoutePolicyTest: RoutePolicyTest
};

})();

//# sourceMappingURL=routepolicy.js.map
