<!-- The <plot-sk> custom element declaration.

  Attributes:
    width - The width of the element in px.

    height - The height of the element in px.

  Methods:
    addTraces(traces) - Adds the given traces to the plot. Note that the
      'label' is also known as the trace id.

      [
        {
          data: [[1, 1.661208], [4, 1.00475], ...],
          label: "Arm64:GCC:GPU:TegraK1:Nexus9:Android:DeferredSurfaceCopy_discardable_640_480:msaa4",
          _params: {"GL_RENDERER":"NVIDIA Tegra", "GL_SHADING_LANGUAGE_VERSION": "OpenGL ES GLSL ES 3.10", ...}
        },
        {
          data: [[0, 0.844692],[1, 0.853242],[2, 0.84812], [4, 0.843628], ...],
          label: "x86_64:Clang:CPU:AVX:MacMini6.2:Mac10.9:DeferredSurfaceCopy_discardable_640_480:8888",
          _params: {"arch":"x86_64", "bench_type":"micro", ...}
        },
        ...
      ]

    clear() - Remove all traces.

    remove(id) - Remove a trace with the given id.

    only(id)   - Remove all traces but the one with the given id.

    removeHighlighted() - Remove all traces currently highlighted.

    removeUnHighlighted() - Remove all traces currently unhighlighted.

    setBackgroundInfo(ticks, skps, lastCommitIndex) - Sets the tick marks,
        the skp background banding, and the index of the last commit.

    highlightGroup(key, value) - Highlight all traces that have params
        that match the given key and value.

    clearHighlight - Remove all highlighting.

    getKeys() - Return the keys of all the traces being displayed.

    setStepIndex(x) - If set, this is the index into the commits at which to
       draw a line indicating a specific commit.

  Events:
    selected - A point on a trace has been clicked on.
      detail.begin,
      detail.end    - The indices of the point clicked and
         the index of the previous data point, useful for looking
         up the commits that correspond to the data points. Note that
         detail.end can be undefined if there is no previous data point.
      detail.id     - The key of the trace clicked on.
      detail.params -  The params for the selected trace.

    highlighted - The mouse is hovering over a trace.
      detail.id     - The key of the trace clicked on.
      detail.value  - The value of the point we are near.

-->

<link rel="import" href="plot-simple.html">

<dom-module id="plot-sk">
  <template>
    <plot-simple-sk width$="{{width}}" height$="{{height}}" id=plot></plot-simple-sk>
  </template>
</dom-module>

<script>
  Polymer({
    is: 'plot-sk',

    properties: {
      width: {
        type: Number,
        value: 800,
        reflectToAttribute: true,
      },
      height: {
        type: Number,
        value: 600,
        reflectToAttribute: true,
      },
    },

    ready: function () {
      // Store the data for each trace.
      this._traces = {};

      // The index of the last valid commit.
      this._lastCommitIndex = 0;

      this.$.plot.addEventListener('trace_focused', function(e) {
        var detail = {
          id: e.detail.id,
          value: e.detail.value,
        };
        this.dispatchEvent(new CustomEvent('highlighted', {detail: detail, bubbles: true}));
      }.bind(this));

      this.$.plot.addEventListener('trace_selected', function(e) {
        var t = this._traces[e.detail.id];

        var beginIndex = t.data[e.detail.index][0];
        var endIndex = undefined;
        if (beginIndex >= 0) {
          endIndex = beginIndex;
          beginIndex = t.data[e.detail.index-1][0];
        }

        var detail = {
          begin: beginIndex,
          end: endIndex,
          id: e.detail.id,
          params: t._params,
        };
        this.dispatchEvent(new CustomEvent('selected', {detail: detail, bubbles: true}));
      }.bind(this));
    },

    addTraces: function (traces) {
      var plotData = {};
      for (var i = traces.length - 1; i >= 0; i--) {
        var t = traces[i];
        if (!this._traces.hasOwnProperty(t.label)) {
          this._traces[t.label] = t;
          plotData[t.label] = t.data;
        }
      }
      this.$.plot.addLines(plotData);
    },

    setStepIndex: function(x) {
      this.$.plot.setXBar(x);
      this.$.plot.resetAxes();
    },

    getKeys: function () {
      return Object.keys(this._traces);
    },

    clear: function () {
      this.$.plot.removeAll();
      this._traces = [];
    },

    resetAxes: function () {
      this.$.plot.resetAxes();
    },

    removeHighlighted: function () {
      var ids = this.$.plot.highlighted();
      var toadd = [];
      Object.keys(this._traces).forEach(function(key) {
        var t = this._traces[key];
        if (ids.indexOf(t.label) == -1) {
          toadd.push(t);
        }
      }.bind(this));
      this.clear();
      this.addTraces(toadd);
    },

    removeUnHighlighted: function () {
      var ids = this.$.plot.highlighted();
      var toadd = [];
      Object.keys(this._traces).forEach(function(key) {
        var t = this._traces[key];
        if (ids.indexOf(t.label) != -1) {
          toadd.push(t);
        }
      }.bind(this));
      this.clear();
      this.addTraces(toadd);
    },

    remove: function (id) {
      this.$.plot.deleteLine(id);
      delete this._traces[id];
    },

    only: function (id) {
      var trace = this._traces[id];
      if (trace) {
        this.clear();
        this.addTraces([trace]);
      }
    },

    clearHighlight: function() {
      this.$.plot.clearHighlight();
    },

    highlightGroup: function (key, value) {
      this.$.plot.clearHighlight();
      var ids = [];
      Object.keys(this._traces).forEach(function(id) {
        if (this._traces[id]._params[key] && this._traces[id]._params[key] == value) {
          ids.push(id);
        }
      }.bind(this));
      this.$.plot.setHighlight(ids);
    },

    setBackgroundInfo: function (ticks, skps, lastCommitIndex) {
      this.$.plot.setTicks(ticks);
      var bands = [];
      for (var i = 2, len = skps.length; i < len; i+=2) {
        bands.push([skps[i-1], skps[i]]);
      }
      this.$.plot.setBanding(bands);

      // TODO Add ability to set max-x in plot-simple-sk, then set it here
      // to lastCommitIndex.
      this._lastCommitIndex = lastCommitIndex;
    },
  });
</script>
