package com.applang; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.Reader; import java.io.Serializable; import java.io.Writer; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.net.URL; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.TreeSet; import java.util.UUID; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.util.Log; public class Util { static final String TAG = Util.class.getSimpleName(); static { Locale.setDefault(Locale.GERMAN); } private static Random random = new Random(); public static Random getRandom() { return random; } private static final int millisPerHour = 1000*60*60; private static final int millisPerDay = millisPerHour * 24; private static Calendar calendar = Calendar.getInstance(Locale.US); static void setWeekDate(int year, int weekOfYear, int dayOfWeek) { while (dayOfWeek > 7) { dayOfWeek -= 7; weekOfYear += 1; } calendar.set(Calendar.YEAR, year); calendar.set(Calendar.WEEK_OF_YEAR, weekOfYear); calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek); setMidnight(); } static void setMonthDate(int year, int month, int dayOfMonth) { calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month); calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); setMidnight(); } static void setMidnight() { calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); } public static Calendar getCalendar() { return calendar; } public static int[] getCalendarDate(long time) { calendar.setTimeInMillis(time); return ints( calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.MONTH), calendar.get(Calendar.YEAR) ); } /** * calculates the milliseconds after 1970-01-01 for a given start of a day (midnight) * @param year * @param week week of year (1..53) or if zero or negative number of month (-11..0) * @param day day of week or day of month * @return */ // NOTE used in xsl scripts public static long timeInMillis(int year, int week, int day) { if (week < 1) return dateInMillis(year, -week, day); setWeekDate(year, week, day); return calendar.getTimeInMillis(); } // NOTE used in xsl scripts public static long timeInMillis(int year, int week, int day, int days) { if (week < 1) return dateInMillis(year, -week, day, days); setWeekDate(year, week, day); calendar.add(Calendar.DATE, days); return calendar.getTimeInMillis(); } public static long dateInMillis(int year, int month, int day) { setMonthDate(year, month, day); return calendar.getTimeInMillis(); } public static long dateInMillis(int year, int month, int day, int days) { setMonthDate(year, month, day); calendar.add(Calendar.DATE, days); return calendar.getTimeInMillis(); } public static int daysToTodayFrom(int year, int weekOfYear, int dayOfWeek) { setWeekDate(year, weekOfYear, dayOfWeek); Date today = new Date(); long diff = today.getTime() - calendar.getTimeInMillis(); return (int)(diff / millisPerDay); } public static long dateFromTodayInMillis(int days, Object... params) { Date today = param(new Date(), 0, params); boolean randomizeTimeOfDay = param(false, 1, params); calendar.setTime(today); setMidnight(); calendar.add(Calendar.DATE, days); long timeInMillis = calendar.getTimeInMillis(); if (randomizeTimeOfDay) timeInMillis += random.nextInt(millisPerDay); return timeInMillis; } public static long hoursFromDate(long date, int hours) { return date + hours * millisPerHour; } public static long getMillis(int days) { return days * millisPerDay; } public static long[] dayInterval(Long time, int days) { if (time == null) return null; long[] interval = new long[2]; if (days < 0) { interval[0] = time - days * millisPerDay; interval[1] = time; } else { interval[0] = time; interval[1] = time + days * millisPerDay; } return interval; } public static long[] weekInterval(Date start, int weeks) { calendar.setTime(start); long millis = calendar.getTimeInMillis(); calendar.add(Calendar.DATE, weeks * 7); long[] interval = new long[2]; if (weeks < 0) { interval[0] = calendar.getTimeInMillis(); interval[1] = millis; } else { interval[0] = millis; interval[1] = calendar.getTimeInMillis(); } return interval; } public static long[] monthInterval(Date start, int months) { calendar.setTime(start); long millis = calendar.getTimeInMillis(); calendar.add(Calendar.MONTH, months); long[] interval = new long[2]; if (months < 0) { interval[0] = calendar.getTimeInMillis(); interval[1] = millis; } else { interval[0] = millis; interval[1] = calendar.getTimeInMillis(); } return interval; } public static String timestampFormat = "yyyy-MM-dd HH:mm:ss.SSS"; // NOTE used in xsl scripts public static String formatDate(long millis, String pattern) { return new SimpleDateFormat(pattern, Locale.US).format(new Date(millis)); } // NOTE used in BeanShell scripts public static String formatDate(Long millis, Object...params) { if (millis == null) return null; // return String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL", millis); String pattern = param(timestampFormat,0,params); Locale locale = param(Locale.US,1,params); return new SimpleDateFormat(pattern, locale).format(new Date(millis)); } public static String[] formatDates(Long[] millis, Object...params) { return formatDates(toLongArray(asList(millis)), params); } public static String[] formatDates(long[] millis, Object...params) { String[] dates = new String[millis.length]; for (int i = 0; i < dates.length; i++) dates[i] = formatDate(millis[i], params); return dates; } public static Date toDate(String dateString, Object...params) { try { String pattern = param("yyyy-MM-dd", 0, params); Locale locale = param(Locale.US,1,params); return new SimpleDateFormat(pattern, locale).parse(dateString); } catch (Exception e) { // Log.e(TAG, "toDate", e); return null; } } // NOTE used in scripts public static Long toTime(String dateString, Object...params) { Date date = toDate(dateString, params); if (date == null) { if (notNullOrEmpty(dateString) && isAvailable(0, params)) { Locale locale = param(Locale.US, 1, params); if (Locale.US.equals(locale)) locale = Locale.getDefault(); else locale = Locale.US; date = toDate(dateString, params[0], locale); } if (date == null) return null; } return date.getTime(); } // NOTE used in xsl scripts public static long now() { return new Date().getTime(); } public static boolean isType(Object prototype, Object o) { if (o == null) return prototype == null; else if (prototype == null) return o == null; else if (prototype instanceof Class<?>) return ((Class<?>)prototype).getName().equals(o.getClass().getName()); else return prototype.getClass().getName().equals(o.getClass().getName()); } public static String identity(Object...o) { int len = o.length; if (len < 1) return ""; else if (len < 2) return o[0] == null ? "null" : o[0].getClass().getSimpleName() + "@" + Integer.toHexString(o[0].hashCode()); String[] s = new String[len]; while (len > 0) s[--len] = identity(o[len]); return Arrays.toString(s); } public static String stringValueOf(Object value) { return value == null ? "" : String.valueOf(value); } public static boolean notNullOrEmpty(Object value) { return stringValueOf(value).length() > 0; } public static boolean nullOrEmpty(Object value) { return !notNullOrEmpty(value); } public static <T> boolean nullOrEmpty(T[] value) { return value == null || value.length < 1; } public static boolean nullOrEmpty(int[] value) { return value == null || value.length < 1; } public static boolean nullOrEmpty(long[] value) { return value == null || value.length < 1; } public static boolean nullOrEmpty(float[] value) { return value == null || value.length < 1; } public static boolean nullOrEmpty(double[] value) { return value == null || value.length < 1; } // NOTE used in xsl scripts public static boolean isWhiteSpace(String s) { for (int i = 0; i < s.length(); i++) if (!Character.isWhitespace(s.charAt(i))) return false; return true; } public static Boolean toBool(Boolean defaultValue, String value) { Boolean result; try { result = Boolean.parseBoolean(value); } catch(NumberFormatException e) { result = defaultValue; } return result; } public static Integer toInt(Integer defaultValue, String value) { Integer result; try { result = Integer.parseInt(value); } catch(NumberFormatException e) { result = defaultValue; } return result; } public static Long fromHex(Long defaultValue, String value) { Long result; try { result = Long.parseLong(value, 16); } catch(NumberFormatException e) { result = defaultValue; } return result; } public static Long toLong(Long defaultValue, String value) { Long result; try { result = Long.parseLong(value); } catch(NumberFormatException e) { result = defaultValue; } return result; } public static Float toFloat(Float defaultValue, String value) { Float result; try { result = Float.parseFloat(value); } catch(NumberFormatException e) { result = defaultValue; } return result; } public static Double toDouble(Double defaultValue, String value) { Double result; try { result = Double.parseDouble(value); } catch(NumberFormatException e) { result = defaultValue; } return result; } public static <T> boolean notAvailable(int index, T[] array) { return !isAvailable(index, array); } public static <T> boolean isAvailable(int index, T[] array) { return array != null && index > -1 && index < array.length && array[index] != null; } public static boolean isAvailable(int index, int[] array) { return array != null && index > -1 && index < array.length; } public static boolean notAvailable(int index, List<?> list) { return !isAvailable(index, list.toArray()); } public static boolean isAvailable(int index, List<?> list) { return isAvailable(index, list.toArray()); } public static Object[] reduceDepth(Object...params) { while (params != null && params.length == 1 && params[0] instanceof Object[]) params = (Object[])params[0]; return params; } @SuppressWarnings("unchecked") public static <T extends Object> T valueOrElse(T elseValue, Object value) { if (value != null) try { return (T)value; } catch (Exception e) {} return elseValue; } public static <T extends Object> T functionValueOrElse(T elseValue, Function<T> value, Object...params) { if (value != null) try { return value.apply(params); } catch (Exception e) {} return elseValue; } /** * retrieves the indicated varargs-parameter from a parameter array * @param <P> type of the values in the parameter array * @param <T> genericized return type * @param defaultParam the value returned if the indexed value doesn't exist in the array * @param index indicating the value in the parameter array that is returned * @param params the parameter array * @return if the indicated value does not exist the value of defaultParam is returned * @throws ClassCastException */ @SuppressWarnings("unchecked") public static <P extends Object, T extends P> T param(T defaultParam, int index, P...params) { if (params != null && index > -1 && params.length > index) try { T returnValue = (T)params[index]; return returnValue; } catch (ClassCastException e) { Log.e(TAG, "param", e); } return defaultParam; } public static int param(int defaultParam, int index, int...params) { if (params != null && index > -1 && params.length > index) return params[index]; else return defaultParam; } public static boolean param(boolean defaultParam, int index, boolean...params) { if (params != null && index > -1 && params.length > index) return params[index]; else return defaultParam; } public static <P extends Object, T extends P> T param_T(T defaultParam, int index, P...params) { T param = param(defaultParam, index, params); if (isType(defaultParam, param)) return param; else return defaultParam; } public static Boolean param_Boolean(Boolean defaultParam, int index, Object... params) { Object param = param(defaultParam, index, params); if (param instanceof Boolean) return (Boolean)param; else return defaultParam; } public static Integer param_Integer(Integer defaultParam, int index, Object... params) { Object param = param(defaultParam, index, params); if (param instanceof Integer) return (Integer)param; else return defaultParam; } public static Double param_Double(Double defaultParam, int index, Object... params) { Object param = param(defaultParam, index, params); if (param instanceof Double) return (Double)param; else return defaultParam; } public static String param_String(String defaultParam, int index, Object... params) { Object param = param(defaultParam, index, params); if (param instanceof String) return (String)param; else return defaultParam; } public static File param_File(File defaultParam, int index, Object... params) { if (params != null && index > -1 && params.length > index) { if (params[index] instanceof File) return (File)params[index]; else if (params[index] instanceof String) return new File((String)params[index]); } return defaultParam; } public static String toString(Object[][] o) { ValList list = vlist(); for (Object object : (Object[])o) list.add(Arrays.toString((Object[])object)); String s = Arrays.toString(list.toArray()); return strip(Constraint.START, strip(Constraint.END, s , "]") , "[") .replaceAll("(\\],) (\\[)", "$1\n\n$2"); } public static String toString(ValMap o) { return String.valueOf(o).replaceAll("\\], ", "\\],\n"); } public static String toString(Object o) { String name = o.getClass().getName(); if (name.startsWith("[") && name.endsWith(";")) { String s = ""; for (int i = 0; i < Array.getLength(o); i++) s += (s.length() > 0 ? NEWLINE : "") + toString(Array.get(o, i)); return enclose("[", s, "]"); } return String.valueOf(o); } public static Object object(Object o) { return o; } public static Object _null() { return object(null); } public static Object[] objects(Object...params) { return params; } public static String[] strings(String...params) { return params; } public static String[] toStrings(Object...params) { return arraycast(params, strings()); } public static <T> String[] toStrings(Collection<T> collection) { return collection.toArray(strings()); } public static <T> List<T> asList(T[] array) { return Arrays.asList(array); } public static <T> Set<T> set(Collection<T> collection) { return new HashSet<T>(collection); } public static <T> Set<T> sortedSet(Collection<T> collection) { return new TreeSet<T>(collection); } public static int[] ints(int...params) { return params; } public interface Function<T> { public T apply(Object...params); } public interface Job<T> { public void perform(T t, Object[] parms) throws Exception; } public static Pattern clippingPattern(String clipper1, String clipper2) { String clipped1 = "[^" + clipper1 + "]"; String clipped2 = "[^" + clipper1 + clipper2 + "]"; String clipped3 = "[^" + clipper2 + "]"; return Pattern.compile( "(" + clipped1 + "*)" + clipper1 + "(" + clipped2 + "+)" + clipper2 + "(" + clipped3 + "*)"); } public static MatchResult[] findAllIn(String input, Pattern pattern) { ArrayList<MatchResult> matches = alist(); Matcher matcher = pattern.matcher(input); while (matcher.find()) matches.add(matcher.toMatchResult()); return matches.toArray(new MatchResult[0]); } public static MatchResult findFirstIn(String input, Pattern pattern) { Matcher matcher = pattern.matcher(input); if (matcher.find()) return matcher.toMatchResult(); else return null; } // NOTE used in xsl scripts public static boolean matches(String s, String regex) { return s.matches(regex); } /** * @param parts * @return a <code>File</code> object constructed from parts of the file path */ public static File fileOf(String...parts) { File file = null; for (int i = 0; i < parts.length; i++) { String part = parts[i]; if (i == 0) file = new File(part); else if (part != null) { part = part.replaceAll("(\\\\|/)+$", ""); file = new File(file, part); } } return file; } public static ValList split(String string, String regex, int...limit) { String[] parts = strings(); if (notNullOrEmpty(string)) parts = limit.length < 1 ? string.split(regex) : string.split(regex, limit[0]); return vlist(parts); } public static <T> String join(String delimiter, T...params) { StringBuilder sb = new StringBuilder(); Iterator<T> iter = asList(params).iterator(); if (iter.hasNext()) do { sb.append(String.valueOf(iter.next())) .append(iter.hasNext() ? delimiter : ""); } while (iter.hasNext()); return sb.toString(); } public static String quoted(String string) { return enclose("\"", string, "\""); } public static String htmlize(String text) { if (isHtml(text)) return text; else return enclose("<html>", text.replaceAll(NEWLINE_REGEX, "<br>"), "</html>"); } private static boolean isHtml(String text) { return text.substring(0, Math.min(text.length(), 20)).trim().toLowerCase().startsWith("<html>"); } public static String deHtmlize(String text) { if (isHtml(text)) { text = text.trim(); text = text.substring(6, text.length() - 7); return text.replaceAll("<br>", NEWLINE); } else return text; } public static String enclose(String decor, Object o, Object...params) { decor = stringValueOf(decor); String string = decor.concat(stringValueOf(o)); if (params.length < 1) return string.concat(decor); for (int i = 0; i < params.length; i++) string = string.concat(param("", i, params)); return string; } public static String strip(Constraint constraint, String string, Object...params) { for (int i = 0; i < params.length; i++) { Object param = param("", i, params); String pad = String.valueOf(param); if (check(string, constraint, pad)) switch (constraint) { case START: string = string.substring(pad.length()); break; case END: string = string.substring(0, string.length() - pad.length()); break; default: } } return string; } public static String stripUnits(String s) { int i = 0; while (i < s.length()) if (Character.isDigit(s.charAt(i)) || "-+.,".contains(String.valueOf(s.charAt(i)))) i++; else break; return s.substring(0, i); } public static String trim(boolean left, String s, String...regex) { for (String rgx : regex) { Matcher m = Pattern.compile(left ? "^" + rgx : rgx + "$").matcher(s); StringBuffer sb = new StringBuffer(); while (m.find()) m.appendReplacement(sb, ""); m.appendTail(sb); s = sb.toString(); } return s; } public static void copyContents(InputStream in, OutputStream out, Object...params) throws IOException { byte scoop[] = new byte[param_Integer(4096, 0, params).intValue()]; int n; while ((n = in.read(scoop, 0, scoop.length)) > -1) out.write(scoop, 0, n); } @SuppressWarnings("resource") public static void copyFile(File sourceFile, File destFile) throws IOException { if(!destFile.exists()) destFile.createNewFile(); FileChannel source = null; FileChannel destination = null; try { source = new FileInputStream(sourceFile).getChannel(); destination = new FileOutputStream(destFile).getChannel(); // previous code: destination.transferFrom(source, 0, source.size()); // to avoid infinite loops, should be: long count = 0; long size = source.size(); while((count += destination.transferFrom(source, count, size-count))<size); } finally { if (source != null) source.close(); if (destination != null) destination.close(); } } public static boolean deleteDirectory(File dir, Object...params) { try { Job<File> deleter = new Job<File>() { public void perform(File f, Object[] params) throws Exception { if (f.delete()) { int no = (Integer) params[0]; Integer n = param_Integer(null, no, (Object[]) params[1]); if (n != null) params[no] = n + 1; } } }; if (dir != null && dir.isDirectory()) { for (File file : dir.listFiles()) if (file.isDirectory()) { if (isSymlink(file)) deleter.perform(file, new Object[]{1, params}); else deleteDirectory(file, params); } else if (file.isFile()) { deleter.perform(file, new Object[]{0, params}); } deleter.perform(dir, new Object[]{1, params}); } return !dir.exists(); } catch (Exception e) { Log.e(TAG, "deleteDirectory", e); return false; } } // NOTE used in xsl scripts public static String canonicalPath(String filePath) { try { return new File(filePath).getCanonicalPath(); } catch (Exception e) { return filePath; } } public static boolean isSymlink(File file) throws IOException { if (file == null) throw new NullPointerException("File must not be null"); File canon; if (file.getParent() == null) { canon = file; } else { File canonDir = file.getParentFile().getCanonicalFile(); canon = new File(canonDir, file.getName()); } if (canon.getCanonicalFile().equals(canon.getAbsoluteFile())) return false; else return true; } public static String readAll(Reader rd, Object...params) throws IOException { Integer chars = param_Integer(null, 0, params); StringBuilder sb = new StringBuilder(); int cp, i = 0; while ((cp = rd.read()) != -1) { sb.append((char) cp); if (chars != null && ++i >= chars) break; } return sb.toString(); } public static String readFromUrl(String url, String encoding) throws IOException { InputStream is = null; try { is = new URL(url).openStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName(encoding))); return readAll(rd); } finally { if (is != null) is.close(); } } public static MatchResult[] excerptsFrom(InputStream is, Pattern pattern) throws IOException { String text = readAll(new BufferedReader(new InputStreamReader(is))); is.close(); return findAllIn(text, pattern); } // NOTE used in scripts public static String contentsFromFile(File file) { return contentsFromFile(file, null); } public static String contentsFromFile(File file, Integer chars) { Reader fr = null; try { fr = new InputStreamReader(new FileInputStream(file)); return readAll(fr, chars); } catch (Exception e) { Log.e(TAG, "contentsFromFile", e); return null; } finally { if (fr != null) try { fr.close(); } catch (IOException e) { Log.e(TAG, "contentsFromFile", e); } } } // NOTE used in scripts public static File contentsToFile(File file, String s) { return contentsToFile(file, s, false); } public static File contentsToFile(File file, String s, boolean append) { Writer fw = null; try { fw = new OutputStreamWriter(new FileOutputStream(file, append)); fw.write(s); } catch (Exception e) { Log.e(TAG, "contentsToFile", e); } finally { if (fw != null) try { fw.close(); } catch (IOException e) { Log.e(TAG, "contentsToFile", e); } } return file; } public static boolean fileExists(File file) { return file == null ? false : file.exists() && file.isFile(); } public static boolean fileExists(String path) { return notNullOrEmpty(path) ? fileExists(new File(path)) : false; } public static class ValList extends ArrayList<Object> { public ValList() { super(); } public ValList(Collection<? extends Object> c) { super(c); } public ValList(int initialCapacity) { super(initialCapacity); } public ValList sizeAtLeast(int size) { while (size() < size) add(null); return this; } @Override public Object get(int index) { if (index < 0) index = size() + index; return super.get(index); } @Override public void add(int index, Object element) { if (index < 0) index = size() + index; super.add(index, element); } @Override public Object remove(int index) { if (index < 0) index = size() + index; return super.remove(index); } } public static <T> ValList vlist(T...values) { return new ValList(asList(values)); } public static ValMap vmap(Object...params) { ValMap map = new ValMap(); for (int i = 0; i < params.length; i+=2) map.put(param_String("", i, params), param(null, i + 1, params)); return map; } public static class ValMap extends HashMap<String,Object> { public ValMap() { super(); } public ValMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } public ValMap(int initialCapacity) { super(initialCapacity); } public ValMap(Map<? extends String, ? extends Object> m) { super(m); } public ValList getList(String key) { Object value = get(key); if (value == null) { ValList list = vlist(); put(key, list); return list; } else if (value instanceof ValList) return (ValList) value; else return null; } public Object getListValue(String key, int index) { return getList(key).get(index); } } public static ValMap mappings = vmap(); public static int clearMappings() { mappings = vmap(); return 0; } // NOTE used in xsl scripts public static String getMapping(String key) { Object value = mappings.get(key); return stringValueOf(value); } // NOTE used in xsl scripts public static String setMapping(String key, String value) { mappings.put(key, value); return ""; } /** * @param d * @param decimalPlace * @return */ public static double round(double d, int decimalPlace) { // see the Javadoc about why we use a String in the constructor // http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html#BigDecimal(double) java.math.BigDecimal bd = new java.math.BigDecimal(Double.toString(d)); bd = bd.setScale(decimalPlace, java.math.BigDecimal.ROUND_HALF_UP); return bd.doubleValue(); } public static double absoluteZero = -273.15; public static double kelvin2celsius(Object value) { double d; if (value instanceof Double) d = (Double) value; else d = toDouble(Double.NaN, value.toString()); return round(d + absoluteZero, 2); } /** * @param <T> type of the given array * @param <U> type of the cast array * @param array the given array * @param a prototype for the cast array * @return the cast array */ public static <T, U> U[] arraycast(T[] array, U[] a) { return asList(array).toArray(a); } public static boolean[] toBooleanArray(List<Boolean> list) { boolean[] primitives = new boolean[list.size()]; for (int i = 0; i < primitives.length; i++) { primitives[i] = list.get(i).booleanValue(); } return primitives; } public static int[] toIntArray(List<Integer> list) { int[] primitives = new int[list.size()]; for (int i = 0; i < primitives.length; i++) { primitives[i] = list.get(i).intValue(); } return primitives; } public static List<Integer> fromIntArray(int[] array) { List<Integer> list = alist(); for (int i = 0; i < array.length; i++) { list.add(array[i]); } return list; } public static long[] toLongArray(List<Long> list) { long[] primitives = new long[list.size()]; for (int i = 0; i < primitives.length; i++) { primitives[i] = list.get(i).longValue(); } return primitives; } public static <T> T[] arrayappend(T[] array, T...elements) { ArrayList<T> list = alist(array); list.addAll(asList(elements)); return list.toArray(array); } public static <T> int arrayindexof(T element, T[] array) { return asList(array).indexOf(element); } public static <T> void arrayreverse(T[] array) { int len = array.length; for (int i = 0; i < len / 2; i++) { T element = array[i]; array[i] = array[len - i - 1]; array[len - i - 1] = element; } } public static void arrayreverse(int[] array) { int len = array.length; for (int i = 0; i < len / 2; i++) { int element = array[i]; array[i] = array[len - i - 1]; array[len - i - 1] = element; } } public static <T> ArrayList<T> alist() { return new ArrayList<T>(); } public static <T> ArrayList<T> alist(T[] elements) { return new ArrayList<T>(asList(elements)); } public static boolean embedsLeft(String whole, String part) { return whole != null && whole.contains(part) && !whole.startsWith(part); } public static boolean embedsRight(String whole, String part) { return whole != null && whole.contains(part) && !whole.endsWith(part); } public static boolean embeds(String whole, String part) { return whole != null && embedsLeft(whole, part) && embedsRight(whole, part); } public static String addPart(String string, String part) { ValList list = split(string, GLUE_REGEX); if (list.add(part)) return join(GLUE, set(list).toArray()); else return string; } public static String removePart(String string, String part) { ValList list = split(string, GLUE_REGEX); if (list.remove(part)) string = join(GLUE, list.toArray()); return string; } public enum Constraint { AMONG(2), START(1), MIDDLE(0), END(-1); final int index; Constraint(int index) { this.index = index; } } public static Boolean among(String string, String regex) { ValList list = split(string, GLUE_REGEX); for (Object element : list) { String part = (String) element; if (part.matches(regex)) return true; } return false; } public static Boolean check(String string, Constraint constraint, String part) { if (string == null) return null; switch (constraint) { case START: return string.startsWith(part); case MIDDLE: return string.contains(part); case AMONG: return among(string, part); case END: return string.endsWith(part); default: return null; } } public static String findFirstFile(File dir, Constraint constraint, String part) { File[] files = dir.listFiles(); if (files != null) for (File file : files) { String path = file.getPath(); if (file.isFile() && check(path, constraint, part)) return path; } return null; } public interface Predicate<T> { boolean apply(T t); } public static <T> Collection<T> filter(Collection<T> target, boolean negate, Predicate<T> predicate) { Collection<T> result = alist(); for (T element: target) { if (predicate.apply(element)) { if (!negate) result.add(element); } else if (negate) result.add(element); } return result; } public static <T> List<Integer> filterIndex(List<T> target, boolean negate, Predicate<T> predicate) { List<Integer> result = alist(); for (int i = 0; i < target.size(); i++) { T element = target.get(i); if (predicate.apply(element)) { if (!negate) result.add(i); } else if (negate) result.add(i); } return result; } public static char decimalSeparator() { NumberFormat f = NumberFormat.getInstance(Locale.getDefault()); if (f instanceof DecimalFormat) { DecimalFormatSymbols symbols = ((DecimalFormat) f).getDecimalFormatSymbols(); return symbols.getDecimalSeparator(); } else return '.'; } public static void delay(long millis) { try { millis += System.currentTimeMillis(); while (System.currentTimeMillis() < millis) Thread.yield(); } catch (Exception e) { Log.e(TAG, "delay", e); } } public static final String PATH_SEP = System.getProperty("file.separator"); // slash public static final String TAB = "\t"; public static final String NEWLINE = "\n"; // System.getProperty("line.separator"); public static final String DOT = "."; public static final String GLUE = "|"; public static final String TAB_REGEX = "\\t"; public static final String NEWLINE_REGEX = "\\n"; public static final String DOT_REGEX = "\\."; public static final String GLUE_REGEX = "\\|"; public static final String WHITESPACE_REGEX = "\\s+"; public static final String WHITESPACE_OR_NOTHING_REGEX = "\\s*"; public static final String SOMETHING_OR_NOTHING_REGEX = ".*"; public static final String[] FOLD_MARKER = strings("{{{", "}}}"); public static final String[] FOLD_MARKER_REGEX = strings("\\{\\{\\{", "\\}\\}\\}"); public static String wildcardRegex(Object wildcard, String...specials) { String chars = join("\\", specials); if (chars.length() > 0) chars = "\\".concat(chars); chars = enclose("[", chars.concat("\\\\w"), "]"); return stringValueOf(wildcard) .replaceAll("\\*", chars.concat("+")) .replaceAll("\\?", chars); } public static String indentedLine(String line, Object level, Object...params) { StringBuffer sb = new StringBuffer(); int indents = param_Integer(0, 0, params); if (level instanceof String) { String indentString = String.valueOf(level); if (notNullOrEmpty(indentString)) for (int i = 0; i < indents; ++i) sb.append(indentString); else sb.append(indents + TAB); } else if (level instanceof Function<?>) sb.append(((Function<?>) level).apply(params)); sb.append(line); sb.append(NEWLINE); return sb.toString(); } public static String flatten(String s) { return s.replaceAll(NEWLINE_REGEX, TAB); } public static boolean isSQLite(File file) { if (fileExists(file)) { String header16 = contentsFromFile(file, 16); return header16.startsWith("SQLite format 3"); } return false; } public static void setPrivateField(Object cl, Object inst, String fieldName, Object value) throws Exception { Class<?> c = cl instanceof Class<?> ? (Class<?>) cl : Class.forName(stringValueOf(cl)); Field field = c.getDeclaredField(fieldName); field.setAccessible(true); field.set(inst, value); } @SuppressWarnings("unchecked") public static <T> T getPrivateField(Object cl, Object inst, String fieldName) { try { Class<?> c = cl instanceof Class<?> ? (Class<?>) cl : Class.forName(stringValueOf(cl)); Field field = c.getDeclaredField(fieldName); field.setAccessible(true); return (T) field.get(inst); } catch (Exception e) { Log.e(TAG, String.format("getPrivateField '%s' in class '%s'", fieldName, cl), e); return null; } } @SuppressWarnings("unchecked") public static <T extends Object> T getConstantByName(String name, String className, String innerClassName) { try { Class<?> c = Class.forName(className); if (notNullOrEmpty(innerClassName)) { Class<?>[] declaredClasses = c.getDeclaredClasses(); c = null; for (Class<?> inner : declaredClasses) if (innerClassName.equals(inner.getSimpleName())) c = inner; } if (c != null) for (Field field : c.getDeclaredFields()) if (name.equals(field.getName())) return (T)field.get(null); } catch (Exception e) { Log.e(TAG, "getConstantByName", e); } return null; } public static String getPackageNameByClass(Class<?> clazz) { String name = clazz.getName(); return name.substring(0, Math.max(0, name.lastIndexOf("."))); } public static BidiMultiMap bmap(int count) { return new BidiMultiMap(new ValList[count]); } public static class BidiMultiMap implements Serializable { private static final long serialVersionUID = UUID.fromString("fe32a444-91e4-4ad2-8b1e-3d4c2f7a26f3").getLeastSignificantBits(); private ValList[] mLists; public BidiMultiMap(ValList...lists) { setLists(lists); } public void setLists(ValList...lists) { if (lists == null) lists = new ValList[0]; int size = 0; for (int i = lists.length - 1; i >= 0; i--) { lists[i] = param_T(vlist(), i, lists); size = Math.max(size, lists[i].size()); } while (lists.length < 2) lists = arrayappend(lists, vlist()); for (int i = 0; i < lists.length; i++) { ValList values = lists[i]; values.sizeAtLeast(size); } mLists = lists; } public ValList[] getLists() { return mLists; } private int[] mIndex = new int[] {0,1}; public int[] getIndex() { return mIndex; } public void setIndex(int...listIndex) { for (int i = 0; i < mIndex.length; i++) { int j = param(mIndex[i], i, listIndex); boolean retval = j > -1 && j < mLists.length; if (retval) mIndex[i] = j; } } public ValList getKeys() { return mLists[mIndex[0]]; } public ValList getValues(int...listIndex) { return isAvailable(0, listIndex) ? (isAvailable(listIndex[0], mLists) ? mLists[listIndex[0]] : null) : mLists[mIndex[1]]; } @Override public String toString() { String separator = GLUE; StringBuilder sb = new StringBuilder(); int keysIndex = mIndex[0]; mIndex[0] = 0; int size = getKeys().size(); for (int i = 0; i < size; i++) { sb.append(String.format("%s", getKeys().get(i))); for (int j = 1; j < mLists.length; j++) { Object val = mLists[j].get(i); sb.append(String.format(separator + "%s", String.valueOf(val))); } if (i < size - 1) sb.append("," + NEWLINE); } mIndex[0] = keysIndex; return enclose("{", sb.toString(), "}"); } public void add(Object...values) { for (int i = 0; i < mLists.length; i++) { Object value = param(null, i, values); mLists[i].add(value); } } public void insert(int index, Object...values) { for (int i = 0; i < mLists.length; i++) { Object value = param(null, i, values); mLists[i].add(index, value); } } public void remove(int index) { for (int i = 0; i < mLists.length; i++) mLists[i].remove(index); } public void removeAll() { for (int i = 0; i < mLists.length; i++) mLists[i].clear(); } public ValList get(int index) { ValList list = vlist(); for (int i = 0; i < mLists.length; i++) list.add(mLists[i].get(index)); return list; } public Integer[] get(Object key) { ValList list = vlist(); List<Object> keys = getKeys(); int index; do { index = keys.lastIndexOf(key); if (index > -1) { list.add(index); keys = keys.subList(0, index); } } while (index > -1); Collections.reverse(list); return list.toArray(new Integer[0]); } public Object getKey(Object value) { int index = getValues().indexOf(value); if (index > -1) return getKeys().get(index); else return null; } public boolean removeKey(Object key) { int index = getKeys().indexOf(key); boolean retval = index > -1; if (retval) remove(index); return retval; } @SuppressWarnings("unchecked") public <T> T getValue(Object key, int...listIndex) { ValList list = getValues(listIndex); if (list == null) return null; int index = getKeys().indexOf(key); if (index > -1) return (T) list.get(index); else return null; } public <T> void putValue(Object key, T value, int...listIndex) { if (getKeys().indexOf(key) < 0) add(key); ValList list = getValues(listIndex); if (list != null) { int index = getKeys().indexOf(key); list.set(index, value); } } public boolean isUnique(Object value, int listIndex) { ValList list = getValues(listIndex); if (list == null) return false; int index = list.indexOf(value); return index > -1 && index == list.lastIndexOf(value); } } public static void redirectOutputToFile(String filename, boolean append) { try { PrintStream pout = new PrintStream( new FileOutputStream( filename, append ) ); System.setOut( pout ); System.setErr( pout ); } catch ( IOException e ) { System.err.println("Can't redirect output to file: "+filename ); } } public static ValMap namedParams(Object...params) { ValMap map = vmap(); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; if (param instanceof String && embedsLeft(param.toString(), "=")) { String[] sides = param.toString().split("=", 2); if (sides.length > 0) { if (sides.length > 1) map.put(sides[0], sides[1]); else map.put(sides[0], ""); continue; } } map.put("param" + i, param); } } return map; } @SuppressWarnings("unchecked") public static <T extends Object> T namedValue(T defaultValue, String name, Map<String, Object> map) throws ClassCastException { if (map.containsKey(name)) try { T returnValue = (T)map.get(name); return returnValue; } catch (ClassCastException e) {} return defaultValue; } public static Boolean namedBoolean(Boolean defaultValue, String name, Map<String, Object> map) { if (map.containsKey(name)) { Object value = map.get(name); if (value instanceof Boolean) return (Boolean) value; else return toBool(defaultValue, "" + value); } else return defaultValue; } public static Integer namedInteger(Integer defaultValue, String name, Map<String, Object> map) { if (map.containsKey(name)) { Object value = map.get(name); if (value instanceof Integer) return (Integer) value; else return toInt(defaultValue, "" + value); } else return defaultValue; } public static Double namedDouble(Double defaultValue, String name, Map<String, Object> map) { if (map.containsKey(name)) { Object value = map.get(name); if (value instanceof Double) return (Double) value; else return toDouble(defaultValue, "" + value); } else return defaultValue; } }