<!--
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">
<link rel="import" href="../../core/gr-reporting/gr-reporting.html">
<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
<link rel="import" href="../gr-diff-processor/gr-diff-processor.html">
<link rel="import" href="../gr-ranged-comment-layer/gr-ranged-comment-layer.html">
<link rel="import" href="../gr-syntax-layer/gr-syntax-layer.html">

<dom-module id="gr-diff-builder">
  <template>
    <div class="contentWrapper">
      <content></content>
    </div>
    <gr-ranged-comment-layer
        id="rangeLayer"
        comments="[[comments]]"></gr-ranged-comment-layer>
    <gr-syntax-layer
        id="syntaxLayer"
        diff="[[diff]]"></gr-syntax-layer>
    <gr-diff-processor
        id="processor"
        groups="{{_groups}}"></gr-diff-processor>
    <gr-reporting id="reporting"></gr-reporting>
  </template>
  <script src="../gr-diff/gr-diff-line.js"></script>
  <script src="../gr-diff/gr-diff-group.js"></script>
  <script src="../gr-diff-highlight/gr-annotation.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',
      };

      var TimingLabel = {
        TOTAL: 'Diff Total Render',
        CONTENT: 'Diff Content Render',
        SYNTAX: 'Diff Syntax Render',
      };

      // If any line of the diff is more than the character limit, then disable
      // syntax highlighting for the entire file.
      var SYNTAX_MAX_LINE_LENGTH = 500;

      var TRAILING_WHITESPACE_PATTERN = /\s+$/;

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

        /**
         * Fired when the diff begins rendering.
         *
         * @event render-start
         */

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

        properties: {
          diff: Object,
          viewMode: String,
          comments: Object,
          isImageDiff: Boolean,
          baseImage: Object,
          revisionImage: Object,
          _builder: Object,
          _groups: Array,
          _layers: Array,
          _showTabs: Boolean,
        },

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

        observers: [
          '_groupsChanged(_groups.splices)',
        ],

        attached: function() {
          // Setup annotation layers.
          this._layers = [
            this._createTrailingWhitespaceLayer(),
            this.$.syntaxLayer,
            this._createIntralineLayer(),
            this._createTabIndicatorLayer(),
            this.$.rangeLayer,
          ];

          this.async(function() {
            this._preRenderThread();
          });
        },

        render: function(comments, prefs) {
          this.$.syntaxLayer.enabled = prefs.syntax_highlighting;
          this._showTabs = !!prefs.show_tabs;
          this._showTrailingWhitespace = !!prefs.show_whitespace_errors;

          // Stop the processor (if it's running).
          this.$.processor.cancel();
          this.$.syntaxLayer.cancel();

          this._builder = this._getDiffBuilder(this.diff, comments, prefs);

          this.$.processor.context = prefs.context;
          this.$.processor.keyLocations = this._getCommentLocations(comments);

          this._clearDiffContent();
          this._builder.addColumns(this.diffElement, prefs.font_size);

          var reporting = this.$.reporting;

          reporting.time(TimingLabel.TOTAL);
          reporting.time(TimingLabel.CONTENT);
          this.fire('render-start');
          return this.$.processor.process(this.diff.content).then(function() {
            if (this.isImageDiff) {
              this._builder.renderDiffImages();
            }

            if (this._anyLineTooLong()) {
              this.$.syntaxLayer.enabled = false;
            }

            reporting.timeEnd(TimingLabel.CONTENT);
            reporting.time(TimingLabel.SYNTAX);
            this.$.syntaxLayer.process().then(function() {
              reporting.timeEnd(TimingLabel.SYNTAX);
              reporting.timeEnd(TimingLabel.TOTAL);
            });
            this.fire('render');
          }.bind(this));
        },

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

        getLineNumberByChild: function(node) {
          var lineEl = this.getLineElByChild(node);
          return lineEl ?
              parseInt(lineEl.getAttribute('data-value'), 10) : 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) {
          return this._builder.getContentByLine(lineNumber, opt_side, opt_root);
        },

        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 result = [];
          this._builder.findLinesByRange(startLine, endLine, opt_side, null,
              result);
          return result;
        },

        getCommentThreadByLine: function(lineNumber, opt_side, opt_root) {
          var content = this.getContentByLine(lineNumber, opt_side, opt_root);
          return this.getCommentThreadByContentEl(content);
        },

        getCommentThreadByContentEl: function(contentEl) {
          if (contentEl.classList.contains('contentText')) {
            contentEl = contentEl.parentElement;
          }
          return contentEl.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);
        },

        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, this._layers);
          } else if (this.viewMode === DiffViewMode.UNIFIED) {
            return new GrDiffBuilderUnified(
                diff, comments, prefs, this.diffElement, this._layers);
          }
          throw Error('Unsupported diff view mode: ' + this.viewMode);
        },

        _clearDiffContent: function() {
          this.diffElement.innerHTML = null;
        },

        _getCommentLocations: function(comments) {
          var result = {
            left: {},
            right: {},
          };
          for (var side in comments) {
            if (side !== GrDiffBuilder.Side.LEFT &&
                side !== GrDiffBuilder.Side.RIGHT) {
              continue;
            }
            comments[side].forEach(function(c) {
              result[side][c.line || GrDiffLine.FILE] = true;
            });
          }
          return result;
        },

        _groupsChanged: function(changeRecord) {
          if (!changeRecord) { return; }
          changeRecord.indexSplices.forEach(function(splice) {
            var group;
            for (var i = 0; i < splice.addedCount; i++) {
              group = splice.object[splice.index + i];
              this._builder.groups.push(group);
              this._builder.emitGroup(group);
            }
          }, this);
        },

        _createIntralineLayer: function() {
          return {
            // Take a DIV.contentText element and a line object with intraline
            // differences to highlight and apply them to the element as
            // annotations.
            annotate: function(el, line) {
              var HL_CLASS = 'style-scope gr-diff intraline';
              line.highlights.forEach(function(highlight) {
                // The start and end indices could be the same if a highlight is
                // meant to start at the end of a line and continue onto the
                // next one. Ignore it.
                if (highlight.startIndex === highlight.endIndex) { return; }

                // If endIndex isn't present, continue to the end of the line.
                var endIndex = highlight.endIndex === undefined ?
                    line.text.length : highlight.endIndex;

                GrAnnotation.annotateElement(
                    el,
                    highlight.startIndex,
                    endIndex - highlight.startIndex,
                    HL_CLASS);
              });
            },
          };
        },

        _createTabIndicatorLayer: function() {
          var show = function() { return this._showTabs; }.bind(this);
          return {
            annotate: function(el, line) {
              // If visible tabs are disabled, do nothing.
              if (!show()) { return; }

              // Find and annotate the locations of tabs.
              var split = line.text.split('\t');
              if (!split) { return; }
              for (var i = 0, pos = 0; i < split.length - 1; i++) {
                // Skip forward by the length of the content
                pos += split[i].length;

                GrAnnotation.annotateElement(el, pos, 1,
                    'style-scope gr-diff tab-indicator');

                // Skip forward by one tab character.
                pos++;
              }
            },
          };
        },

        _createTrailingWhitespaceLayer: function() {
          var show = function() {
            return this._showTrailingWhitespace;
          }.bind(this);

          return {
            annotate: function(el, line) {
              if (!show()) { return; }

              var match = line.text.match(TRAILING_WHITESPACE_PATTERN);
              if (match) {
                // Normalize string positions in case there is unicode before or
                // within the match.
                var index = GrAnnotation.getStringLength(
                    line.text.substr(0, match.index));
                var length = GrAnnotation.getStringLength(match[0]);
                GrAnnotation.annotateElement(el, index, length,
                    'style-scope gr-diff trailing-whitespace');
              }
            },
          };
        },

        /**
         * In pages with large diffs, creating the first comment thread can be
         * slow because nested Polymer elements (particularly
         * iron-autogrow-textarea) add style elements to the document head,
         * which, in turn, triggers a reflow on the page. Create a hidden
         * thread, attach it to the page, and remove it so the stylesheet will
         * already exist and the user's comment will be quick to load.
         * @see https://gerrit-review.googlesource.com/c/82213/
         */
        _preRenderThread: function() {
          var thread = document.createElement('gr-diff-comment-thread');
          thread.setAttribute('hidden', true);
          thread.addDraft();
          var parent = Polymer.dom(this.root);
          parent.appendChild(thread);
          Polymer.dom.flush();
          parent.removeChild(thread);
        },

        /**
         * @return {Boolean} whether any of the lines in _groups are longer
         * than SYNTAX_MAX_LINE_LENGTH.
         */
        _anyLineTooLong: function() {
          return this._groups.reduce(function(acc, group) {
            return acc || group.lines.reduce(function(acc, line) {
              return acc || line.text.length >= SYNTAX_MAX_LINE_LENGTH;
            }, false);
          }, false);
        },
      });
    })();
  </script>
</dom-module>
