<!--
Copyright (C) 2015 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.
-->

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="gr-diff-comment.html">

<dom-module id="gr-diff-comment-thread">
  <template>
    <style>
      :host {
        display: block;
        white-space: normal;
      }
      gr-diff-comment {
        border-left: 1px solid #ddd;
      }
      gr-diff-comment:first-of-type {
        border-top: 1px solid #ddd;
      }
      gr-diff-comment:last-of-type {
        border-bottom: 1px solid #ddd;
      }
    </style>
    <div id="container">
      <template id="commentList" is="dom-repeat" items="{{_orderedComments}}" as="comment">
        <gr-diff-comment
            comment="{{comment}}"
            change-num="[[changeNum]]"
            patch-num="[[patchNum]]"
            draft="[[comment.__draft]]"
            show-actions="[[showActions]]"
            project-config="[[projectConfig]]"
            on-height-change="_handleCommentHeightChange"
            on-reply="_handleCommentReply"
            on-discard="_handleCommentDiscard"
            on-done="_handleCommentDone"></gr-diff-comment>
      </template>
    </div>
  </template>
  <script>
  (function() {
    'use strict';


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

      /**
       * Fired when the height of the thread changes.
       *
       * @event height-change
       */

      /**
       * Fired when the thread should be discarded.
       *
       * @event discard
       */

      properties: {
        changeNum: String,
        comments: {
          type: Array,
          value: function() { return []; },
        },
        patchNum: String,
        path: String,
        showActions: Boolean,
        projectConfig: Object,

        _boundWindowResizeHandler: {
          type: Function,
          value: function() { return this._handleWindowResize.bind(this); }
        },
        _lastHeight: Number,
        _orderedComments: Array,
      },

      get naturalHeight() {
        return this.$.container.offsetHeight;
      },

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

      attached: function() {
        window.addEventListener('resize', this._boundWindowResizeHandler);
      },

      detached: function() {
        window.removeEventListener('resize', this._boundWindowResizeHandler);
      },

      _handleWindowResize: function(e) {
        this._heightChanged();
      },

      _commentsChanged: function(changeRecord) {
        this._orderedComments = this._sortedComments(this.comments);
      },

      _sortedComments: function(comments) {
        comments.sort(function(c1, c2) {
          var c1Date = c1.__date || util.parseDate(c1.updated);
          var c2Date = c2.__date || util.parseDate(c2.updated);
          return c1Date - c2Date;
        });

        var commentIDToReplies = {};
        var topLevelComments = [];
        for (var i = 0; i < comments.length; i++) {
          var c = comments[i];
          if (c.in_reply_to) {
            if (commentIDToReplies[c.in_reply_to] == null) {
              commentIDToReplies[c.in_reply_to] = [];
            }
            commentIDToReplies[c.in_reply_to].push(c);
          } else {
            topLevelComments.push(c);
          }
        }
        var results = [];
        for (var i = 0; i < topLevelComments.length; i++) {
          this._visitComment(topLevelComments[i], commentIDToReplies, results);
        }
        return results;
      },

      _visitComment: function(parent, commentIDToReplies, results) {
        results.push(parent);

        var replies = commentIDToReplies[parent.id];
        if (!replies) { return; }
        for (var i = 0; i < replies.length; i++) {
          this._visitComment(replies[i], commentIDToReplies, results);
        }
      },

      _handleCommentHeightChange: function(e) {
        e.stopPropagation();
        this._heightChanged();
      },

      _handleCommentReply: function(e) {
        var comment = e.detail.comment;
        var quoteStr;
        if (e.detail.quote) {
          var msg = comment.message;
          var quoteStr = msg.split('\n').map(
              function(line) { return ' > ' + line; }).join('\n') + '\n\n';
        }
        var reply =
            this._newReply(comment.id, comment.line, this.path, quoteStr);
        this.push('comments', reply);

        // Allow the reply to render in the dom-repeat.
        this.async(function() {
          var commentEl = this._commentElWithDraftID(reply.__draftID);
          commentEl.editing = true;
          this.async(this._heightChanged.bind(this), 1);
        }.bind(this), 1);
      },

      _handleCommentDone: function(e) {
        var comment = e.detail.comment;
        var reply = this._newReply(comment.id, comment.line, this.path, 'Done');
        this.push('comments', reply);

        // Allow the reply to render in the dom-repeat.
        this.async(function() {
          var commentEl = this._commentElWithDraftID(reply.__draftID);
          commentEl.save();
          this.async(this._heightChanged.bind(this), 1);
        }.bind(this), 1);
      },

      _commentElWithDraftID: function(draftID) {
        var commentEls =
            Polymer.dom(this.root).querySelectorAll('gr-diff-comment');
        for (var i = 0; i < commentEls.length; i++) {
          if (commentEls[i].comment.__draftID == draftID) {
            return commentEls[i];
          }
        }
        return null;
      },

      _newReply: function(inReplyTo, line, path, opt_message) {
        var c = {
          __draft: true,
          __draftID: Math.random().toString(36),
          __date: new Date(),
          line: line,
          path: path,
          in_reply_to: inReplyTo,
        };
        if (opt_message != null) {
          c.message = opt_message;
        }
        return c;
      },

      _handleCommentDiscard: function(e) {
        // TODO(andybons): In Shadow DOM, the event bubbles up, while in Shady
        // DOM, it respects the bubbles property.
        // https://github.com/Polymer/polymer/issues/3226
        e.stopPropagation();
        var diffCommentEl = Polymer.dom(e).rootTarget;
        var idx = this._indexOf(diffCommentEl.comment, this.comments);
        if (idx == -1) {
          throw Error('Cannot find comment ' +
              JSON.stringify(diffCommentEl.comment));
        }
        this.splice('comments', idx, 1);
        if (this.comments.length == 0) {
          this.fire('discard', null, {bubbles: false});
          return;
        }
        this.async(this._heightChanged.bind(this), 1);
      },

      _heightChanged: function() {
        var height = this.$.container.offsetHeight;
        if (height == this._lastHeight) { return; }

        this.fire('height-change', {height: height}, {bubbles: false});
        this._lastHeight = height;
      },

      _indexOf: function(comment, arr) {
        for (var i = 0; i < arr.length; i++) {
          var c = arr[i];
          if ((c.__draftID != null && c.__draftID == comment.__draftID) ||
              (c.id != null && c.id == comment.id)) {
            return i;
          }
        }
        return -1;
      },

    });
  })();
  </script>
</dom-module>
