Source: panels/root/storage_usb_item.js

/* global DeviceStorageHelper, openIncompatibleSettingsDialog */
/**
 * Links the root panel list item with USB Storage.
 *
 * XXX bug 973451 will remove media storage part
 */
define(function(require) {
  'use strict';

  var SettingsListener = require('shared/settings_listener');
  var AsyncStorage = require('shared/async_storage');
  var SettingsCache = require('modules/settings_cache');
  var SettingsService = require('modules/settings_service');

  /**
   * @alias module:panels/root/storage_usb_item
   * @class USBStorageItem
   * @param {Object} elements
                     elements displaying the usb and media storage information
   * @returns {USBStorageItem}
   */
  function USBStorageItem(elements) {
    this._enabled = false;
    this._elements = elements;
    this._umsSettingKey = 'ums.enabled';
    // XXX media related attributes
    this._defaultMediaVolume = null;
    this._defaultVolumeState = 'available';
    this._defaultMediaVolumeKey = 'device.storage.writable.name';
    this._boundUmsSettingHandler = this._umsSettingHandler.bind(this);
    this._boundMediaVolumeChangeHandler =
      this._mediaVolumeChangeHandler.bind(this);
  }

  USBStorageItem.prototype = {
    /**
     * The value indicates whether the module is responding. If it is false, the
     * UI stops reflecting the updates from the root panel context.
     *
     * @access public
     * @memberOf USBStorageItem.prototype
     * @type {Boolean}
     */
    get enabled() {
      return this._enabled;
    },

    set enabled(value) {
      if (this._enabled === value) {
        return;
      } else {
        this._enabled = value;
      }
      if (value) { //observe
        this._elements.usbEnabledCheckBox.disabled = false;
        // ums master switch on root panel
        this._elements.usbEnabledCheckBox.addEventListener('change', this);

        SettingsListener.observe(this._umsSettingKey, false,
          this._boundUmsSettingHandler);

        // media storage
        // Show default media volume state on root panel
        SettingsListener.observe(this._defaultMediaVolumeKey, 'sdcard',
          this._boundMediaVolumeChangeHandler);
        window.addEventListener('localized', this);

        // register USB storage split click handler
        this._elements.usbStorage.addEventListener('click', this._onItemClick);
      } else { //unobserve
        this._elements.usbEnabledCheckBox.removeEventListener('change', this);

        SettingsListener.unobserve(this._umsSettingKey,
          this._boundUmsSettingHandler);

        // media storage
        SettingsListener.unobserve(this._defaultMediaVolumeKey,
          this._boundMediaVolumeChangeHandler);
        window.removeEventListener('localized', this);

        this._elements.usbStorage.removeEventListener('click',
          this._onItemClick);
      }
    },

    _umsSettingHandler: function storage_umsSettingHandler(enabled) {
      this._elements.usbEnabledCheckBox.checked = enabled;
      this._updateUmsDesc();
    },

    // navigate to USB Storage panel
    _onItemClick: function storage_onItemClick(evt) {
      SettingsService.navigate('usbStorage');
    },

    handleEvent: function storage_handleEvent(evt) {
      switch (evt.type) {
        case 'localized':
          this._updateMediaStorageInfo();
          break;
        case 'change':
          if (evt.target === this._elements.usbEnabledCheckBox) {
            this._umsMasterSettingChanged(evt);
          } else {
            // we are handling storage state changes
            // possible state: available, unavailable, shared
            this._updateMediaStorageInfo();
          }
          break;
      }
    },

    // ums description
    _updateUmsDesc: function storage_updateUmsDesc() {
      var key;
      if (this._elements.usbEnabledCheckBox.checked) {
        //TODO list all enabled volume name
        key = 'enabled';
      } else if (this._defaultVolumeState === 'shared') {
        key = 'umsUnplugToDisable';
      } else {
        key = 'disabled';
      }
      this._elements.usbEnabledInfoBlock.setAttribute('data-l10n-id', key);
    },

    _umsMasterSettingChanged: function storage_umsMasterSettingChanged(evt) {
      var checkbox = evt.target;
      var cset = {};
      var warningKey = 'ums-turn-on-warning';

      if (checkbox.checked) {
        AsyncStorage.getItem(warningKey, function(showed) {
          if (!showed) {
            this._elements.umsWarningDialog.hidden = false;

            this._elements.umsConfirmButton.onclick = function() {
              AsyncStorage.setItem(warningKey, true);
              this._elements.umsWarningDialog.hidden = true;

              SettingsCache.getSettings(
                this._openIncompatibleSettingsDialogIfNeeded.bind(this));
            }.bind(this);

            this._elements.umsCancelButton.onclick = function() {
              cset[this._umsSettingKey] = false;
              Settings.mozSettings.createLock().set(cset);

              checkbox.checked = false;
              this._elements.umsWarningDialog.hidden = true;
            }.bind(this);
          } else {
            SettingsCache.getSettings(
              this._openIncompatibleSettingsDialogIfNeeded.bind(this));
          }
        }.bind(this));
      } else {
        cset[this._umsSettingKey] = false;
        Settings.mozSettings.createLock().set(cset);
      }
    },

    _openIncompatibleSettingsDialogIfNeeded:
      function storage_openIncompatibleSettingsDialogIfNeeded(settings) {
        var cset = {};
        var umsSettingKey = this._umsSettingKey;
        var usbTetheringSetting = settings['tethering.usb.enabled'];

        if (!usbTetheringSetting) {
          cset[umsSettingKey] = true;
          Settings.mozSettings.createLock().set(cset);
        } else {
          var oldSetting = 'tethering.usb.enabled';
          openIncompatibleSettingsDialog('incompatible-settings-warning',
            umsSettingKey, oldSetting, null);
        }
    },

    // XXX media related functions
    _mediaVolumeChangeHandler:
      function storage_mediaVolumeChangeHandler(defaultName) {
      if (this._defaultMediaVolume) {
        this._defaultMediaVolume.removeEventListener('change', this);
      }
      this._defaultMediaVolume = this._getDefaultVolume(defaultName);
      if (this._defaultMediaVolume) {
        this._defaultMediaVolume.addEventListener('change', this);
      }
      this._updateMediaStorageInfo();
    },

    // Media Storage
    _updateMediaStorageInfo: function storage_updateMediaStorageInfo() {
      if (!this._defaultMediaVolume) {
        this._updateVolumeState(null, 'unavailable');
        return;
      }

      var self = this;
      this._defaultMediaVolume.available().onsuccess = function(evt) {
        var state = evt.target.result;
        var firstVolume = navigator.getDeviceStorages('sdcard')[0];
        // if the default storage is unavailable, and it's not the
        // internal storage, we show the internal storage status instead.
        if (state === 'unavailable' &&
          self._defaultMediaVolume.storageName !== firstVolume.storageName) {
          firstVolume.available().onsuccess = function(e) {
            self._updateVolumeState(firstVolume, e.target.result);
          };
        } else {
          self._updateVolumeState(self._defaultMediaVolume, state);
        }
      };
    },

    _updateVolumeState: function storage_updateVolumeState(volume, state) {
      this._defaultVolumeState = state;
      this._updateUmsDesc();
      switch (state) {
        case 'available':
          this._updateMediaFreeSpace(volume);
          this._lockMediaStorageMenu(false);
          break;

        case 'shared':
          this._elements.mediaStorageDesc.removeAttribute('data-l10n-id');
          this._elements.mediaStorageDesc.textContent = '';
          this._lockMediaStorageMenu(false);
          break;

        case 'unavailable':
          this._elements.mediaStorageDesc.setAttribute('data-l10n-id',
                                                       'no-storage');
          this._lockMediaStorageMenu(true);
          break;
      }
    },

    _updateMediaFreeSpace: function storage_updateMediaFreeSpace(volume) {
      var self = this;
      volume.freeSpace().onsuccess = function(e) {
        DeviceStorageHelper.showFormatedSize(self._elements.mediaStorageDesc,
          'availableSize', e.target.result);
      };
    },

    _lockMediaStorageMenu: function storage_setMediaMenuState(lock) {
      if (lock) {
        this._elements.mediaStorageSection.setAttribute('aria-disabled', true);
      } else {
        this._elements.mediaStorageSection.removeAttribute('aria-disabled');
      }
    },

    // util function
    _getDefaultVolume: function storage_getDefaultVolume(name) {
      // Per API design, all media type return the same volumes.
      // So we use 'sdcard' here for no reason.
      // https://bugzilla.mozilla.org/show_bug.cgi?id=856782#c10
      var volumes = navigator.getDeviceStorages('sdcard');
      if (!name || name === '') {
        return volumes[0];
      }
      for (var i = 0; i < volumes.length; ++i) {
        if (volumes[i].storageName === name) {
          return volumes[i];
        }
      }
      return volumes[0];
    }
  };

  return function ctor_usb_storage_item(elements) {
    return new USBStorageItem(elements);
  };
});