<!--
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.
-->
<link rel="import" href="../../../bower_components/polymer/polymer.html">

<dom-module id="gr-diff-builder">
  <template>
    <div class="contentWrapper">
      <content></content>
    </div>
  </template>
  <script src="../gr-diff/gr-diff-line.js"></script>
  <script src="../gr-diff/gr-diff-group.js"></script>
  <script src="gr-diff-builder.js"></script>
  <script src="gr-diff-builder-side-by-side.js"></script>
  <script src="gr-diff-builder-unified.js"></script>
  <script src="gr-diff-builder-image.js"></script>
  <script>
    (function() {
      'use strict';

      var DiffViewMode = {
        SIDE_BY_SIDE: 'SIDE_BY_SIDE',
        UNIFIED: 'UNIFIED_DIFF',
      };

      Polymer({
        is: 'gr-diff-builder',

        /**
         * Fired when the diff is rendered.
         *
         * @event render
         */

        properties: {
          viewMode: String,
          isImageDiff: Boolean,
          baseImage: Object,
          revisionImage: Object,
          _builder: Object,
        },

        get diffElement() {
          return this.queryEffectiveChildren('#diffTable');
        },

        render: function(diff, comments, prefs) {
          this._builder = this._getDiffBuilder(diff, comments, prefs);
          this._renderDiff();
        },

        getLineElByChild: function(node) {
          while (node) {
            if (node instanceof Element) {
              if (node.classList.contains('lineNum')) {
                return node;
              }
              if (node.classList.contains('section')) {
                return null;
              }
            }
            node = node.previousSibling || node.parentElement;
          }
          return null;
        },

        renderLineRange: function(startLine, endLine, opt_side) {
          var groups =
              this._builder.getGroupsByLineRange(startLine, endLine, opt_side);
          groups.forEach(function(group) {
            var newElement = this._builder.buildSectionElement(group);
            var oldElement = group.element;

            // Transfer comment threads from existing section to new one.
            var threads = Polymer.dom(newElement).querySelectorAll(
                'gr-diff-comment-thread');
            threads.forEach(function(threadEl) {
              var lineEl = this.getLineElByChild(threadEl, oldElement);
              if (!lineEl) { // New comment thread.
                return;
              }
              var side = this.getSideByLineEl(lineEl);
              var line = lineEl.getAttribute('data-value');
              var oldThreadEl =
                  this.getCommentThreadByLine(line, side, oldElement);
              threadEl.parentNode.replaceChild(oldThreadEl, threadEl);
            }, this);

            // Replace old group elements with new ones.
            group.element.parentNode.replaceChild(newElement, group.element);
            group.element = newElement;
          }, this);

          this.async(function() {
            this.fire('render');
          }, 1);
        },

        getContentByLine: function(lineNumber, opt_side, opt_root) {
          var root = Polymer.dom(opt_root || this.diffElement);
          var sideSelector = !!opt_side ? ('.' + opt_side) : '';
          return root.querySelector('td.lineNum[data-value="' + lineNumber +
              '"]' + sideSelector + ' ~ td.content');
        },

        getContentByLineEl: function(lineEl) {
          var root = Polymer.dom(lineEl.parentElement);
          var side = this.getSideByLineEl(lineEl);
          var line = lineEl.getAttribute('data-value');
          return this.getContentByLine(line, side, root);
        },

        getLineElByNumber: function(lineNumber, opt_side) {
          var sideSelector = !!opt_side ? ('.' + opt_side) : '';
          return this.diffElement.querySelector(
              '.lineNum[data-value="' + lineNumber + '"]' + sideSelector);
        },

        getContentsByLineRange: function(startLine, endLine, opt_side) {
          var groups =
              this._builder.getGroupsByLineRange(startLine, endLine, opt_side);
          // In each group, search Element for lines in range.
          return groups.reduce((function(acc, group) {
            for (var line = startLine; line <= endLine; line++) {
              var content =
                  this.getContentByLine(line, opt_side, group.element);
              if (content) {
                acc.push(content);
              }
            }
            return acc;
          }).bind(this), []);
        },

        getCommentThreadByLine: function(lineNumber, opt_side, opt_root) {
          var root = Polymer.dom(opt_root || this.diffElement);
          var sideSelector = !!opt_side ? ('.' + opt_side) : '';
          var content = this.getContentByLine(lineNumber, opt_side, opt_root);
          return content.querySelector('gr-diff-comment-thread');
        },

        getSideByLineEl: function(lineEl) {
          return lineEl.classList.contains(GrDiffBuilder.Side.RIGHT) ?
              GrDiffBuilder.Side.RIGHT : GrDiffBuilder.Side.LEFT;
        },

        createCommentThread: function(changeNum, patchNum, path, side,
            projectConfig) {
          return this._builder.createCommentThread(changeNum, patchNum, path,
              side, projectConfig);
        },

        emitGroup: function(group, sectionEl) {
          this._builder.emitGroup(group, sectionEl);
        },

        emitDiff: function() {
          this._builder.emitDiff();
        },

        showContext: function(newGroups, sectionEl) {
          var groups = this._builder._groups;
          // TODO(viktard): Polyfill findIndex for IE10.
          var contextIndex = groups.findIndex(function(group) {
            return group.element == sectionEl;
          });
          groups.splice.apply(groups, [contextIndex, 1].concat(newGroups));

          newGroups.forEach(function(newGroup) {
            this._builder.emitGroup(newGroup, sectionEl);
          }, this);
          sectionEl.parentNode.removeChild(sectionEl);

          this.async(function() {
            this.fire('render');
          }, 1);
        },

        _getDiffBuilder: function(diff, comments, prefs) {
          if (this.isImageDiff) {
            return new GrDiffBuilderImage(diff, comments, prefs,
                this.diffElement, this.baseImage, this.revisionImage);
          } else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
            return new GrDiffBuilderSideBySide(
                diff, comments, prefs, this.diffElement);
          } else if (this.viewMode === DiffViewMode.UNIFIED) {
            return new GrDiffBuilderUnified(
                diff, comments, prefs, this.diffElement);
          }
          throw Error('Unsupported diff view mode: ' + this.viewMode);
        },

        _renderDiff: function() {
          this._clearDiffContent();
          this.emitDiff();
          this.async(function() {
            this.fire('render');
          }, 1);
        },

        _clearDiffContent: function() {
          this.diffElement.innerHTML = null;
        },
      });
    })();
  </script>
</dom-module>
