/**
 * @license
 * Copyright (C) 2019 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';

  /** @enum {string} */
  Gerrit.CoverageType = {
    /**
     * start_character and end_character of the range will be ignored for this
     * type.
     */
    COVERED: 'COVERED',
    /**
     * start_character and end_character of the range will be ignored for this
     * type.
     */
    NOT_COVERED: 'NOT_COVERED',
    PARTIALLY_COVERED: 'PARTIALLY_COVERED',
    /**
     * You don't have to use this. If there is no coverage information for a
     * range, then it implicitly means NOT_INSTRUMENTED. start_character and
     * end_character of the range will be ignored for this type.
     */
    NOT_INSTRUMENTED: 'NOT_INSTRUMENTED',
  };

  /**
   * @typedef {{
   *   side: string,
   *   type: Gerrit.CoverageType,
   *   code_range: Gerrit.Range,
   * }}
   */
  Gerrit.CoverageRange;

  Polymer({
    is: 'gr-coverage-layer',

    properties: {
      /**
       * Must be sorted by code_range.start_line.
       * Must only contain ranges that match the side.
       *
       * @type {!Array<!Gerrit.CoverageRange>}
       */
      coverageRanges: Array,
      side: String,

      /**
       * We keep track of the line number from the previous annotate() call,
       * and also of the index of the coverage range that had matched.
       * annotate() calls are coming in with increasing line numbers and
       * coverage ranges are sorted by line number. So this is a very simple
       * and efficient way for finding the coverage range that matches a given
       * line number.
       */
      _lineNumber: {
        type: Number,
        value: 0,
      },
      _index: {
        type: Number,
        value: 0,
      },
    },

    /**
     * Layer method to add annotations to a line.
     *
     * @param {!HTMLElement} el Not used for this layer.
     * @param {!HTMLElement} lineNumberEl The <td> element with the line number.
     * @param {!Object} line Not used for this layer.
     */
    annotate(el, lineNumberEl, line) {
      if (!lineNumberEl || !lineNumberEl.classList.contains(this.side)) {
        return;
      }
      const elementLineNumber = parseInt(
          lineNumberEl.getAttribute('data-value'), 10);
      if (!elementLineNumber || elementLineNumber < 1) return;

      // If the line number is smaller than before, then we have to reset our
      // algorithm and start searching the coverage ranges from the beginning.
      // That happens for example when you expand diff sections.
      if (elementLineNumber < this._lineNumber) {
        this._index = 0;
      }
      this._lineNumber = elementLineNumber;

      // We simply loop through all the coverage ranges until we find one that
      // matches the line number.
      while (this._index < this.coverageRanges.length) {
        const coverageRange = this.coverageRanges[this._index];

        // If the line number has moved past the current coverage range, then
        // try the next coverage range.
        if (this._lineNumber > coverageRange.code_range.end_line) {
          this._index++;
          continue;
        }

        // If the line number has not reached the next coverage range (and the
        // range before also did not match), then this line has not been
        // instrumented. Nothing to do for this line.
        if (this._lineNumber < coverageRange.code_range.start_line) {
          return;
        }

        // The line number is within the current coverage range. Style it!
        lineNumberEl.classList.add(coverageRange.type);
        return;
      }
    },
  });
})();

@@ -1301,16 +1301,329 @@
 ,%0A  %7D;%0A%0A
+  const TOOLTIP_MAP = new Map(%5B%0A    %5BGerrit.CoverageType.COVERED, 'Covered by tests.'%5D,%0A    %5BGerrit.CoverageType.NOT_COVERED, 'Not covered by tests.'%5D,%0A    %5BGerrit.CoverageType.PARTIALLY_COVERED, 'Partially covered by tests.'%5D,%0A    %5BGerrit.CoverageType.NOT_INSTRUMENTED, 'Not instrumented by any tests.'%5D,%0A  %5D);%0A%0A
   /**%0A  
@@ -4444,16 +4444,82 @@
 .type);%0A
+        lineNumberEl.title = TOOLTIP_MAP.get(coverageRange.type);%0A
         

Add tooltips to coverage layer line elements