// Copyright (C) 2017 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';

  Polymer({
    is: 'gr-diff-comment-thread-group',

    properties: {
      changeNum: String,
      comments: {
        type: Array,
        value() { return []; },
      },
      projectName: String,
      patchForNewThreads: String,
      range: Object,
      isOnParent: {
        type: Boolean,
        value: false,
      },
      parentIndex: {
        type: Number,
        value: null,
      },
      _threads: {
        type: Array,
        value() { return []; },
      },
    },

    observers: [
      '_commentsChanged(comments.*)',
    ],

    addNewThread(locationRange) {
      this.push('_threads', {
        comments: [],
        locationRange,
        patchNum: this.patchForNewThreads,
      });
    },

    removeThread(locationRange) {
      for (let i = 0; i < this._threads.length; i++) {
        if (this._threads[i].locationRange === locationRange) {
          this.splice('_threads', i, 1);
          return;
        }
      }
    },

    getThreadForRange(rangeToCheck) {
      const threads = [].filter.call(
          Polymer.dom(this.root).querySelectorAll('gr-diff-comment-thread'),
          thread => {
            return thread.locationRange === rangeToCheck;
          });
      if (threads.length === 1) {
        return threads[0];
      }
    },

    _commentsChanged() {
      this._threads = this._getThreadGroups(this.comments);
    },

    _sortByDate(threadGroups) {
      if (!threadGroups.length) { return; }
      return threadGroups.sort((a, b) => {
        // If a comment is a draft, it doesn't have a start_datetime yet.
        // Assume it is newer than the comment it is being compared to.
        if (!a.start_datetime) {
          return 1;
        }
        if (!b.start_datetime) {
          return -1;
        }
        return util.parseDate(a.start_datetime) -
            util.parseDate(b.start_datetime);
      });
    },

    _calculateLocationRange(range, comment) {
      return 'range-' + range.start_line + '-' +
          range.start_character + '-' +
          range.end_line + '-' +
          range.end_character + '-' +
          comment.__commentSide;
    },

    /**
     * Determines what the patchNum of a thread should be. Use patchNum from
     * comment if it exists, otherwise the property of the thread group.
     * This is needed for switching between side-by-side and unified views when
     * there are unsaved drafts.
     */
    _getPatchNum(comment) {
      return comment.patchNum || this.patchForNewThreads;
    },

    _getThreadGroups(comments) {
      const threadGroups = {};

      for (const comment of comments) {
        let locationRange;
        if (!comment.range) {
          locationRange = 'line-' + comment.__commentSide;
        } else {
          locationRange = this._calculateLocationRange(comment.range, comment);
        }

        if (threadGroups[locationRange]) {
          threadGroups[locationRange].comments.push(comment);
        } else {
          threadGroups[locationRange] = {
            start_datetime: comment.updated,
            comments: [comment],
            locationRange,
            commentSide: comment.__commentSide,
            patchNum: this._getPatchNum(comment),
          };
        }
      }

      const threadGroupArr = [];
      const threadGroupKeys = Object.keys(threadGroups);
      for (const threadGroupKey of threadGroupKeys) {
        threadGroupArr.push(threadGroups[threadGroupKey]);
      }

      return this._sortByDate(threadGroupArr);
    },
  });
})();