/**
 * @license
 * 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 MAX_INITIAL_SHOWN_MESSAGES = 20;
  const MESSAGES_INCREMENT = 5;

  const ReportingEvent = {
    SHOW_ALL: 'show-all-messages',
    SHOW_MORE: 'show-more-messages',
  };

  /**
   * @appliesMixin Gerrit.KeyboardShortcutMixin
   * @extends Polymer.Element
   */
  class GrMessagesList extends Polymer.mixinBehaviors( [
    Gerrit.KeyboardShortcutBehavior,
  ], Polymer.GestureEventListeners(
      Polymer.LegacyElementMixin(
          Polymer.Element))) {
    static get is() { return 'gr-messages-list'; }

    static get properties() {
      return {
        changeNum: Number,
        messages: {
          type: Array,
          value() { return []; },
        },
        reviewerUpdates: {
          type: Array,
          value() { return []; },
        },
        changeComments: Object,
        projectName: String,
        showReplyButtons: {
          type: Boolean,
          value: false,
        },
        labels: Object,

        _expanded: {
          type: Boolean,
          value: false,
          observer: '_expandedChanged',
        },

        _expandCollapseTitle: {
          type: String,
        },

        _hideAutomated: {
          type: Boolean,
          value: false,
        },
        /**
         * The messages after processing and including merged reviewer updates.
         */
        _processedMessages: {
          type: Array,
          computed: '_computeItems(messages, reviewerUpdates)',
          observer: '_processedMessagesChanged',
        },
        /**
         * The subset of _processedMessages that is visible to the user.
         */
        _visibleMessages: {
          type: Array,
          value() { return []; },
        },

        _labelExtremes: {
          type: Object,
          computed: '_computeLabelExtremes(labels.*)',
        },
      };
    }

    scrollToMessage(messageID) {
      let el = this.$$('[data-message-id="' + messageID + '"]');
      // If the message is hidden, expand the hidden messages back to that
      // point.
      if (!el) {
        let index;
        for (index = 0; index < this._processedMessages.length; index++) {
          if (this._processedMessages[index].id === messageID) {
            break;
          }
        }
        if (index === this._processedMessages.length) { return; }

        const newMessages = this._processedMessages.slice(index,
            -this._visibleMessages.length);
        // Add newMessages to the beginning of _visibleMessages.
        this.splice(...['_visibleMessages', 0, 0].concat(newMessages));
        // Allow the dom-repeat to stamp.
        Polymer.dom.flush();
        el = this.$$('[data-message-id="' + messageID + '"]');
      }

      el.set('message.expanded', true);
      let top = el.offsetTop;
      for (let offsetParent = el.offsetParent;
        offsetParent;
        offsetParent = offsetParent.offsetParent) {
        top += offsetParent.offsetTop;
      }
      window.scrollTo(0, top);
      this._highlightEl(el);
    }

    _isAutomated(message) {
      return !!(message.reviewer ||
          (message.tag && message.tag.startsWith('autogenerated')));
    }

    _computeItems(messages, reviewerUpdates) {
      // Polymer 2: check for undefined
      if ([messages, reviewerUpdates].some(arg => arg === undefined)) {
        return [];
      }

      messages = messages || [];
      reviewerUpdates = reviewerUpdates || [];
      let mi = 0;
      let ri = 0;
      let result = [];
      let mDate;
      let rDate;
      for (let i = 0; i < messages.length; i++) {
        messages[i]._index = i;
      }

      while (mi < messages.length || ri < reviewerUpdates.length) {
        if (mi >= messages.length) {
          result = result.concat(reviewerUpdates.slice(ri));
          break;
        }
        if (ri >= reviewerUpdates.length) {
          result = result.concat(messages.slice(mi));
          break;
        }
        mDate = mDate || util.parseDate(messages[mi].date);
        rDate = rDate || util.parseDate(reviewerUpdates[ri].date);
        if (rDate < mDate) {
          result.push(reviewerUpdates[ri++]);
          rDate = null;
        } else {
          result.push(messages[mi++]);
          mDate = null;
        }
      }
      return result;
    }

    _expandedChanged(exp) {
      if (this._processedMessages) {
        for (let i = 0; i < this._processedMessages.length; i++) {
          this._processedMessages[i].expanded = exp;
        }
      }
      // _visibleMessages is a subarray of _processedMessages
      // _processedMessages contains all items from _visibleMessages
      // At this point all _visibleMessages.expanded values are set,
      // and notifyPath must be used to notify Polymer about changes.
      if (this._visibleMessages) {
        for (let i = 0; i < this._visibleMessages.length; i++) {
          this.notifyPath(`_visibleMessages.${i}.expanded`);
        }
      }

      if (this._expanded) {
        this._expandCollapseTitle = this.createTitle(
            this.Shortcut.COLLAPSE_ALL_MESSAGES, this.ShortcutSection.ACTIONS);
      } else {
        this._expandCollapseTitle = this.createTitle(
            this.Shortcut.EXPAND_ALL_MESSAGES, this.ShortcutSection.ACTIONS);
      }
    }

    _highlightEl(el) {
      const highlightedEls =
          Polymer.dom(this.root).querySelectorAll('.highlighted');
      for (const highlighedEl of highlightedEls) {
        highlighedEl.classList.remove('highlighted');
      }
      function handleAnimationEnd() {
        el.removeEventListener('animationend', handleAnimationEnd);
        el.classList.remove('highlighted');
      }
      el.addEventListener('animationend', handleAnimationEnd);
      el.classList.add('highlighted');
    }

    /**
     * @param {boolean} expand
     */
    handleExpandCollapse(expand) {
      this._expanded = expand;
    }

    _handleExpandCollapseTap(e) {
      e.preventDefault();
      this.handleExpandCollapse(!this._expanded);
    }

    _handleAnchorClick(e) {
      this.scrollToMessage(e.detail.id);
    }

    _hasAutomatedMessages(messages) {
      if (!messages) { return false; }
      for (const message of messages) {
        if (this._isAutomated(message)) {
          return true;
        }
      }
      return false;
    }

    _computeExpandCollapseMessage(expanded) {
      return expanded ? 'Collapse all' : 'Expand all';
    }

    /**
     * Computes message author's file comments for change's message.
     * Method uses this.messages to find next message and relies on messages
     * to be sorted by date field descending.
     *
     * @param {!Object} changeComments changeComment object, which includes
     *     a method to get all published comments (including robot comments),
     *     which returns a Hash of arrays of comments, filename as key.
     * @param {!Object} message
     * @return {!Object} Hash of arrays of comments, filename as key.
     */
    _computeCommentsForMessage(changeComments, message) {
      if ([changeComments, message].some(arg => arg === undefined)) {
        return [];
      }
      const comments = changeComments.getAllPublishedComments();
      if (message._index === undefined || !comments || !this.messages) {
        return [];
      }
      const messages = this.messages || [];
      const index = message._index;
      const authorId = message.author && message.author._account_id;
      const mDate = util.parseDate(message.date).getTime();
      // NB: Messages array has oldest messages first.
      let nextMDate;
      if (index > 0) {
        for (let i = index - 1; i >= 0; i--) {
          if (messages[i] && messages[i].author &&
              messages[i].author._account_id === authorId) {
            nextMDate = util.parseDate(messages[i].date).getTime();
            break;
          }
        }
      }
      const msgComments = {};
      for (const file in comments) {
        if (!comments.hasOwnProperty(file)) { continue; }
        const fileComments = comments[file];
        for (let i = 0; i < fileComments.length; i++) {
          if (fileComments[i].author &&
              fileComments[i].author._account_id !== authorId) {
            continue;
          }
          const cDate = util.parseDate(fileComments[i].updated).getTime();
          if (cDate <= mDate) {
            if (nextMDate && cDate <= nextMDate) {
              continue;
            }
            msgComments[file] = msgComments[file] || [];
            msgComments[file].push(fileComments[i]);
          }
        }
      }
      return msgComments;
    }

    /**
     * Returns the number of messages to splice to the beginning of
     * _visibleMessages. This is the minimum of the total number of messages
     * remaining in the list and the number of messages needed to display five
     * more visible messages in the list.
     */
    _getDelta(visibleMessages, messages, hideAutomated) {
      if ([visibleMessages, messages].some(arg => arg === undefined)) {
        return 0;
      }

      let delta = MESSAGES_INCREMENT;
      const msgsRemaining = messages.length - visibleMessages.length;

      if (hideAutomated) {
        let counter = 0;
        let i;
        for (i = msgsRemaining; i > 0 && counter < MESSAGES_INCREMENT; i--) {
          if (!this._isAutomated(messages[i - 1])) { counter++; }
        }
        delta = msgsRemaining - i;
      }
      return Math.min(msgsRemaining, delta);
    }

    /**
     * Gets the number of messages that would be visible, but do not currently
     * exist in _visibleMessages.
     */
    _numRemaining(visibleMessages, messages, hideAutomated) {
      if ([visibleMessages, messages].some(arg => arg === undefined)) {
        return 0;
      }

      if (hideAutomated) {
        return this._getHumanMessages(messages).length -
            this._getHumanMessages(visibleMessages).length;
      }
      return messages.length - visibleMessages.length;
    }

    _computeIncrementText(visibleMessages, messages, hideAutomated) {
      let delta = this._getDelta(visibleMessages, messages, hideAutomated);
      delta = Math.min(
          this._numRemaining(visibleMessages, messages, hideAutomated), delta);
      return 'Show ' + Math.min(MESSAGES_INCREMENT, delta) + ' more';
    }

    _getHumanMessages(messages) {
      return messages.filter(msg => !this._isAutomated(msg));
    }

    _computeShowHideTextHidden(visibleMessages, messages,
        hideAutomated) {
      if ([visibleMessages, messages].some(arg => arg === undefined)) {
        return 0;
      }

      if (hideAutomated) {
        messages = this._getHumanMessages(messages);
        visibleMessages = this._getHumanMessages(visibleMessages);
      }
      return visibleMessages.length >= messages.length;
    }

    _handleShowAllTap() {
      this._visibleMessages = this._processedMessages;
      this.$.reporting.reportInteraction(ReportingEvent.SHOW_ALL);
    }

    _handleIncrementShownMessages() {
      const delta = this._getDelta(this._visibleMessages,
          this._processedMessages, this._hideAutomated);
      const len = this._visibleMessages.length;
      const newMessages = this._processedMessages.slice(-(len + delta), -len);
      // Add newMessages to the beginning of _visibleMessages
      this.splice(...['_visibleMessages', 0, 0].concat(newMessages));
      this.$.reporting.reportInteraction(ReportingEvent.SHOW_MORE);
    }

    _processedMessagesChanged(messages) {
      if (messages) {
        this._visibleMessages = messages.slice(-MAX_INITIAL_SHOWN_MESSAGES);

        if (messages.length === 0) return;
        const tags = messages.map(message => message.tag || message.type ||
            (message.comments ? 'comments' : 'none'));
        const tagsCounted = tags.reduce((acc, val) => {
          acc[val] = (acc[val] || 0) + 1;
          return acc;
        }, {all: messages.length});
        this.$.reporting.reportInteraction('messages-count', tagsCounted);
      }
    }

    _computeNumMessagesText(visibleMessages, messages,
        hideAutomated) {
      const total =
          this._numRemaining(visibleMessages, messages, hideAutomated);
      return total === 1 ? 'Show 1 message' : 'Show all ' + total + ' messages';
    }

    _computeIncrementHidden(visibleMessages, messages,
        hideAutomated) {
      const total =
          this._numRemaining(visibleMessages, messages, hideAutomated);
      return total <= this._getDelta(visibleMessages, messages, hideAutomated);
    }

    /**
     * Compute a mapping from label name to objects representing the minimum and
     * maximum possible values for that label.
     */
    _computeLabelExtremes(labelRecord) {
      const extremes = {};
      const labels = labelRecord.base;
      if (!labels) { return extremes; }
      for (const key of Object.keys(labels)) {
        if (!labels[key] || !labels[key].values) { continue; }
        const values = Object.keys(labels[key].values)
            .map(v => parseInt(v, 10));
        values.sort((a, b) => a - b);
        if (!values.length) { continue; }
        extremes[key] = {min: values[0], max: values[values.length - 1]};
      }
      return extremes;
    }
  }

  customElements.define(GrMessagesList.is, GrMessagesList);
})();
