1package autotest.afe;
2
3import autotest.afe.ITextBox;
4import autotest.common.JSONArrayList;
5import autotest.common.StaticDataRepository;
6import autotest.common.Utils;
7import autotest.common.table.DataTable;
8import autotest.common.table.DataTable.DataTableListener;
9import autotest.common.table.DataTable.TableWidgetFactory;
10import autotest.common.table.SelectionManager;
11import autotest.common.table.SelectionManager.SelectionListener;
12import autotest.common.table.TableClickWidget;
13import autotest.common.ui.SimplifiedList;
14
15import com.google.gwt.event.dom.client.ChangeEvent;
16import com.google.gwt.event.dom.client.ChangeHandler;
17import com.google.gwt.json.client.JSONArray;
18import com.google.gwt.json.client.JSONObject;
19import com.google.gwt.user.client.ui.Composite;
20import com.google.gwt.user.client.ui.HasHTML;
21import com.google.gwt.user.client.ui.Widget;
22
23import java.util.ArrayList;
24import java.util.Collection;
25import java.util.HashMap;
26import java.util.List;
27import java.util.Map;
28
29public class TestSelector extends Composite implements DataTableListener, ChangeHandler,
30                                                TableWidgetFactory, SelectionListener {
31    public static interface Display {
32        public SimplifiedList getTestTypeSelect();
33        public ITextBox getTestNameFilter();
34        public IDataTable getTestTable();
35        public ISelectionManager getTestSelection();
36        public HasHTML getTestInfo();
37    }
38
39    // TODO: Change DataTable to passive view, then get rid of this ad-hoc interface
40    public static interface IDataTable {
41        public void setWidgetFactory(TableWidgetFactory widgetFactory);
42        public void addListener(DataTableListener listener);
43        public void clear();
44        public void addRow(JSONObject row);
45        public void refreshWidgets();
46
47        public static class DataTableImpl extends DataTable implements IDataTable {
48            public DataTableImpl(String[][] columns) {
49                super(columns);
50            }
51        }
52    }
53
54    // TODO: Change SelectionManager to use the DataTable passive view model, then get rid of this
55    // ad-hoc interface
56    public static interface ISelectionManager {
57        public void deselectAll();
58        public Widget createWidget(int row, int cell, JSONObject rowObject);
59        public void addListener(SelectionListener listener);
60
61        public static class SelectionManagerImpl extends SelectionManager
62                implements ISelectionManager {
63            public SelectionManagerImpl(DataTable table, boolean selectOnlyOne) {
64                super(table, selectOnlyOne);
65            }
66
67        }
68    }
69
70    // control file types
71    public static final String SERVER_TYPE = "Server";
72    public static final String CLIENT_TYPE = "Client";
73
74    public static interface TestSelectorListener {
75        /**
76         * Called when a test is selected or deselected, or when the test type is changed.
77         */
78        public void onTestSelectionChanged();
79    }
80
81    private static class TestInfoBuilder {
82        private static final Map<String, String> timeMap = new HashMap<String, String>();
83        static {
84            timeMap.put("SHORT", "less than 15 minutes");
85            timeMap.put("MEDIUM", "15 minutes to four hours");
86            timeMap.put("LONG", "over four hours");
87        }
88
89        private StringBuilder builder = new StringBuilder();
90        private JSONObject test;
91
92        public TestInfoBuilder(JSONObject test) {
93            this.test = test;
94
95            writeTitleLine();
96            appendTextField("Written by", getField("author"));
97            appendTextField("Type", getField("test_type"));
98            appendTextField("Synchronization count", getField("sync_count"));
99            writeTime();
100            writeSkipVerify(test);
101
102            builder.append("<br>" + getField("description"));
103        }
104
105        private void writeTitleLine() {
106            builder.append("<b>" + getField("name") + "</b> ");
107            builder.append("(" +
108                           getField("test_class") + " / " + getField("test_category") +
109                           ")<br><br>");
110        }
111
112        private void writeTime() {
113            String time = getField("test_time");
114            String timeDetail = "unknown time";
115            if (timeMap.containsKey(time)) {
116                timeDetail = timeMap.get(time);
117            }
118            appendTextField("Time", time + " (" + timeDetail + ")");
119        }
120
121        private void writeSkipVerify(JSONObject test) {
122            if (!test.get("run_verify").isBoolean().booleanValue()) {
123                builder.append("Verify is <b>not</b> run<br>");
124            }
125        }
126
127        private void appendTextField(String name, String text) {
128            builder.append("<b>" + name + "</b>: " + text + "<br>");
129        }
130
131        private String getField(String field) {
132            return Utils.escape(Utils.jsonToString(test.get(field)));
133        }
134
135        public String getInfo() {
136            return builder.toString();
137        }
138    }
139
140    private boolean enabled = true;
141    private TestSelectorListener listener;
142    private StaticDataRepository staticData = StaticDataRepository.getRepository();
143    private List<JSONObject> selectedTests = new ArrayList<JSONObject>();
144    private JSONArray imageTests = new JSONArray();
145
146    private Display display;
147
148    public void bindDisplay(Display display) {
149        this.display = display;
150
151        display.getTestTypeSelect().addItem(CLIENT_TYPE, CLIENT_TYPE);
152        display.getTestTypeSelect().addItem(SERVER_TYPE, SERVER_TYPE);
153        display.getTestTypeSelect().addChangeHandler(this);
154
155        display.getTestTable().setWidgetFactory(this);
156        display.getTestTable().addListener(this);
157
158        populateTests();
159
160        display.getTestSelection().addListener(this);
161        display.getTestNameFilter().addChangeHandler(this);
162    }
163
164    private void populateTests() {
165        display.getTestSelection().deselectAll();
166        display.getTestTable().clear();
167
168        JSONArray tests = staticData.getData("tests").isArray();
169
170        if (usingTestsFromBuild()) {
171            tests = imageTests;
172        }
173
174        for (JSONObject test : new JSONArrayList<JSONObject>(tests)) {
175            if (!includeExperimentalTests()
176                    && test.get("experimental").isBoolean().booleanValue()) {
177                continue;
178            }
179            String testType = test.get("test_type").isString().stringValue().toLowerCase();
180            String testName = test.get("name").isString().stringValue().toLowerCase();
181            if (testType.equals(getSelectedTestType()) &&
182                testName.contains(getTestNameFilterText())) {
183                display.getTestTable().addRow(test);
184            }
185        }
186    }
187
188    private boolean includeExperimentalTests() {
189        JSONObject user = staticData.getData("current_user").isObject();
190        return user.get("show_experimental").isBoolean().booleanValue();
191    }
192
193    @Override
194    public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) {
195        TestInfoBuilder builder = new TestInfoBuilder(row);
196        display.getTestInfo().setHTML(builder.getInfo());
197    }
198
199    @Override
200    public void onChange(ChangeEvent event) {
201        populateTests();
202        notifyListener();
203    }
204
205    public Collection<JSONObject> getSelectedTests() {
206        return selectedTests;
207    }
208
209    public String getSelectedTestType() {
210        return display.getTestTypeSelect().getSelectedName().toLowerCase();
211    }
212
213    public String getTestNameFilterText() {
214        return display.getTestNameFilter().getText().toLowerCase();
215    }
216
217    public void setEnabled(boolean enabled) {
218        this.enabled = enabled;
219        display.getTestTypeSelect().setEnabled(enabled);
220        display.getTestNameFilter().setEnabled(enabled);
221        display.getTestTable().refreshWidgets();
222    }
223
224    public Widget createWidget(int row, int cell, JSONObject rowObject) {
225        TableClickWidget widget =
226            (TableClickWidget) display.getTestSelection().createWidget(row, cell, rowObject);
227        if (!enabled) {
228            widget.getContainedWidget().setEnabled(false);
229        }
230        return widget;
231    }
232
233    public void reset() {
234        display.getTestTypeSelect().selectByName(CLIENT_TYPE);
235        display.getTestNameFilter().setText("");
236        populateTests();
237    }
238
239    private void notifyListener() {
240        if (listener != null) {
241            listener.onTestSelectionChanged();
242        }
243    }
244
245    public void setListener(TestSelectorListener listener) {
246        this.listener = listener;
247    }
248
249    public void onAdd(Collection<JSONObject> objects) {
250        selectedTests.addAll(objects);
251        notifyListener();
252    }
253
254    public void onRemove(Collection<JSONObject> objects) {
255        selectedTests.removeAll(objects);
256        notifyListener();
257    }
258
259    public void setImageTests(JSONArray tests) {
260        imageTests = tests;
261    }
262
263    public boolean usingTestsFromBuild() {
264        return imageTests.size() > 0;
265    }
266}
267