(function () {

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

/* Package-scope variables */
var OrderedDict;

(function(){

///////////////////////////////////////////////////////////////////////////////////
//                                                                               //
// packages/ordered-dict/ordered_dict.js                                         //
//                                                                               //
///////////////////////////////////////////////////////////////////////////////////
                                                                                 //
// This file defines an ordered dictionary abstraction that is useful for        // 1
// maintaining a dataset backed by observeChanges.  It supports ordering items   // 2
// by specifying the item they now come before.                                  // 3
                                                                                 // 4
// The implementation is a dictionary that contains nodes of a doubly-linked     // 5
// list as its values.                                                           // 6
                                                                                 // 7
// constructs a new element struct                                               // 8
// next and prev are whole elements, not keys.                                   // 9
var element = function (key, value, next, prev) {                                // 10
  return {                                                                       // 11
    key: key,                                                                    // 12
    value: value,                                                                // 13
    next: next,                                                                  // 14
    prev: prev                                                                   // 15
  };                                                                             // 16
};                                                                               // 17
OrderedDict = function (/* ... */) {                                             // 18
  var self = this;                                                               // 19
  self._dict = {};                                                               // 20
  self._first = null;                                                            // 21
  self._last = null;                                                             // 22
  self._size = 0;                                                                // 23
  var args = _.toArray(arguments);                                               // 24
  self._stringify = function (x) { return x; };                                  // 25
  if (typeof args[0] === 'function')                                             // 26
    self._stringify = args.shift();                                              // 27
  _.each(args, function (kv) {                                                   // 28
    self.putBefore(kv[0], kv[1], null);                                          // 29
  });                                                                            // 30
};                                                                               // 31
                                                                                 // 32
_.extend(OrderedDict.prototype, {                                                // 33
  // the "prefix keys with a space" thing comes from here                        // 34
  // https://github.com/documentcloud/underscore/issues/376#issuecomment-2815649
  _k: function (key) { return " " + this._stringify(key); },                     // 36
                                                                                 // 37
  empty: function () {                                                           // 38
    var self = this;                                                             // 39
    return !self._first;                                                         // 40
  },                                                                             // 41
  size: function () {                                                            // 42
    var self = this;                                                             // 43
    return self._size;                                                           // 44
  },                                                                             // 45
  _linkEltIn: function (elt) {                                                   // 46
    var self = this;                                                             // 47
    if (!elt.next) {                                                             // 48
      elt.prev = self._last;                                                     // 49
      if (self._last)                                                            // 50
        self._last.next = elt;                                                   // 51
      self._last = elt;                                                          // 52
    } else {                                                                     // 53
      elt.prev = elt.next.prev;                                                  // 54
      elt.next.prev = elt;                                                       // 55
      if (elt.prev)                                                              // 56
        elt.prev.next = elt;                                                     // 57
    }                                                                            // 58
    if (self._first === null || self._first === elt.next)                        // 59
      self._first = elt;                                                         // 60
  },                                                                             // 61
  _linkEltOut: function (elt) {                                                  // 62
    var self = this;                                                             // 63
    if (elt.next)                                                                // 64
      elt.next.prev = elt.prev;                                                  // 65
    if (elt.prev)                                                                // 66
      elt.prev.next = elt.next;                                                  // 67
    if (elt === self._last)                                                      // 68
      self._last = elt.prev;                                                     // 69
    if (elt === self._first)                                                     // 70
      self._first = elt.next;                                                    // 71
  },                                                                             // 72
  putBefore: function (key, item, before) {                                      // 73
    var self = this;                                                             // 74
    if (self._dict[self._k(key)])                                                // 75
      throw new Error("Item " + key + " already present in OrderedDict");        // 76
    var elt = before ?                                                           // 77
          element(key, item, self._dict[self._k(before)]) :                      // 78
          element(key, item, null);                                              // 79
    if (elt.next === undefined)                                                  // 80
      throw new Error("could not find item to put this one before");             // 81
    self._linkEltIn(elt);                                                        // 82
    self._dict[self._k(key)] = elt;                                              // 83
    self._size++;                                                                // 84
  },                                                                             // 85
  append: function (key, item) {                                                 // 86
    var self = this;                                                             // 87
    self.putBefore(key, item, null);                                             // 88
  },                                                                             // 89
  remove: function (key) {                                                       // 90
    var self = this;                                                             // 91
    var elt = self._dict[self._k(key)];                                          // 92
    if (elt === undefined)                                                       // 93
      throw new Error("Item " + key + " not present in OrderedDict");            // 94
    self._linkEltOut(elt);                                                       // 95
    self._size--;                                                                // 96
    delete self._dict[self._k(key)];                                             // 97
    return elt.value;                                                            // 98
  },                                                                             // 99
  get: function (key) {                                                          // 100
    var self = this;                                                             // 101
    if (self.has(key))                                                           // 102
        return self._dict[self._k(key)].value;                                   // 103
    return undefined;                                                            // 104
  },                                                                             // 105
  has: function (key) {                                                          // 106
    var self = this;                                                             // 107
    return _.has(self._dict, self._k(key));                                      // 108
  },                                                                             // 109
  // Iterate through the items in this dictionary in order, calling              // 110
  // iter(value, key, index) on each one.                                        // 111
                                                                                 // 112
  // Stops whenever iter returns OrderedDict.BREAK, or after the last element.   // 113
  forEach: function (iter) {                                                     // 114
    var self = this;                                                             // 115
    var i = 0;                                                                   // 116
    var elt = self._first;                                                       // 117
    while (elt !== null) {                                                       // 118
      var b = iter(elt.value, elt.key, i);                                       // 119
      if (b === OrderedDict.BREAK)                                               // 120
        return;                                                                  // 121
      elt = elt.next;                                                            // 122
      i++;                                                                       // 123
    }                                                                            // 124
  },                                                                             // 125
  first: function () {                                                           // 126
    var self = this;                                                             // 127
    if (self.empty())                                                            // 128
      return undefined;                                                          // 129
    return self._first.key;                                                      // 130
  },                                                                             // 131
  firstValue: function () {                                                      // 132
    var self = this;                                                             // 133
    if (self.empty())                                                            // 134
      return undefined;                                                          // 135
    return self._first.value;                                                    // 136
  },                                                                             // 137
  last: function () {                                                            // 138
    var self = this;                                                             // 139
    if (self.empty())                                                            // 140
      return undefined;                                                          // 141
    return self._last.key;                                                       // 142
  },                                                                             // 143
  lastValue: function () {                                                       // 144
    var self = this;                                                             // 145
    if (self.empty())                                                            // 146
      return undefined;                                                          // 147
    return self._last.value;                                                     // 148
  },                                                                             // 149
  prev: function (key) {                                                         // 150
    var self = this;                                                             // 151
    if (self.has(key)) {                                                         // 152
      var elt = self._dict[self._k(key)];                                        // 153
      if (elt.prev)                                                              // 154
        return elt.prev.key;                                                     // 155
    }                                                                            // 156
    return null;                                                                 // 157
  },                                                                             // 158
  next: function (key) {                                                         // 159
    var self = this;                                                             // 160
    if (self.has(key)) {                                                         // 161
      var elt = self._dict[self._k(key)];                                        // 162
      if (elt.next)                                                              // 163
        return elt.next.key;                                                     // 164
    }                                                                            // 165
    return null;                                                                 // 166
  },                                                                             // 167
  moveBefore: function (key, before) {                                           // 168
    var self = this;                                                             // 169
    var elt = self._dict[self._k(key)];                                          // 170
    var eltBefore = before ? self._dict[self._k(before)] : null;                 // 171
    if (elt === undefined)                                                       // 172
      throw new Error("Item to move is not present");                            // 173
    if (eltBefore === undefined) {                                               // 174
      throw new Error("Could not find element to move this one before");         // 175
    }                                                                            // 176
    if (eltBefore === elt.next) // no moving necessary                           // 177
      return;                                                                    // 178
    // remove from its old place                                                 // 179
    self._linkEltOut(elt);                                                       // 180
    // patch into its new place                                                  // 181
    elt.next = eltBefore;                                                        // 182
    self._linkEltIn(elt);                                                        // 183
  },                                                                             // 184
  // Linear, sadly.                                                              // 185
  indexOf: function (key) {                                                      // 186
    var self = this;                                                             // 187
    var ret = null;                                                              // 188
    self.forEach(function (v, k, i) {                                            // 189
      if (self._k(k) === self._k(key)) {                                         // 190
        ret = i;                                                                 // 191
        return OrderedDict.BREAK;                                                // 192
      }                                                                          // 193
      return undefined;                                                          // 194
    });                                                                          // 195
    return ret;                                                                  // 196
  },                                                                             // 197
  _checkRep: function () {                                                       // 198
    var self = this;                                                             // 199
    _.each(self._dict, function (k, v) {                                         // 200
      if (v.next === v)                                                          // 201
        throw new Error("Next is a loop");                                       // 202
      if (v.prev === v)                                                          // 203
        throw new Error("Prev is a loop");                                       // 204
    });                                                                          // 205
  }                                                                              // 206
                                                                                 // 207
});                                                                              // 208
OrderedDict.BREAK = {"break": true};                                             // 209
                                                                                 // 210
///////////////////////////////////////////////////////////////////////////////////

}).call(this);


/* Exports */
if (typeof Package === 'undefined') Package = {};
Package['ordered-dict'] = {
  OrderedDict: OrderedDict
};

})();

//# sourceMappingURL=ordered-dict.js.map
