1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file.
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
5ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/**
62385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch * Model for the folder shortcuts. This object is cr.ui.ArrayDataModel-like
72385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch * object with additional methods for the folder shortcut feature.
82385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch * This uses chrome.storage as backend. Items are always sorted by file path.
9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * @constructor
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * @extends {cr.EventTarget}
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */
132385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdochfunction FolderShortcutsDataModel() {
14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  this.array_ = [];
15ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  /**
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)   * Eliminate unsupported folders from the list.
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)   *
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)   * @param {Array.<string>} array Folder array which may contain the
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)   *     unsupported folders.
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)   * @return {Array.<string>} Folder list without unsupported folder.
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)   */
23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  var filter = function(array) {
24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return array.filter(PathUtil.isEligibleForFolderShortcut);
25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  };
26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Loads the contents from the storage to initialize the array.
282385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  chrome.storage.sync.get(FolderShortcutsDataModel.NAME, function(value) {
292385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!(FolderShortcutsDataModel.NAME in value))
30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return;
31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
32ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Since the value comes from outer resource, we have to check it just in
33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // case.
342385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var list = value[FolderShortcutsDataModel.NAME];
35ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (list instanceof Array) {
36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      list = filter(list);
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
382385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      var permutation = this.calculatePermitation_(this.array_, list);
39ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      this.array_ = list;
402385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      this.firePermutedEvent_(permutation);
41ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
42ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }.bind(this));
43ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Listening for changes in the storage.
45ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  chrome.storage.onChanged.addListener(function(changes, namespace) {
462385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (!(FolderShortcutsDataModel.NAME in changes) || namespace != 'sync')
47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return;
48ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
492385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var list = changes[FolderShortcutsDataModel.NAME].newValue;
50ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Since the value comes from outer resource, we have to check it just in
51ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // case.
52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (list instanceof Array) {
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      list = filter(list);
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
55558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      // If the list is not changed, do nothing and just return.
56558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      if (this.array_.length == list.length) {
57558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        var changed = false;
58558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        for (var i = 0; i < this.array_.length; i++) {
594311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch          // Same item check: must be exact match.
60558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          if (this.array_[i] != list[i]) {
61558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            changed = true;
62558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            break;
63558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          }
64558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        }
65558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        if (!changed)
66558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          return;
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      }
68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
692385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      var permutation = this.calculatePermitation_(this.array_, list);
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      this.array_ = list;
712385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      this.firePermutedEvent_(permutation);
72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
73ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }.bind(this));
74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
762385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch/**
772385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch * Key name in chrome.storage. The array are stored with this name.
782385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch * @type {string}
792385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch * @const
802385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch */
812385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen MurdochFolderShortcutsDataModel.NAME = 'folder-shortcuts-list';
822385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
832385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen MurdochFolderShortcutsDataModel.prototype = {
84ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  __proto__: cr.EventTarget.prototype,
85ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
86ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
87ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @return {number} Number of elements in the array.
88ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
89ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  get length() {
90ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return this.array_.length;
91ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  },
92ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
93ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
94ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @param {number} index Index of the element to be retrieved.
95ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @return {string} The value of the |index|-th element.
96ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
972385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  item: function(index) {
98ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return this.array_[index];
99ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  },
100ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @param {string} value Value of the element to be retrieved.
103ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @return {number} Index of the element with the specified |value|.
104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
105ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  getIndex: function(value) {
106ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    for (var i = 0; i < this.length; i++) {
1074311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      // Same item check: must be exact match.
1084311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      if (this.array_[i] == value) {
109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        return i;
110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return -1;
113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  },
114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
1164311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   * Compares 2 strings and returns a number indicating one string comes before
1174311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   * or after or is the same as the other string in sort order.
1184311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   *
1194311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   * @param {string} a String1.
1204311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   * @param {string} b String2.
1214311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   * @return {boolean} Return -1, if String1 < String2. Return 0, if String1 ==
1224311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   *     String2. Otherwise, return 1.
1234311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch   */
1244311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  compare: function(a, b) {
1254311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    return a.localeCompare(b,
1264311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch                           undefined,  // locale parameter, use default locale.
1274311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch                           {usage: 'sort', numeric: true});
1284311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  },
1294311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
1304311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  /**
1312385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * Adds the given item to the array. If there were already same item in the
1322385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * list, return the index of the existing item without adding a duplicate
1332385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * item.
1342385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   *
135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @param {string} value Value to be added into the array.
136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @return {number} Index in the list which the element added to.
137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  add: function(value) {
1392385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var oldArray = this.array_.slice(0);  // Shallow copy.
1402385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var addedIndex = -1;
1412385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    for (var i = 0; i < this.length; i++) {
1424311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      // Same item check: must be exact match.
1434311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      if (this.array_[i] == value)
144ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        return i;
1454311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
1464311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      // Since the array is sorted, new item will be added just before the first
1474311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      // larger item.
1484311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      if (this.compare(this.array_[i], value) >= 0) {
149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        this.array_.splice(i, 0, value);
1502385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        addedIndex = i;
151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
153ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
154ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // If value is not added yet, add it at the last.
1552385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (addedIndex == -1) {
156ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      this.array_.push(value);
1572385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      addedIndex = this.length;
1582385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    }
1592385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
1602385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    this.firePermutedEvent_(
1612385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        this.calculatePermitation_(oldArray, this.array_));
162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    this.save_();
1632385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return addedIndex;
164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  },
165ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * Removes the given item from the array.
168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @param {string} value Value to be removed from the array.
169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @return {number} Index in the list which the element removed from.
170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  remove: function(value) {
1722385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var removedIndex = -1;
1732385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var oldArray = this.array_.slice(0);  // Shallow copy.
1742385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    for (var i = 0; i < this.length; i++) {
1754311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      // Same item check: must be exact match.
176ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (this.array_[i] == value) {
177ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        this.array_.splice(i, 1);
1782385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        removedIndex = i;
179ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
180ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
181ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1822385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
1832385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    if (removedIndex != -1) {
1842385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      this.firePermutedEvent_(
1852385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          this.calculatePermitation_(oldArray, this.array_));
1862385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      this.save_();
1872385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      return removedIndex;
1882385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    }
1892385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
1902385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    // No item is removed.
1912385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return -1;
1922385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  },
1932385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
1942385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  /**
1952385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * @param {string} path Path to be checked.
1962385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * @return {boolean} True if the given |path| exists in the array. False
1972385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   *     otherwise.
1982385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   */
1992385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  exists: function(path) {
2002385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var index = this.getIndex(path);
2012385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return (index >= 0);
202ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  },
203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * Saves the current array to chrome.storage.
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @private
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  save_: function() {
209ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    var obj = {};
2102385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    obj[FolderShortcutsDataModel.NAME] = this.array_;
2112385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    chrome.storage.sync.set(obj, function() {});
212ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  },
213ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
214ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
2152385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * Creates a permutation array for 'permuted' event, which is compatible with
216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * a parmutation array used in cr/ui/array_data_model.js.
217ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   *
218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @param {array} oldArray Previous array before changing.
219ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @param {array} newArray New array after changing.
220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @return {Array.<number>} Created permutation array.
221ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * @private
222ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
2232385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  calculatePermitation_: function(oldArray, newArray) {
224ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    var oldIndex = 0;  // Index of oldArray.
225ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    var newIndex = 0;  // Index of newArray.
226ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
227ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Note that both new and old arrays are sorted.
228ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    var permutation = [];
229ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    for (; oldIndex < oldArray.length; oldIndex++) {
230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (newIndex >= newArray.length) {
231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        // oldArray[oldIndex] is deleted, which is not in the new array.
232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        permutation[oldIndex] = -1;
233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        continue;
234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
235ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
236ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      while (newIndex < newArray.length) {
2374311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        // Unchanged item, which exists in both new and old array. But the
2384311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        // index may be changed.
239ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        if (oldArray[oldIndex] == newArray[newIndex]) {
240ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          permutation[oldIndex] = newIndex;
241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          newIndex++;
242ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          break;
2434311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        }
2444311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
2454311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        // oldArray[oldIndex] is deleted, which is not in the new array.
2464311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        if (this.compare(oldArray[oldIndex], newArray[newIndex]) < 0) {
247ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          permutation[oldIndex] = -1;
248ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          break;
249ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        }
2504311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
2514311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        // In the case of this.compare(oldArray[oldIndex]) > 0:
2524311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        // newArray[newIndex] is added, which is not in the old array.
2534311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        newIndex++;
254ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
255ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
256ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return permutation;
257ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  },
258ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
259ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /**
2602385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * Fires a 'permuted' event, which is compatible with cr.ui.ArrayDataModel.
2612385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch   * @param {Array.<number>} Permutation array.
262ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   */
2632385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  firePermutedEvent_: function(permutation) {
264ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    var permutedEvent = new Event('permuted');
265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    permutedEvent.newLength = this.length;
266ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    permutedEvent.permutation = permutation;
267ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    this.dispatchEvent(permutedEvent);
268ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2692385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    // Note: This model only fires 'permuted' event, because:
270558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // 1) 'change' event is not necessary to fire since it is covered by
271558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    //    'permuted' event.
2722385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    // 2) 'splice' and 'sorted' events are not implemented. These events are
2733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    //    not used in NavigationListModel. We have to implement them when
2743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    //    necessary.
275ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
276ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch};
277