// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function() {
  'use strict';

  const VALID_EMAIL_ALERT = 'Please input a valid email.';

  Polymer({
    is: 'gr-account-list',

    /**
     * Fired when user inputs an invalid email address.
     *
     * @event show-alert
     */

    properties: {
      accounts: {
        type: Array,
        value() { return []; },
        notify: true,
      },
      change: Object,
      filter: Function,
      placeholder: String,
      /**
       * Needed for template checking since value is initially set to null.
       * @type {?Object} */
      pendingConfirmation: {
        type: Object,
        value: null,
        notify: true,
      },
      readonly: {
        type: Boolean,
        value: false,
      },

      /**
       * When true, the account-entry autocomplete uses the account suggest API
       * endpoint, which suggests any account in that Gerrit instance (and does
       * not suggest groups).
       *
       * When false/undefined, account-entry uses the suggest_reviewers API
       * endpoint, which suggests any account or group in that Gerrit instance
       * that is not already a reviewer (or is not CCed) on that change.
       */
      allowAnyUser: {
        type: Boolean,
        value: false,
      },

      /**
       * When true, allows for non-suggested inputs to be added.
       */
      allowAnyInput: {
        type: Boolean,
        value: false,
      },

      /**
       * Array of values (groups/accounts) that are removable. When this prop is
       * undefined, all values are removable.
       */
      removableValues: Array,
      maxCount: {
        type: Number,
        value: 0,
      },
    },

    listeners: {
      remove: '_handleRemove',
    },

    get accountChips() {
      return Polymer.dom(this.root).querySelectorAll('gr-account-chip');
    },

    get focusStart() {
      return this.$.entry.focusStart;
    },

    _handleAdd(e) {
      this._addReviewer(e.detail.value);
    },

    _addReviewer(reviewer) {
      // Append new account or group to the accounts property. We add our own
      // internal properties to the account/group here, so we clone the object
      // to avoid cluttering up the shared change object.
      if (reviewer.account) {
        const account =
            Object.assign({}, reviewer.account, {_pendingAdd: true});
        this.push('accounts', account);
      } else if (reviewer.group) {
        if (reviewer.confirm) {
          this.pendingConfirmation = reviewer;
          return;
        }
        const group = Object.assign({}, reviewer.group,
            {_pendingAdd: true, _group: true});
        this.push('accounts', group);
      } else if (this.allowAnyInput) {
        if (!reviewer.includes('@')) {
          // Repopulate the input with what the user tried to enter and have
          // a toast tell them why they can't enter it.
          this.$.entry.setText(reviewer);
          this.dispatchEvent(new CustomEvent('show-alert',
            {detail: {message: VALID_EMAIL_ALERT}, bubbles: true}));
          return false;
        } else {
          const account = {email: reviewer, _pendingAdd: true};
          this.push('accounts', account);
        }
      }
      this.pendingConfirmation = null;
      return true;
    },

    confirmGroup(group) {
      group = Object.assign(
          {}, group, {confirmed: true, _pendingAdd: true, _group: true});
      this.push('accounts', group);
      this.pendingConfirmation = null;
    },

    _computeChipClass(account) {
      const classes = [];
      if (account._group) {
        classes.push('group');
      }
      if (account._pendingAdd) {
        classes.push('pendingAdd');
      }
      return classes.join(' ');
    },

    _accountMatches(a, b) {
      if (a && b) {
        if (a._account_id) {
          return a._account_id === b._account_id;
        }
        if (a.email) {
          return a.email === b.email;
        }
      }
      return a === b;
    },

    _computeRemovable(account) {
      if (this.readonly) { return false; }
      if (this.removableValues) {
        for (let i = 0; i < this.removableValues.length; i++) {
          if (this._accountMatches(this.removableValues[i], account)) {
            return true;
          }
        }
        return !!account._pendingAdd;
      }
      return true;
    },

    _handleRemove(e) {
      const toRemove = e.detail.account;
      this._removeAccount(toRemove);
      this.$.entry.focus();
    },

    _removeAccount(toRemove) {
      if (!toRemove || !this._computeRemovable(toRemove)) { return; }
      for (let i = 0; i < this.accounts.length; i++) {
        let matches;
        const account = this.accounts[i];
        if (toRemove._group) {
          matches = toRemove.id === account.id;
        } else {
          matches = this._accountMatches(toRemove, account);
        }
        if (matches) {
          this.splice('accounts', i, 1);
          return;
        }
      }
      console.warn('received remove event for missing account', toRemove);
    },

    _handleInputKeydown(e) {
      const input = e.detail.input;
      if (input.selectionStart !== input.selectionEnd ||
          input.selectionStart !== 0) {
        return;
      }
      switch (e.detail.keyCode) {
        case 8: // Backspace
          this._removeAccount(this.accounts[this.accounts.length - 1]);
          break;
        case 37: // Left arrow
          if (this.accountChips[this.accountChips.length - 1]) {
            this.accountChips[this.accountChips.length - 1].focus();
          }
          break;
      }
    },

    _handleChipKeydown(e) {
      const chip = e.target;
      const chips = this.accountChips;
      const index = chips.indexOf(chip);
      switch (e.keyCode) {
        case 8: // Backspace
        case 13: // Enter
        case 32: // Spacebar
        case 46: // Delete
          this._removeAccount(chip.account);
          // Splice from this array to avoid inconsistent ordering of
          // event handling.
          chips.splice(index, 1);
          if (index < chips.length) {
            chips[index].focus();
          } else if (index > 0) {
            chips[index - 1].focus();
          } else {
            this.$.entry.focus();
          }
          break;
        case 37: // Left arrow
          if (index > 0) {
            chip.blur();
            chips[index - 1].focus();
          }
          break;
        case 39: // Right arrow
          chip.blur();
          if (index < chips.length - 1) {
            chips[index + 1].focus();
          } else {
            this.$.entry.focus();
          }
          break;
      }
    },

    /**
     * Submit the text of the entry as a reviewer value, if it exists. If it is
     * a successful submit of the text, clear the entry value.
     *
     * @return {boolean} If there is text in the entry, return true if the
     *     submission was successful and false if not. If there is no text,
     *     return true.
     */
    submitEntryText() {
      const text = this.$.entry.getText();
      if (!text.length) { return true; }
      const wasSubmitted = this._addReviewer(text);
      if (wasSubmitted) { this.$.entry.clear(); }
      return wasSubmitted;
    },

    additions() {
      return this.accounts.filter(account => {
        return account._pendingAdd;
      }).map(account => {
        if (account._group) {
          return {group: account};
        } else {
          return {account};
        }
      });
    },

    _computeEntryHidden(maxCount, accountsRecord, readonly) {
      return (maxCount && maxCount <= accountsRecord.base.length) || readonly;
    },
  });
})();
