<!--
@license
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="../../shared/gr-js-api-interface/gr-js-api-interface.html">
<link rel="import" href="../gr-diff-processor/gr-diff-processor.html">
<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.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">
      <slot></slot>
    </div>
    <gr-ranged-comment-layer
        id="rangeLayer"
        comment-ranges="[[commentRanges]]"></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>
    <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
  </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 src="gr-diff-builder-binary.js"></script>
  <script>
    (function() {
      'use strict';

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

      const 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.
      const SYNTAX_MAX_LINE_LENGTH = 500;

      // Disable syntax highlighting if the overall diff is too large.
      const SYNTAX_MAX_DIFF_LENGTH = 20000;

      const 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
         */

        /**
         * Fired when the diff finishes rendering text content, but not
         * necessarily syntax highlights.
         *
         * @event render-content
         */

        properties: {
          diff: Object,
          diffPath: String,
          changeNum: String,
          patchNum: String,
          viewMode: String,
          isImageDiff: Boolean,
          baseImage: Object,
          revisionImage: Object,
          parentIndex: Number,
          path: String,
          projectName: String,

          _builder: Object,
          _groups: Array,
          _layers: Array,
          _showTabs: Boolean,
          /** @type {!Array<!Gerrit.HoveredRange>} */
          commentRanges: {
            type: Array,
          },
        },

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

        get _commentThreadElements() {
          return this.queryAllEffectiveChildren('.comment-thread');
        },

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

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

          // Get layers from plugins (if any).
          for (const pluginLayer of this.$.jsAPI.getDiffLayers(
              this.diffPath, this.changeNum, this.patchNum)) {
            layers.push(pluginLayer);
          }

          this._layers = layers;
        },

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

          // Stop the processor and syntax layer (if they're running).
          this.cancel();

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

          this.$.processor.context = prefs.context;
          this.$.processor.keyLocations = keyLocations;

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

          const reporting = this.$.reporting;
          const isBinary = !!(this.isImageDiff || this.diff.binary);

          reporting.time(TimingLabel.TOTAL);
          reporting.time(TimingLabel.CONTENT);
          this.dispatchEvent(new CustomEvent('render-start', {bubbles: true}));
          return this.$.processor.process(this.diff.content, isBinary)
              .then(() => {
                if (this.isImageDiff) {
                  this._builder.renderDiff();
                }
                this.dispatchEvent(new CustomEvent('render-content',
                    {bubbles: true}));

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

                reporting.timeEnd(TimingLabel.CONTENT);
                reporting.time(TimingLabel.SYNTAX);
                return this.$.syntaxLayer.process().then(() => {
                  reporting.timeEnd(TimingLabel.SYNTAX);
                  reporting.timeEnd(TimingLabel.TOTAL);
                  this.dispatchEvent(
                      new CustomEvent('render', {bubbles: true}));
                });
              });
        },

        getLineElByChild(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(node) {
          const lineEl = this.getLineElByChild(node);
          return lineEl ?
              parseInt(lineEl.getAttribute('data-value'), 10) :
              null;
        },

        getContentByLine(lineNumber, opt_side, opt_root) {
          return this._builder.getContentByLine(lineNumber, opt_side, opt_root);
        },

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

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

        getContentsByLineRange(startLine, endLine, opt_side) {
          const result = [];
          this._builder.findLinesByRange(startLine, endLine, opt_side, null,
              result);
          return result;
        },

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

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

        showContext(newGroups, sectionEl) {
          const groups = this._builder.groups;

          const contextIndex = groups.findIndex(group =>
            group.element === sectionEl
          );
          groups.splice(...[contextIndex, 1].concat(newGroups));

          for (const newGroup of newGroups) {
            this._builder.emitGroup(newGroup, sectionEl);
          }
          sectionEl.parentNode.removeChild(sectionEl);

          this.async(() => this.fire('render-content'), 1);
        },

        cancel() {
          this.$.processor.cancel();
          this.$.syntaxLayer.cancel();
        },

        _handlePreferenceError(pref) {
          const message = `The value of the '${pref}' user preference is ` +
              `invalid. Fix in diff preferences`;
          this.dispatchEvent(new CustomEvent('show-alert', {
            detail: {
              message,
            }, bubbles: true}));
          throw Error(`Invalid preference value: ${pref}`);
        },

        _getDiffBuilder(diff, prefs) {
          if (isNaN(prefs.tab_size) || prefs.tab_size <= 0) {
            this._handlePreferenceError('tab size');
            return;
          }

          if (isNaN(prefs.line_length) || prefs.line_length <= 0) {
            this._handlePreferenceError('diff width');
            return;
          }

          let builder = null;
          if (this.isImageDiff) {
            builder = new GrDiffBuilderImage(diff,
              this._commentThreadElements, prefs, this.diffElement,
              this.baseImage, this.revisionImage);
          } else if (diff.binary) {
            // If the diff is binary, but not an image.
            return new GrDiffBuilderBinary(diff,
                this._commentThreadElements, prefs, this.diffElement);
          } else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
            builder = new GrDiffBuilderSideBySide(diff,
                this._commentThreadElements, prefs, this.diffElement,
                this._layers);
          } else if (this.viewMode === DiffViewMode.UNIFIED) {
            builder = new GrDiffBuilderUnified(diff,
                this._commentThreadElements, prefs, this.diffElement,
                this._layers);
          }
          if (!builder) {
            throw Error('Unsupported diff view mode: ' + this.viewMode);
          }
          return builder;
        },

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

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

        _createIntralineLayer() {
          return {
            // Take a DIV.contentText element and a line object with intraline
            // differences to highlight and apply them to the element as
            // annotations.
            annotate(el, line) {
              const HL_CLASS = 'style-scope gr-diff intraline';
              for (const highlight of line.highlights) {
                // 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) { continue; }

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

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

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

              // Find and annotate the locations of tabs.
              const split = line.text.split('\t');
              if (!split) { return; }
              for (let 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() {
          const show = function() {
            return this._showTrailingWhitespace;
          }.bind(this);

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

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

        /**
         * @return {boolean} whether any of the lines in _groups are longer
         * than SYNTAX_MAX_LINE_LENGTH.
         */
        _anyLineTooLong() {
          return this._groups.reduce((acc, group) => {
            return acc || group.lines.reduce((acc, line) => {
              return acc || line.text.length >= SYNTAX_MAX_LINE_LENGTH;
            }, false);
          }, false);
        },

        _diffTooLargeForSyntax() {
          return this._anyLineTooLong() ||
              this.getDiffLength() > SYNTAX_MAX_DIFF_LENGTH;
        },

        setBlame(blame) {
          if (!this._builder || !blame) { return; }
          this._builder.setBlame(blame);
        },

        /**
         * Get the approximate length of the diff as the sum of the maximum
         * length of the chunks.
         * @return {number}
         */
        getDiffLength() {
          return this.diff.content.reduce((sum, sec) => {
            if (sec.hasOwnProperty('ab')) {
              return sum + sec.ab.length;
            } else {
              return sum + Math.max(
                  sec.hasOwnProperty('a') ? sec.a.length : 0,
                  sec.hasOwnProperty('b') ? sec.b.length : 0);
            }
          }, 0);
        },
      });
    })();
  </script>
</dom-module>
