text: /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
  /**
   * Attached clients are OAuth apps and devices
   *
   * It sorts items in order that is defined in FxA-89 feature description.
   */
  'use strict';
  
  const Backbone = require('backbone');
  const Constants = require('../lib/constants');
  const Device = require('./device');
  const OAuthApp = require('./oauth-app');
  const WebSession = require('./web-session');
  
  var AttachedClients = Backbone.Collection.extend({
    model: function(attrs, options) {
      if (attrs.clientType === Constants.CLIENT_TYPE_DEVICE) {
        return new Device(attrs, options);
      } else if (attrs.clientType === Constants.CLIENT_TYPE_OAUTH_APP) {
        return new OAuthApp(attrs, options);
      } else if (attrs.clientType === Constants.CLIENT_TYPE_WEB_SESSION) {
        return new WebSession(attrs, options);
      }
    },
  
    fetchClients (clientTypes = {}, user) {
      var account = user.getSignedInAccount();
      var fetchItems = [];
  
      if (clientTypes.devices) {
        fetchItems.push(user.fetchAccountDevices(account));
      }
  
      if (clientTypes.oAuthApps) {
        fetchItems.push(user.fetchAccountOAuthApps(account));
      }
  
      if (clientTypes.sessions) {
        fetchItems.push(user.fetchAccountSessions(account));
      }
  
      return Promise.all(fetchItems)
        .then((results) => {
          // need to reset and sync add the models,
          // Backbone cannot merge two simultaneous responses.
          this.reset();
          if (results) {
            results.forEach((items) => {
              this.add(items, {
                merge: true
              });
            });
          }
        });
    },
  
    comparator (a, b) {
      // 1. the current device is first.
      // 2. devices of the same type are grouped together as defined in clientOrder.
      // 3. those with lastAccessTime are sorted in descending order
      // 4. the rest sorted in alphabetical order.
      if (a.get('isCurrentDevice')) {
        return -1;
      }
      if (b.get('isCurrentDevice')) {
        return 1;
      }
  
      var clientOrder = {
        [Constants.CLIENT_TYPE_DEVICE]: 0,
        [Constants.CLIENT_TYPE_OAUTH_APP]: 1,
        [Constants.CLIENT_TYPE_WEB_SESSION]: 2
      };
  
      var aClientType = a.get('clientType');
      var bClientType = b.get('clientType');
      if (aClientType !== bClientType) {
        return clientOrder[aClientType] - clientOrder[bClientType];
      }
  
      // check lastAccessTime. If one has an access time and the other does
      // not, the one with the access time is automatically higher in the
      // list. If both have access times, sort in descending order, unless
      // access times are the same, then sort alphabetically.
      var aLastAccessTime = a.get('lastAccessTime');
      var bLastAccessTime = b.get('lastAccessTime');
  
      if (aLastAccessTime !== bLastAccessTime) {
        return bLastAccessTime - aLastAccessTime;
      } else if (aLastAccessTime && ! bLastAccessTime) {
        return -1;
      } else if (! aLastAccessTime && bLastAccessTime) {
        return 1;
      }
  
      // if access time is the same,
      // sort alphabetically
      var aName = (a.get('name') || '').trim().toLowerCase();
      var bName = (b.get('name') || '').trim().toLowerCase();
  
      if (aName < bName) {
        return -1;
      } else if (aName > bName) {
        return 1;
      }
  
      return 0;
    }
  
  });
  
  module.exports = AttachedClients;
  