1package autotest.tko;
2
3import autotest.common.Utils;
4import autotest.common.ui.ExtendedListBox;
5import autotest.common.ui.NotifyManager;
6import autotest.common.ui.TabView;
7import autotest.tko.SeriesSelector.Series;
8
9import com.google.gwt.event.dom.client.ChangeEvent;
10import com.google.gwt.event.dom.client.ChangeHandler;
11import com.google.gwt.event.dom.client.ClickEvent;
12import com.google.gwt.event.dom.client.ClickHandler;
13import com.google.gwt.json.client.JSONObject;
14import com.google.gwt.json.client.JSONString;
15import com.google.gwt.user.client.ui.HorizontalPanel;
16import com.google.gwt.user.client.ui.Panel;
17import com.google.gwt.user.client.ui.RadioButton;
18import com.google.gwt.user.client.ui.TextBox;
19import com.google.gwt.user.client.ui.VerticalPanel;
20
21import java.util.HashMap;
22import java.util.List;
23import java.util.Map;
24
25public class MetricsPlotFrontend extends DynamicGraphingFrontend implements ClickHandler {
26
27    public static final String NORMALIZE_SINGLE = "single";
28    public static final String NORMALIZE_FIRST = "first";
29    public static final String NORMALIZE_SERIES_PREFIX = "series__";
30    public static final String NORMALIZE_X_PREFIX = "x__";
31
32    protected FilterSelector globalFilter = new FilterSelector(DBColumnSelector.PERF_VIEW);
33    private ExtendedListBox plotSelector = new ExtendedListBox();
34    private ExtendedListBox xAxis = new DBColumnSelector(DBColumnSelector.PERF_VIEW, true);
35    private RadioButton noNormalizeMultiple =
36        new RadioButton("normalize", "No normalization (multiple subplots)");
37    private RadioButton noNormalizeSingle =
38        new RadioButton("normalize", "No normalization (single plot)");
39    private RadioButton normalizeFirst = new RadioButton("normalize", "First data point");
40    private RadioButton normalizeSeries = new RadioButton("normalize", "Specified series:");
41    private ExtendedListBox normalizeSeriesSelect = new ExtendedListBox();
42    private RadioButton normalizeX = new RadioButton("normalize", "Specified X-axis value:");
43    private TextBox normalizeXSelect = new TextBox();
44    private SeriesSelector seriesSelector = new SeriesSelector(new ChangeHandler() {
45        public void onChange(ChangeEvent event) {
46            refreshSeries();
47        }
48    });
49
50    public MetricsPlotFrontend(final TabView parent) {
51        super(parent, new MetricsPlot(), "metrics");
52
53        noNormalizeSingle.setValue(true);
54
55        noNormalizeMultiple.addClickHandler(this);
56        noNormalizeSingle.addClickHandler(this);
57        normalizeFirst.addClickHandler(this);
58        normalizeSeries.addClickHandler(this);
59        normalizeX.addClickHandler(this);
60
61        normalizeSeriesSelect.setEnabled(false);
62        normalizeXSelect.setEnabled(false);
63
64        plotSelector.addItem("Line");
65        plotSelector.addItem("Bar");
66        plotSelector.addChangeHandler(new ChangeHandler() {
67            public void onChange(ChangeEvent event) {
68                checkNormalizeInput();
69            }
70        });
71
72        Panel normalizePanel = new VerticalPanel();
73        normalizePanel.add(noNormalizeMultiple);
74        normalizePanel.add(noNormalizeSingle);
75        Panel seriesPanel = new HorizontalPanel();
76        seriesPanel.add(normalizeSeries);
77        seriesPanel.add(normalizeSeriesSelect);
78        normalizePanel.add(seriesPanel);
79        normalizePanel.add(normalizeFirst);
80        Panel baselinePanel = new HorizontalPanel();
81        baselinePanel.add(normalizeX);
82        baselinePanel.add(normalizeXSelect);
83        normalizePanel.add(baselinePanel);
84
85        addControl("Preconfigured:", preconfig);
86        addControl("Plot:", plotSelector);
87        addControl("X-axis values:", xAxis);
88        addControl("Global filters:", globalFilter);
89        addControl("Series:", seriesSelector);
90        addControl("Normalize to:", normalizePanel);
91
92        commonInitialization();
93    }
94
95    @Override
96    public void onClick(ClickEvent event) {
97        if (event.getSource() != noNormalizeSingle && event.getSource() != noNormalizeMultiple
98                && event.getSource() != normalizeSeries && event.getSource() != normalizeX) {
99            super.onClick(event);
100            return;
101        }
102
103        normalizeSeriesSelect.setEnabled(false);
104        normalizeXSelect.setEnabled(false);
105        if (event.getSource() == normalizeSeries) {
106            normalizeSeriesSelect.setEnabled(true);
107            refreshSeries();
108        } else if (event.getSource() == normalizeX) {
109            normalizeXSelect.setEnabled(true);
110        }
111
112        checkInvertible();
113    }
114
115    private void addNormalizeParameter(String plotType, Map<String, String> parameters) {
116        String normalizationType = null;
117        if (plotType.equals("Line") && noNormalizeSingle.getValue()) {
118            normalizationType = NORMALIZE_SINGLE;
119        } else if (normalizeFirst.getValue()) {
120            normalizationType = NORMALIZE_FIRST;
121        } else if (normalizeSeries.getValue()) {
122            String series = normalizeSeriesSelect.getSelectedValue();
123            normalizationType = NORMALIZE_SERIES_PREFIX + series;
124        } else if (normalizeX.getValue()) {
125            String baseline = normalizeXSelect.getText();
126            normalizationType = NORMALIZE_X_PREFIX + baseline;
127        }
128
129        if (normalizationType != null) {
130            parameters.put("normalize", normalizationType);
131        }
132    }
133
134    @Override
135    public void addToHistory(Map<String, String> args) {
136        String plot = plotSelector.getValue(plotSelector.getSelectedIndex());
137        args.put("plot", plot);
138        args.put("xAxis", xAxis.getSelectedValue());
139        globalFilter.addToHistory(args, "globalFilter");
140        seriesSelector.addToHistory(args);
141        addNormalizeParameter(plot, args);
142    }
143
144    @Override
145    public void handleHistoryArguments(Map<String, String> args) {
146        setVisible(false);
147        plot.setVisible(false);
148        embeddingLink.setVisible(false);
149        globalFilter.reset();
150        seriesSelector.reset();
151        for (int i = 0; i < plotSelector.getItemCount(); i++) {
152            if (plotSelector.getValue(i).equals(args.get("plot"))) {
153                plotSelector.setSelectedIndex(i);
154                break;
155            }
156        }
157
158        xAxis.selectByValue(args.get("xAxis"));
159        globalFilter.handleHistoryArguments(args, "globalFilter");
160        seriesSelector.handleHistoryArguments(args);
161
162        refreshSeries();
163        noNormalizeMultiple.setValue(true);
164        normalizeSeriesSelect.setEnabled(false);
165        normalizeXSelect.setEnabled(false);
166        String normalizeString = args.get("normalize");
167        if (normalizeString != null) {
168            if (normalizeString.equals(NORMALIZE_SINGLE)) {
169                noNormalizeSingle.setValue(true);
170            } else if (normalizeString.equals(NORMALIZE_FIRST)) {
171                normalizeFirst.setValue(true);
172            } else if (normalizeString.startsWith(NORMALIZE_SERIES_PREFIX)) {
173                normalizeSeries.setValue(true);
174                String series = normalizeString.substring(NORMALIZE_SERIES_PREFIX.length());
175                for (int i = 0; i < normalizeSeriesSelect.getItemCount(); i++) {
176                    if (normalizeSeriesSelect.getValue(i).equals(series)) {
177                        normalizeSeriesSelect.setSelectedIndex(i);
178                        break;
179                    }
180                }
181                normalizeSeriesSelect.setEnabled(true);
182            } else if (normalizeString.startsWith(NORMALIZE_X_PREFIX)) {
183                normalizeX.setValue(true);
184                normalizeXSelect.setText(normalizeString.substring(NORMALIZE_X_PREFIX.length()));
185                normalizeXSelect.setEnabled(true);
186            }
187        }
188        checkNormalizeInput();
189        checkInvertible();
190
191        setVisible(true);
192    }
193
194    @Override
195    protected void addAdditionalEmbeddingParams(JSONObject params) {
196        params.put("graph_type", new JSONString("metrics"));
197        params.put("params", buildParams());
198    }
199
200    private void refreshSeries() {
201        String selectedValue = normalizeSeriesSelect.getSelectedValue();
202        normalizeSeriesSelect.clear();
203        for (Series selector : seriesSelector.getAllSeries()) {
204            normalizeSeriesSelect.addItem(selector.getName());
205            if (selector.getName().equals(selectedValue)) {
206                normalizeSeriesSelect.setSelectedIndex(normalizeSeriesSelect.getItemCount() - 1);
207            }
208        }
209    }
210
211    // Disable "No Normalization (multiple)" for bar charts
212    private void checkNormalizeInput() {
213        if (plotSelector.getValue(plotSelector.getSelectedIndex()).equals("Line")) {
214            noNormalizeMultiple.setEnabled(true);
215        } else {
216            noNormalizeMultiple.setEnabled(false);
217            if (noNormalizeMultiple.getValue()) {
218                noNormalizeSingle.setValue(true);
219            }
220        }
221    }
222
223    private JSONObject buildQueries() {
224        List<Series> seriesList = seriesSelector.getAllSeries();
225        JSONObject queries = new JSONObject();
226        StringBuilder sql = new StringBuilder();
227
228        sql.append("SELECT ");
229        sql.append(xAxis.getSelectedValue());
230        for (Series series : seriesList) {
231            addSeriesSelects(series, sql);
232        }
233
234        sql.append(" FROM tko_perf_view_2");
235
236        String xFilterString = globalFilter.getFilterString();
237        if (xFilterString.equals("")) {
238            NotifyManager.getInstance().showError("You must enter a global filter");
239            return null;
240        }
241
242        sql.append(" WHERE ");
243        sql.append(xFilterString);
244
245        sql.append(" GROUP BY ");
246        sql.append(xAxis.getSelectedValue());
247        queries.put("__main__", new JSONString(sql.toString()));
248
249        for (Series series : seriesList) {
250            String drilldownQuery = getSeriesDrilldownQuery(series, xFilterString);
251            queries.put("__" + series.getName() + "__", new JSONString(drilldownQuery));
252        }
253
254        return queries;
255    }
256
257    private String getSeriesDrilldownQuery(Series series, String xFilterString) {
258        StringBuilder sql;
259        sql = new StringBuilder();
260        ExtendedListBox valueSelector = series.getDBColumnSelector();
261
262        sql.append("SELECT test_idx, ");
263        sql.append(valueSelector.getSelectedValue());
264        sql.append(" FROM tko_perf_view_2 WHERE ");
265
266        String seriesFilter = series.getFilterString();
267        if (!xFilterString.equals("") || !seriesFilter.equals("")) {
268            sql.append(xFilterString.replace("%", "%%"));
269            if (!xFilterString.equals("") && !seriesFilter.equals("")) {
270                sql.append(" AND ");
271            }
272            sql.append(seriesFilter.replace("%", "%%"));
273            sql.append(" AND ");
274        }
275
276        sql.append(xAxis.getSelectedValue());
277        sql.append(" = %s ORDER BY ");
278        sql.append(valueSelector.getSelectedValue());
279        return sql.toString();
280    }
281
282    private void addSeriesSelects(Series series, StringBuilder sql) {
283        ExtendedListBox valueSelector = series.getDBColumnSelector();
284
285        StringBuilder ifClause = new StringBuilder();
286        String seriesFilter = series.getFilterString();
287        if (!seriesFilter.equals("")) {
288            ifClause.append("IF(");
289            ifClause.append(seriesFilter);
290            ifClause.append(", ");
291        }
292        ifClause.append(valueSelector.getSelectedValue());
293        if (!seriesFilter.equals("")) {
294            ifClause.append(", NULL)");
295        }
296
297        sql.append(", ");
298        sql.append(series.getAggregation());
299        sql.append(ifClause.toString());
300        sql.append(") '");
301        sql.append(series.getName());
302        sql.append("'");
303        if (series.wantErrorBars()) {
304            sql.append(", STDDEV(");
305            sql.append(ifClause.toString());
306            sql.append(") 'errors-");
307            sql.append(series.getName());
308            sql.append("'");
309        }
310    }
311
312    // Disable the "Invert y-axis" checkboxes if inversion doesn't make sense
313    private void checkInvertible() {
314        boolean invertible = noNormalizeMultiple.getValue() || normalizeFirst.getValue()
315                             || normalizeX.getValue();
316        seriesSelector.setInvertible(invertible);
317    }
318
319    @Override
320    protected JSONObject buildParams() {
321        JSONObject queries = buildQueries();
322        if (queries == null) {
323            return null;
324        }
325
326        Map<String, String> params = new HashMap<String, String>();
327        String plot = plotSelector.getSelectedValue();
328        params.put("plot", plot);
329        addNormalizeParameter(plot, params);
330
331        JSONObject jsonParams = Utils.mapToJsonObject(params);
332        jsonParams.put("invert", Utils.stringsToJSON(seriesSelector.getInverted()));
333        jsonParams.put("queries", queries);
334        return jsonParams;
335    }
336
337    @Override
338    public String getFrontendId() {
339        return "metrics_plot";
340    }
341}
342