12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Use of this source code is governed by a BSD-style license that can be
32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// found in the LICENSE file.
42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis'use strict';
62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
72da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbase.require('tracks.timeline_container_track');
82da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbase.require('sorted_array_utils');
92da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbase.require('ui');
102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
112da489cd246702bee5938545b18a6f710ed214bcJamie Gennisbase.exportTo('tracks', function() {
122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  /**
142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * A track that displays a TimelineSliceGroup.
152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * @constructor
162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * @extends {TimelineContainerTrack}
172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   */
182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  var TimelineSliceGroupTrack = base.ui.define(tracks.TimelineContainerTrack);
202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  TimelineSliceGroupTrack.prototype = {
222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    __proto__: tracks.TimelineContainerTrack.prototype,
242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    decorate: function() {
262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.classList.add('timeline-slice-group-track');
272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    get group() {
302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return this.group_;
312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    set group(g) {
342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.group_ = g;
352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.updateChildTracks_();
362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    set heading(h) {
392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (this.tracks_.length)
402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        this.tracks_[0].heading = h;
412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    set tooltip(t) {
442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (this.tracks_.length)
452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        this.tracks_[0].tooltip = t;
462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    set decorateHit(f) {
492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.decorateHit_ = f;
502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.updateChildTracks_();
512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    applyCategoryFilter_: function() {
542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.updateChildTracks_();
552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    addSliceTrack_: function(slices) {
582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var track = new tracks.TimelineSliceTrack();
592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      track.slices = slices;
602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      track.decorateHit = this.decorateHit_;
612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.addTrack_(track);
622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return track;
632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    updateChildTracks_: function() {
662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!this.group_) {
672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        this.visible = false;
682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return;
692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var slices = tracing.filterSliceArray(this.categoryFilter,
722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                            this.group_.slices);
732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!slices.length) {
742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        this.visible = false;
752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return;
762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.visible = true;
782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (this.areArrayContentsSame_(this.filteredSlices_, slices))
802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return;
812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.filteredSlices_ = slices;
832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.detach();
842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.subRows_ = this.buildSubRows_(slices);
852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      for (var srI = 0; srI < this.subRows_.length; srI++) {
862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (this.subRows_[srI].length) {
872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          this.addSliceTrack_(this.subRows_[srI]);
882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        }
892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    /**
932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis     * Breaks up the list of slices into N rows, each of which is a list of
942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis     * slices that are non overlapping.
952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis     */
962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    buildSubRows_: function(slices) {
972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // This function works by walking through slices by start time.
982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //
992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // The basic idea here is to insert each slice as deep into the subrow
1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // list as it can go such that every subSlice is fully contained by its
1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // parent slice.
1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //
1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // Visually, if we start with this:
1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  0:  [    a       ]
1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  1:    [  b  ]
1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  2:    [c][d]
1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //
1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // To place this slice:
1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //               [e]
1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // We first check row 2's last item, [d]. [e] wont fit into [d] (they dont
1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // even intersect). So we go to row 1. That gives us [b], and [d] wont fit
1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // into that either. So, we go to row 0 and its last slice, [a]. That can
1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // completely contain [e], so that means we should add [e] as a subchild
1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // of [a]. That puts it on row 1, yielding:
1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  0:  [    a       ]
1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  1:    [  b  ][e]
1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  2:    [c][d]
1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //
1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // If we then get this slice:
1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //                      [f]
1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // We do the same deepest-to-shallowest walk of the subrows trying to fit
1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // it. This time, it doesn't fit in any open slice. So, we simply append
1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      // it to row 0:
1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  0:  [    a       ]  [f]
1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  1:    [  b  ][e]
1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      //  2:    [c][d]
1272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!slices.length)
1282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return [];
1292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var ops = [];
1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      for (var i = 0; i < slices.length; i++) {
1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (slices[i].subSlices)
1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          slices[i].subSlices.splice(0,
1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                     slices[i].subSlices.length);
1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        ops.push(i);
1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      ops.sort(function(ix, iy) {
1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var x = slices[ix];
1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var y = slices[iy];
1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (x.start != y.start)
1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          return x.start - y.start;
1436e58f015d94bedc1072f08b30f0a5a6ac6e653efJamie Gennis
1446e58f015d94bedc1072f08b30f0a5a6ac6e653efJamie Gennis        // Elements get inserted into the slices array in order of when the
1456e58f015d94bedc1072f08b30f0a5a6ac6e653efJamie Gennis        // slices end.  Because slices must be properly nested, we break
1466e58f015d94bedc1072f08b30f0a5a6ac6e653efJamie Gennis        // start-time ties by assuming that the elements appearing earlier in
1476e58f015d94bedc1072f08b30f0a5a6ac6e653efJamie Gennis        // the slices array (and thus ending earlier) start later.
1486e58f015d94bedc1072f08b30f0a5a6ac6e653efJamie Gennis        return iy - ix;
1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      });
1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var subRows = [[]];
1522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.badSlices_ = [];  // TODO(simonjam): Connect this again.
1532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      for (var i = 0; i < ops.length; i++) {
1552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var op = ops[i];
1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var slice = slices[op];
1572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        // Try to fit the slice into the existing subrows.
1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var inserted = false;
1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        for (var j = subRows.length - 1; j >= 0; j--) {
1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          if (subRows[j].length == 0)
1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            continue;
1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var insertedSlice = subRows[j][subRows[j].length - 1];
1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          if (slice.start < insertedSlice.start) {
1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            this.badSlices_.push(slice);
1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            inserted = true;
1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          if (slice.start >= insertedSlice.start &&
1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              slice.end <= insertedSlice.end) {
1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            // Insert it into subRow j + 1.
1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            while (subRows.length <= j + 1)
1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              subRows.push([]);
1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            subRows[j + 1].push(slice);
1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            if (insertedSlice.subSlices)
1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              insertedSlice.subSlices.push(slice);
1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            inserted = true;
1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            break;
1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        }
1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (inserted)
1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          continue;
1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        // Append it to subRow[0] as a root.
1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        subRows[0].push(slice);
1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return subRows;
1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    areArrayContentsSame_: function(a, b) {
1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!a || !b)
1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return false;
1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!a.length || !b.length)
1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return false;
1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (a.length != b.length)
1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return false;
1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      for (var i = 0; i < a.length; ++i) {
1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (a[i] != b[i])
2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          return false;
2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return true;
2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    }
2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  };
2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return {
2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    TimelineSliceGroupTrack: TimelineSliceGroupTrack
2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  };
2092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis});
210