Source: pages/google-photos-page.js

'use strict';

  new ExceptionHandler();

  window.app = window.app || {};
  app.GooglePhotosPage = Polymer({
    is: 'google-photos-page',

    behaviors: [
      Chrome.LocalizeBehavior,
    ],

    properties: {
      isAlbumMode: {
        type: Boolean,
        value: true,
        notify: true,
      },

      useGoogleAlbums: {
        type: Boolean,
        value: true,
        notify: true,
      },

      useGooglePhotos: {
        type: Boolean,
        value: false,
        notify: true,
      },

      albums: {
        /** @type {app.GoogleSource.Album[]} */
        type: Array,
        notify: true,
        value: [],
      },

      selections: {
        /** @type {{id: id, photos: photos}} */
        type: Array,
        value: [],
      },

      waitForLoad: {
        type: Boolean,
        value: false,
        notify: true,
      },

      permPicasa: {
        type: String,
        value: 'notSet',
        notify: true,
      },

      isHidden: {
        type: Boolean,
        computed: '_computeHidden(waitForLoad, permPicasa)',
      },
    },

    // so we can lazily create the page
    factoryImpl: function(id) {
      this.setAttribute('id', id);
    },

    ready: function() {
      if (Chrome.Storage.getBool('isAlbumMode')) {
        this.loadAlbumList();
      }
    },

    /**
     * Query Picasa for the list of the users albums
     */
    loadAlbumList: function() {
      const ERR_TITLE = Chrome.Locale.localize('err_load_album_list');
      this._checkPermissions().then((allowed) => {
        if (!allowed) {
          const err = new Error(Chrome.Locale.localize('err_auth_picasa'));
          return Promise.reject(err);
        }
        this.set('waitForLoad', true);
        return app.GoogleSource.loadAlbumList();
      }).then((albums) => {
        // get all the user's albums
        this.splice('albums', 0, this.albums.length);
        albums = albums || [];
        albums.forEach((album) => {
          this.push('albums', album);
        });
        // update the currently selected albums from the web
        // eslint-disable-next-line promise/no-nesting
        app.PhotoSources.process('useGoogleAlbums').catch((err) => {
          Chrome.GA.error(err.message, 'GooglePhotosPage.loadAlbumList');
        });
        // set selected state on albums
        this._selectAlbums();
        this.set('waitForLoad', false);
        return Promise.resolve();
      }).catch((err) => {
        this.set('waitForLoad', false);
        Chrome.Log.error(err.message,
            'GooglePhotosPage.loadAlbumList', ERR_TITLE);
        this.$.dialogTitle.innerHTML =
            Chrome.Locale.localize('err_request_failed');
        this.$.dialogText.innerHTML = err.message;
        this.$.errorDialog.open();
      });
    },

    /**
     * Try to get permissions, if not already authorized - may block
     * @returns {Promise<boolean>} true if we have permissions
     * @private
     */
    _checkPermissions: function() {
      if (app.Permissions.isAllowed(app.Permissions.PICASA)) {
        return Promise.resolve(true);
      } else {
        return app.Permissions.request(app.Permissions.PICASA).then((granted) => {
          return Promise.resolve(granted);
        });
      }
    },

    /**
     * Set keys for photo sources
     * @param {boolean} useGoogle - Google Photos use enabled
     * @param {boolean} isAlbumMode - Are we in album mode
     * @private
     */
    _setUseKeys: function(useGoogle, isAlbumMode) {
      const useAlbums = (useGoogle && isAlbumMode);
      const usePhotos = (useGoogle && !isAlbumMode);
      this.set('useGoogleAlbums', useAlbums);
      this.set('useGooglePhotos', usePhotos);
    },

    /**
     * Event: Handle tap on mode icon
     * @private
     */
    _onModeTapped: function() {
      this.set('isAlbumMode', !this.isAlbumMode);
      this._setUseKeys(this.$.googlePhotosToggle.checked, this.isAlbumMode);
      if (this.isAlbumMode) {
        this.loadAlbumList();
      } else {
        this.albums.splice(0, this.albums.length);
        this.selections.splice(0, this.selections.length);
      }
    },

    /**
     * Event: Handle tap on refresh album list icon
     * @private
     */
    _onRefreshTapped: function() {
      Chrome.GA.event(Chrome.GA.EVENT.ICON, 'refreshGoogleAlbums');
      this.loadAlbumList();
    },

    /**
     * Event: Handle tap on select all albums icon
     * @private
     */
    _onSelectAllTapped: function() {
      Chrome.GA.event(Chrome.GA.EVENT.ICON, 'selectAllGoogleAlbums');
      for (let i = 0; i < this.albums.length; i++) {
        const album = this.albums[i];
        if (!album.checked) {
          this.selections.push({id: album.id, photos: album.photos});
          const set = Chrome.Storage.safeSet('albumSelections', this.selections,
                  'useGoogleAlbums');
          if (!set) {
            // exceeded storage limits
            this.selections.pop();
            this._showStorageErrorDialog(
                'GooglePhotosPage._onSelectAllTapped');
            break;
          }
          this.set('albums.' + i + '.checked', true);
        }
      }
    },

    /**
     * Event: Handle tap on deselect all albums icon
     * @private
     */
    _onDeselectAllTapped: function() {
      Chrome.GA.event(Chrome.GA.EVENT.ICON, 'deselectAllGoogleAlbums');
      this._uncheckAll();
      this.selections.splice(0, this.selections.length);
      Chrome.Storage.set('albumSelections', null);
    },

    /**
     * Event: Album checkbox state changed
     * @param {Event} event - tap event
     * @param {app.GoogleSource.Album} event.model.album - the album
     * @private
     */
    _onAlbumSelectChanged: function(event) {
      const album = event.model.album;

      Chrome.GA.event(Chrome.GA.EVENT.CHECK,
          `selectGoogleAlbum: ${album.checked}`);

      if (album.checked) {
        // add new
        this.selections.push({id: album.id, photos: album.photos});
      } else {
        // delete old
        const index = this.selections.findIndex((e) => {
          return e.id === album.id;
        });
        if (index !== -1) {
          this.selections.splice(index, 1);
        }
      }

      const set = Chrome.Storage.safeSet('albumSelections', this.selections,
          'useGoogleAlbums');
      if (!set) {
        // exceeded storage limits
        this.selections.pop();
        this.set('albums.' + album.index + '.checked', false);
        this._showStorageErrorDialog(
            'GooglePhotosPage._onAlbumSelectChanged');
      }
    },

    /**
     * Event: checked state changed on main toggle changed
     * @private
     */
    _onUseGoogleChanged: function() {
      const useGoogle = this.$.googlePhotosToggle.checked;
      this._setUseKeys(useGoogle, this.isAlbumMode);
      Chrome.GA.event(Chrome.GA.EVENT.TOGGLE,
          `useGoogle: ${useGoogle}`);
    },

    /**
     * Exceeded storage limits error
     * @param {string} method - function that caused error
     * @private
     */
    _showStorageErrorDialog: function(method) {
      const ERR_TITLE = Chrome.Locale.localize('err_storage_title');
      Chrome.Log.error('safeSet failed', method, ERR_TITLE);
      this.$.dialogTitle.innerHTML = ERR_TITLE;
      this.$.dialogText.innerHTML = Chrome.Locale.localize('err_storage_desc');
      this.$.errorDialog.open();
    },

    /**
     * Set the checked state of the stored albums
     * @private
     */
    _selectAlbums: function() {
      this.set('selections', Chrome.Storage.get('albumSelections', []));
      for (let i = 0; i < this.albums.length; i++) {
        for (let j = 0; j < this.selections.length; j++) {
          if (this.albums[i].id === this.selections[j].id) {
            this.set('albums.' + i + '.checked', true);
            break;
          }
        }
      }
    },

    /**
     * Uncheck all albums
     * @private
     */
    _uncheckAll: function() {
      this.albums.forEach((album, index) => {
        if (album.checked) {
          this.set('albums.' + index + '.checked', false);
        }
      });
    },

    /**
     * Computed property: Hidden state of main interface
     * @param {boolean} waitForLoad - true if loading
     * @param {string} permPicasa - permission state
     * @returns {boolean} true if hidden
     * @private
     */
    _computeHidden: function(waitForLoad, permPicasa) {
      let ret = true;
      if (!waitForLoad && (permPicasa === 'allowed')) {
        ret = false;
      }
      return ret;
    },

    /**
     * Computed binding: Calculate page title
     * @param {boolean} isAlbumMode - true if album mode
     * @returns {string} page title
     * @private
     */
    _computeTitle: function(isAlbumMode) {
      let ret = '';
      if (isAlbumMode) {
        ret = Chrome.Locale.localize('google_title');
      } else {
        ret = Chrome.Locale.localize('google_title_photos');
      }
      return ret;
    },

    /**
     * Computed binding: Calculate mode icon
     * @param {boolean} isAlbumMode - true if album mode
     * @returns {string} an icon
     * @private
     */
    _computeModeIcon: function(isAlbumMode) {
      let ret = '';
      if (isAlbumMode) {
        ret = 'myicons:photo-album';
      } else {
        ret = 'myicons:photo';
      }
      return ret;
    },

    /**
     * Computed binding: Calculate mode tooltip
     * @param {boolean} isAlbumMode - true if album mode
     * @returns {string} page title
     * @private
     */
    _computeModeTooltip: function(isAlbumMode) {
      let ret = '';
      if (isAlbumMode) {
        ret = Chrome.Locale.localize('tooltip_google_mode_albums');
      } else {
        ret = Chrome.Locale.localize('tooltip_google_mode_photos');
      }
      return ret;
    },

    /**
     * Computed binding: Calculate mode tooltip
     * @param {boolean} useGoogle - true if using Google Photos
     * @param {boolean} isAlbumMode - true if album mode
     * @returns {boolean} true if album icons should be disabled
     * @private
     */
    _computeAlbumIconDisabled(useGoogle, isAlbumMode) {
      return !(useGoogle && isAlbumMode);
    },

    /**
     * Computed binding: Set photo count label on an album
     * @param {int} count - number of photos in album
     * @returns {string} i18n label
     * @private
     */
    _computePhotoLabel: function(count) {
      let ret = `${count} ${Chrome.Locale.localize('photos')}`;
      if (count === 1) {
        ret = `${count} ${Chrome.Locale.localize('photo')}`;
      }
      return ret;
    },

    /**
     * Initialize value if it is not in localStorage
     * @private
     */
    _initPermPicasa: function() {
      this.set('permPicasa', 'notSet');
    },

    /**
     * Initialize value if it is not in localStorage
     * @private
     */
    _initIsAlbumMode: function() {
      this.set('isAlbumMode', true);
    },

    /**
     * Initialize value if it is not in localStorage
     * @private
     */
    _initUseGoogleAlbums: function() {
      this.set('useGoogleAlbums', true);
    },

    /**
     * Initialize value if it is not in localStorage
     * @private
     */
    _initUseGooglePhotos: function() {
      this.set('useGooglePhotos', true);
    },
  });