// 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',
  };

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

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

      _expanded: {
        type: Boolean,
        value: false,
        observer: '_expandedChanged',
      },
      _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 []; },
      },
    },

    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) {
      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) {
      for (let i = 0; i < this._processedMessages.length; i++) {
        this._processedMessages[i].expanded = exp;
        if (i < this._visibleMessages.length) {
          this.set(['_visibleMessages', i, 'expanded'], exp);
        }
      }
    },

    _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);
    },

    _handleScrollTo(e) {
      this.scrollToMessage(e.detail.message.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) {
      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) {
      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 (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 => {
        return !this._isAutomated(msg);
      });
    },

    _computeShowHideTextHidden(visibleMessages, messages,
        hideAutomated) {
      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) {
      this._visibleMessages = messages.slice(-MAX_INITIAL_SHOWN_MESSAGES);
    },

    _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);
    },
  });
})();
