1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5'use strict';
6
7base.requireStylesheet('tracing.analysis.analysis_results');
8
9base.require('tracing.analysis.util');
10base.require('tracing.analysis.analysis_link');
11base.require('tracing.analysis.generic_object_view');
12base.require('ui');
13
14base.exportTo('tracing.analysis', function() {
15  var AnalysisResults = ui.define('div');
16
17  AnalysisResults.prototype = {
18    __proto__: HTMLDivElement.prototype,
19
20    decorate: function() {
21      this.className = 'analysis-results';
22    },
23
24    clear: function() {
25      this.textContent = '';
26    },
27
28    createSelectionChangingLink: function(text, selectionGenerator,
29                                          opt_tooltip) {
30      var el = this.ownerDocument.createElement('a');
31      tracing.analysis.AnalysisLink.decorate(el);
32      el.textContent = text;
33      el.selectionGenerator = selectionGenerator;
34      if (opt_tooltip)
35        el.title = opt_tooltip;
36      return el;
37    },
38
39    appendElement_: function(parent, tagName, opt_text) {
40      var n = parent.ownerDocument.createElement(tagName);
41      parent.appendChild(n);
42      if (opt_text != undefined)
43        n.textContent = opt_text;
44      return n;
45    },
46
47    appendText_: function(parent, text) {
48      var textElement = parent.ownerDocument.createTextNode(text);
49      parent.appendChild(textNode);
50      return textNode;
51    },
52
53    appendTableCell_: function(table, row, cellnum, text) {
54      var td = this.appendElement_(row, 'td', text);
55      td.className = table.className + '-col-' + cellnum;
56      return td;
57    },
58
59    appendTableCell: function(table, row, text) {
60      return this.appendTableCell_(table, row, row.children.length, text);
61    },
62
63    appendTableCellWithTooltip_: function(table, row, cellnum, text, tooltip) {
64      if (tooltip) {
65        var td = this.appendElement_(row, 'td');
66        td.className = table.className + '-col-' + cellnum;
67        var span = this.appendElement_(td, 'span', text);
68        span.className = 'tooltip';
69        span.title = tooltip;
70        return td;
71      } else {
72        this.appendTableCell_(table, row, cellnum, text);
73      }
74    },
75
76    /**
77     * Adds a table with the given className.
78     * @return {HTMLTableElement} The newly created table.
79     */
80    appendTable: function(className, numColumns) {
81      var table = this.appendElement_(this, 'table');
82      table.headerRow = this.appendElement_(table, 'tr');
83      table.className = className + ' analysis-table';
84      table.numColumns = numColumns;
85      return table;
86    },
87
88    /**
89     * Creates and appends a row to |table| with a left-aligned |label]
90     * header that spans all columns.
91     */
92    appendTableHeader: function(table, label) {
93      var th = this.appendElement_(table.headerRow, 'th', label);
94      th.className = 'analysis-table-header';
95    },
96
97    appendTableRow: function(table) {
98      return this.appendElement_(table, 'tr');
99    },
100
101    /**
102     * Creates and appends a row to |table| with a left-aligned |label]
103     * in the first column and an optional |opt_value| in the second
104     * column.
105     */
106    appendSummaryRow: function(table, label, opt_value) {
107      var row = this.appendElement_(table, 'tr');
108      row.className = 'analysis-table-row';
109
110      this.appendTableCell_(table, row, 0, label);
111
112      if (opt_value !== undefined) {
113        var objectView = new tracing.analysis.GenericObjectView();
114        objectView.object = opt_value;
115        objectView.classList.add('analysis-table-col-1');
116        objectView.style.display = 'table-cell';
117        row.appendChild(objectView);
118      } else {
119        this.appendTableCell_(table, row, 1, '');
120      }
121      for (var i = 2; i < table.numColumns; i++)
122        this.appendTableCell_(table, row, i, '');
123    },
124
125    /**
126     * Adds a spacing row to spread out results.
127     */
128    appendSpacingRow: function(table) {
129      var row = this.appendElement_(table, 'tr');
130      row.className = 'analysis-table-row';
131      for (var i = 0; i < table.numColumns; i++)
132        this.appendTableCell_(table, row, i, ' ');
133    },
134
135    /**
136     * Creates and appends a row to |table| with a left-aligned |label]
137     * in the first column and a millisecvond |time| value in the second
138     * column.
139     */
140    appendSummaryRowTime: function(table, label, time) {
141      this.appendSummaryRow(table, label,
142                            tracing.analysis.tsRound(time) + ' ms');
143    },
144
145    /**
146     * Creates and appends a row to |table| that summarizes one or more slices,
147     * or one or more counters.
148     * The row has a left-aligned |label| in the first column, the |duration|
149     * of the data in the second, the number of |occurrences| in the third.
150     * @param {object=} opt_statistics May be undefined, or an object which
151     * contains calculated staistics containing min/max/avg for slices, or
152     * min/max/avg/start/end for counters.
153     */
154    appendDataRow: function(
155        table, label, opt_duration, opt_occurences,
156        opt_statistics, opt_selectionGenerator) {
157
158      var tooltip = undefined;
159      if (opt_statistics) {
160        tooltip = 'Min Duration:\u0009' +
161                  tracing.analysis.tsRound(opt_statistics.min) +
162                  ' ms \u000DMax Duration:\u0009' +
163                  tracing.analysis.tsRound(opt_statistics.max) +
164                  ' ms \u000DAvg Duration:\u0009' +
165                  tracing.analysis.tsRound(opt_statistics.avg) +
166                  ' ms (\u03C3 = ' +
167                  tracing.analysis.tsRound(opt_statistics.avg_stddev) + ')';
168
169        if (opt_statistics.start) {
170          tooltip += '\u000DStart Time:\u0009' +
171              tracing.analysis.tsRound(opt_statistics.start) + ' ms';
172        }
173        if (opt_statistics.end) {
174          tooltip += '\u000DEnd Time:\u0009' +
175              tracing.analysis.tsRound(opt_statistics.end) + ' ms';
176        }
177        if (opt_statistics.frequency && opt_statistics.frequency_stddev) {
178          tooltip += '\u000DFrequency:\u0009' +
179              tracing.analysis.tsRound(opt_statistics.frequency) +
180              ' occurrences/s (\u03C3 = ' +
181              tracing.analysis.tsRound(opt_statistics.frequency_stddev) + ')';
182        }
183      }
184
185      var row = this.appendElement_(table, 'tr');
186      row.className = 'analysis-table-row';
187
188      if (!opt_selectionGenerator) {
189        this.appendTableCellWithTooltip_(table, row, 0, label, tooltip);
190      } else {
191        var labelEl = this.appendTableCellWithTooltip_(
192            table, row, 0, label, tooltip);
193        labelEl.textContent = '';
194        labelEl.appendChild(
195            this.createSelectionChangingLink(label, opt_selectionGenerator,
196            tooltip));
197      }
198
199      if (opt_duration !== undefined) {
200        if (opt_duration instanceof Array) {
201          this.appendTableCellWithTooltip_(table, row, 1,
202              '[' + opt_duration.join(', ') + ']', tooltip);
203        } else {
204          this.appendTableCellWithTooltip_(table, row, 1,
205              tracing.analysis.tsRound(opt_duration) + ' ms', tooltip);
206        }
207      } else {
208        this.appendTableCell_(table, row, 1, '');
209      }
210
211      if (opt_occurences !== undefined) {
212        this.appendTableCellWithTooltip_(table, row, 2,
213            String(opt_occurences) + ' occurrences', tooltip);
214
215      } else {
216        this.appendTableCell_(table, row, 2, '');
217      }
218    }
219  };
220  return {
221    AnalysisResults: AnalysisResults
222  };
223});
224