1package autotest.common;
2
3import com.google.gwt.dom.client.Document;
4import com.google.gwt.dom.client.Element;
5import com.google.gwt.http.client.URL;
6import com.google.gwt.i18n.client.NumberFormat;
7import com.google.gwt.json.client.JSONArray;
8import com.google.gwt.json.client.JSONNumber;
9import com.google.gwt.json.client.JSONObject;
10import com.google.gwt.json.client.JSONString;
11import com.google.gwt.json.client.JSONValue;
12import com.google.gwt.user.client.Window;
13import com.google.gwt.user.client.ui.Anchor;
14import com.google.gwt.user.client.ui.HTMLPanel;
15
16import java.util.ArrayList;
17import java.util.Collection;
18import java.util.HashMap;
19import java.util.List;
20import java.util.Map;
21
22public class Utils {
23    public static final String JSON_NULL = "<null>";
24    public static final String RETRIEVE_LOGS_URL = "/tko/retrieve_logs.cgi";
25
26    private static final String[][] escapeMappings = {
27        {"&", "&amp;"},
28        {">", "&gt;"},
29        {"<", "&lt;"},
30        {"\"", "&quot;"},
31        {"'", "&apos;"},
32    };
33
34    /**
35     * Converts a collection of Java <code>String</code>s into a <code>JSONArray
36     * </code> of <code>JSONString</code>s.
37     */
38    public static JSONArray stringsToJSON(Collection<String> strings) {
39        JSONArray result = new JSONArray();
40        for(String s : strings) {
41            result.set(result.size(), new JSONString(s));
42        }
43        return result;
44    }
45
46    /**
47     * Converts a collection of Java <code>Integers</code>s into a <code>JSONArray
48     * </code> of <code>JSONNumber</code>s.
49     */
50    public static JSONArray integersToJSON(Collection<Integer> integers) {
51        JSONArray result = new JSONArray();
52        for(Integer i : integers) {
53            result.set(result.size(), new JSONNumber(i));
54        }
55        return result;
56    }
57
58    /**
59     * Converts a <code>JSONArray</code> of <code>JSONStrings</code> to an
60     * array of Java <code>Strings</code>.
61     */
62    public static String[] JSONtoStrings(JSONArray strings) {
63        String[] result = new String[strings.size()];
64        for (int i = 0; i < strings.size(); i++) {
65            result[i] = jsonToString(strings.get(i));
66        }
67        return result;
68    }
69
70    /**
71     * Converts a <code>JSONArray</code> of <code>JSONObjects</code> to an
72     * array of Java <code>Strings</code> by grabbing the specified field from
73     * each object.
74     */
75    public static String[] JSONObjectsToStrings(JSONArray objects, String field) {
76        String[] result = new String[objects.size()];
77        for (int i = 0; i < objects.size(); i++) {
78            JSONValue fieldValue = objects.get(i).isObject().get(field);
79            result[i] = jsonToString(fieldValue);
80        }
81        return result;
82    }
83
84    public static JSONObject mapToJsonObject(Map<String, String> map) {
85        JSONObject result = new JSONObject();
86        for (Map.Entry<String, String> entry : map.entrySet()) {
87            result.put(entry.getKey(), new JSONString(entry.getValue()));
88        }
89        return result;
90    }
91
92    public static Map<String, String> jsonObjectToMap(JSONObject object) {
93        Map<String, String> result = new HashMap<String, String>();
94        for (String key : object.keySet()) {
95            result.put(key, jsonToString(object.get(key)));
96        }
97        return result;
98    }
99
100    /**
101     * Get a value out of a JSONObject list of size 1.
102     * @return list[0]
103     * @throws IllegalArgumentException if the list is not of size 1
104     */
105    public static JSONObject getSingleObjectFromList(List<JSONObject> list) {
106        if(list.size() != 1) {
107            throw new IllegalArgumentException("List is not of size 1");
108        }
109        return list.get(0);
110    }
111
112    public static JSONObject getSingleObjectFromArray(JSONArray array) {
113        return getSingleObjectFromList(new JSONArrayList<JSONObject>(array));
114    }
115
116    public static JSONObject copyJSONObject(JSONObject source) {
117        JSONObject dest = new JSONObject();
118        for(String key : source.keySet()) {
119            dest.put(key, source.get(key));
120        }
121        return dest;
122    }
123
124    public static String escape(String text) {
125        for (String[] mapping : escapeMappings) {
126            text = text.replace(mapping[0], mapping[1]);
127        }
128        return text;
129    }
130
131    public static String unescape(String text) {
132        // must iterate in reverse order
133        for (int i = escapeMappings.length - 1; i >= 0; i--) {
134            text = text.replace(escapeMappings[i][1], escapeMappings[i][0]);
135        }
136        return text;
137    }
138
139    public static <T> List<T> wrapObjectWithList(T object) {
140        List<T> list = new ArrayList<T>();
141        list.add(object);
142        return list;
143    }
144
145    public static <T> String joinStrings(String joiner, List<T> objects, boolean wantBlanks) {
146        StringBuilder result = new StringBuilder();
147        boolean first = true;
148        for (T object : objects) {
149            String piece = object.toString();
150            if (piece.equals("") && !wantBlanks) {
151                continue;
152            }
153            if (first) {
154                first = false;
155            } else {
156                result.append(joiner);
157            }
158            result.append(piece);
159        }
160        return result.toString();
161    }
162
163    public static <T> String joinStrings(String joiner, List<T> objects) {
164        return joinStrings(joiner, objects, false);
165    }
166
167    public static Map<String,String> decodeUrlArguments(String urlArguments,
168                                                        Map<String, String> arguments) {
169        String[] components = urlArguments.split("&");
170        for (String component : components) {
171            String[] parts = component.split("=");
172            if (parts.length > 2) {
173                throw new IllegalArgumentException();
174            }
175            String key = decodeComponent(parts[0]);
176            String value = "";
177            if (parts.length == 2) {
178                value = URL.decodeComponent(parts[1]);
179            }
180            arguments.put(key, value);
181        }
182        return arguments;
183    }
184
185    private static String decodeComponent(String component) {
186        return URL.decodeComponent(component.replace("%27", "'"));
187    }
188
189    public static String encodeUrlArguments(Map<String, String> arguments) {
190        List<String> components = new ArrayList<String>();
191        for (Map.Entry<String, String> entry : arguments.entrySet()) {
192            String key = encodeComponent(entry.getKey());
193            String value = encodeComponent(entry.getValue());
194            components.add(key + "=" + value);
195        }
196        return joinStrings("&", components);
197    }
198
199    private static String encodeComponent(String component) {
200        return URL.encodeComponent(component).replace("'", "%27");
201    }
202
203    /**
204     * @param path should be of the form "123-showard/status.log" or just "123-showard"
205     */
206    public static String getLogsUrl(String path) {
207        return "/results/" + path;
208    }
209
210    public static String getRetrieveLogsUrl(String path) {
211        String logUrl = URL.encode(getLogsUrl(path));
212        return RETRIEVE_LOGS_URL + "?job=" + logUrl;
213    }
214
215    public static String jsonToString(JSONValue value) {
216        JSONString string;
217        JSONNumber number;
218        assert value != null;
219        if ((string = value.isString()) != null) {
220            return string.stringValue();
221        }
222        if ((number = value.isNumber()) != null) {
223            double doubleValue = number.doubleValue();
224            if (doubleValue == (int) doubleValue) {
225                return Integer.toString((int) doubleValue);
226            }
227            return Double.toString(doubleValue);
228
229        }
230        if (value.isNull() != null) {
231            return JSON_NULL;
232        }
233        return value.toString();
234    }
235
236    public static String setDefaultValue(Map<String, String> map, String key, String defaultValue) {
237        if (map.containsKey(key)) {
238            return map.get(key);
239        }
240        map.put(key, defaultValue);
241        return defaultValue;
242    }
243
244    public static JSONValue setDefaultValue(JSONObject object, String key, JSONValue defaultValue) {
245        if (object.containsKey(key)) {
246            return object.get(key);
247        }
248        object.put(key, defaultValue);
249        return defaultValue;
250    }
251
252    public static List<String> splitList(String list, String splitRegex) {
253        String[] parts = list.split(splitRegex);
254        List<String> finalParts = new ArrayList<String>();
255        for (String part : parts) {
256            if (!part.equals("")) {
257                finalParts.add(part);
258            }
259        }
260        return finalParts;
261    }
262
263    public static List<String> splitList(String list) {
264        return splitList(list, ",");
265    }
266
267    public static List<String> splitListWithSpaces(String list) {
268        return splitList(list, "[,\\s]+");
269    }
270
271    public static void updateObject(JSONObject destination, JSONObject source) {
272        if (source == null) {
273            return;
274        }
275        for (String key : source.keySet()) {
276            destination.put(key, source.get(key));
277        }
278    }
279
280    public static void openUrlInNewWindow(String url) {
281        Window.open(url, "_blank", "");
282    }
283
284    public static HTMLPanel divToPanel(String elementId) {
285        Element divElement = Document.get().getElementById(elementId);
286        divElement.getParentElement().removeChild(divElement);
287        return new HTMLPanel(divElement.getInnerHTML());
288    }
289
290    public static void setElementVisible(String elementId, boolean visible) {
291        String display = visible ? "block" : "none";
292        Document.get().getElementById(elementId).getStyle().setProperty("display", display);
293    }
294
295    public static String percentage(int num, int total) {
296        if (total == 0) {
297            return "N/A";
298        }
299        NumberFormat format = NumberFormat.getFormat("##0.#%");
300        return format.format(num / (double) total);
301    }
302
303    public static String numberAndPercentage(int num, int total) {
304        return num + " (" + percentage(num, total) + ")";
305    }
306
307    public static interface JsonObjectFactory<T> {
308        public T fromJsonObject(JSONObject object);
309    }
310
311    public static <T> List<T> createList(JSONArray objects, JsonObjectFactory<T> factory) {
312        List<T> list = new ArrayList<T>();
313        for (JSONObject object : new JSONArrayList<JSONObject>(objects)) {
314            list.add(factory.fromJsonObject(object));
315        }
316        return list;
317    }
318
319    public static String getBaseUrl() {
320        return Window.Location.getProtocol() + "//" + Window.Location.getHost();
321    }
322
323    public static String getGoogleStorageHttpUrl(String bucketPath) {
324      if (bucketPath != null) {
325        if (bucketPath.startsWith("gs://")) {
326          String bucketName = bucketPath.substring(5);
327          return "https://console.cloud.google.com/storage/browser/" + bucketName;
328        }
329      }
330      return null;
331    }
332
333    public static Anchor createGoogleStorageHttpUrlLink(String label, String bucketPath) {
334      String url = getGoogleStorageHttpUrl(bucketPath);
335      if (url != null) {
336        if (url != null) {
337          Anchor a = new Anchor(label, url);
338          a.setTarget("_blank");
339          return a;
340        }
341      }
342      return null;
343    }
344}
345