package jtrade.util;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.Duration;
import org.joda.time.LocalTime;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormat;
public class Util {
private static final int INSERTION_SORT_CUTOFF = 10;
public static double select(double[] data, int k) {
double[] a = data.clone();
quickSelect(a, k);
return a[k - 1];
}
public static void quickSelect(double[] a, int k) {
quickSelect(a, 0, a.length - 1, k);
}
private static void quickSelect(double[] a, int low, int high, int k) {
if (low + INSERTION_SORT_CUTOFF > high) {
insertionSort(a, low, high);
return;
}
// Sort low, middle, high
int middle = (low + high) / 2;
if (a[middle] < a[low]) {
swap(a, low, middle);
}
if (a[high] < a[low]) {
swap(a, low, high);
}
if (a[high] < a[middle]) {
swap(a, middle, high);
}
// Place pivot at position high - 1
swap(a, middle, high - 1);
double pivot = a[high - 1];
// Begin partitioning
int i, j;
for (i = low, j = high - 1;;) {
while (a[++i] < pivot)
;
while (pivot < (a[--j]))
;
if (i >= j) {
break;
}
swap(a, i, j);
}
// Restore pivot
swap(a, i, high - 1);
// Recurse; only this part changes
if (k <= i) {
quickSelect(a, low, i - 1, k);
} else if (k > i + 1) {
quickSelect(a, i + 1, high, k);
}
}
public static void insertionSort(double[] a, int low, int high) {
for (int p = low + 1; p <= high; p++) {
double tmp = a[p];
int j;
for (j = p; j > low && tmp < (a[j - 1]); j--) {
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
private static <T> void swap(double[] a, int i, int j) {
double tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
public static <T extends Comparable<T>> T select(T[] data, int k) {
T[] a = data.clone();
quickSelect(a, k);
return a[k - 1];
}
/**
* Quick selection algorithm. Places the kth smallest item in a[k-1].
*
* @param a
* an array of Comparable items.
* @param k
* the desired rank (1 is minimum) in the entire array.
*/
public static <T extends Comparable<T>> void quickSelect(T[] a, int k) {
quickSelect(a, 0, a.length - 1, k);
}
/**
* Internal selection method that makes recursive calls. Uses median-of-three
* partitioning and a cutoff of 10. Places the kth smallest item in a[k-1].
*
* @param a
* an array of Comparable items.
* @param low
* the left-most index of the subarray.
* @param high
* the right-most index of the subarray.
* @param k
* the desired rank (1 is minimum) in the entire array.
*/
private static <T extends Comparable<T>> void quickSelect(T[] a, int low, int high, int k) {
if (low + INSERTION_SORT_CUTOFF > high) {
insertionSort(a, low, high);
return;
}
// Sort low, middle, high
int middle = (low + high) / 2;
if (a[middle].compareTo(a[low]) < 0) {
swap(a, low, middle);
}
if (a[high].compareTo(a[low]) < 0) {
swap(a, low, high);
}
if (a[high].compareTo(a[middle]) < 0) {
swap(a, middle, high);
}
// Place pivot at position high - 1
swap(a, middle, high - 1);
T pivot = a[high - 1];
// Begin partitioning
int i, j;
for (i = low, j = high - 1;;) {
while (a[++i].compareTo(pivot) < 0)
;
while (pivot.compareTo(a[--j]) < 0)
;
if (i >= j) {
break;
}
swap(a, i, j);
}
// Restore pivot
swap(a, i, high - 1);
// Recurse; only this part changes
if (k <= i) {
quickSelect(a, low, i - 1, k);
} else if (k > i + 1) {
quickSelect(a, i + 1, high, k);
}
}
/**
* Internal insertion sort routine for subarrays that is used by quicksort.
*
* @param a
* an array of Comparable items.
* @param low
* the left-most index of the subarray.
* @param n
* the number of items to sort.
*/
private static <T extends Comparable<T>> void insertionSort(T[] a, int low, int high) {
for (int p = low + 1; p <= high; p++) {
T tmp = a[p];
int j;
for (j = p; j > low && tmp.compareTo(a[j - 1]) < 0; j--) {
a[j] = a[j - 1];
}
a[j] = tmp;
}
}
private static <T> void swap(T[] a, int i, int j) {
T tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
public static Object callMethod(Object obj, String method, Object... args) {
try {
Class<?>[] classes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
classes[i] = args[i].getClass();
}
Method m = obj.getClass().getDeclaredMethod(method, classes);
m.setAccessible(true);
return m.invoke(obj, args);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
public static Field getField(Class<?> cls, String name) {
Field[] fields = cls.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(name)) {
return fields[i];
}
}
if (cls.getSuperclass() != null) {
Field f = getField(cls.getSuperclass(), name);
if (f != null) {
return f;
}
}
return null;
}
public static Collection<Field> getFields(Class<?> cls) {
Collection<Field> result = new LinkedHashSet<Field>();
if (cls.getSuperclass() != null) {
result.addAll(getFields(cls.getSuperclass()));
}
Field[] fields = cls.getFields();
for (int i = 0; i < fields.length; i++) {
result.add(fields[i]);
}
return result;
}
public static Object coerceType(Object obj, Class<?> type) {
if (obj == null) {
return null;
}
if (type == null) {
return obj;
}
if (type.isAssignableFrom(obj.getClass())) {
return obj;
}
if (type.equals(String.class)) {
return obj.toString();
} else if (type.equals(Boolean.class)) {
return Boolean.valueOf(obj.toString());
} else if (type.equals(Integer.class)) {
if (obj instanceof Number) {
return Integer.valueOf(((Number) obj).intValue());
}
return Integer.valueOf(obj.toString());
} else if (type.equals(Long.class)) {
if (obj instanceof Number) {
return Long.valueOf(((Number) obj).longValue());
}
return Long.valueOf(obj.toString());
} else if (type.equals(Float.class)) {
if (obj instanceof Number) {
return Float.valueOf(((Number) obj).floatValue());
}
return Float.valueOf(obj.toString().replace(',', '.'));
} else if (type.equals(Double.class)) {
if (obj instanceof Number) {
return Double.valueOf(((Number) obj).doubleValue());
}
return Double.valueOf(obj.toString().replace(',', '.'));
} else if (type.equals(Byte.class)) {
return Byte.valueOf(obj.toString());
} else if (type.equals(Short.class)) {
return Short.valueOf(obj.toString());
} else if (type.equals(BigInteger.class)) {
return new BigInteger(obj.toString());
} else if (type.equals(BigDecimal.class)) {
return new BigDecimal(obj.toString().replace(',', '.'));
} else if (type.equals(LocalTime.class)) {
return DateTimeFormat.forPattern("HH:mm:ss").parseLocalTime(obj.toString());
} else if (type.equals(DateTime.class)) {
return DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").parseDateTime(obj.toString());
} else if (type.equals(File.class)) {
return new File(obj.toString());
} else if (type.equals(Class.class)) {
try {
return Class.forName(obj.toString());
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
} else {
try {
return type.getConstructor(String.class).newInstance(obj.toString());
} catch (Exception e) {
}
}
throw new IllegalArgumentException("Cannot coerce '" + obj + "' to '" + type + "'");
}
public static void copyProperties(Object source, Object dest) {
if (source instanceof Map) {
for (Iterator<?> iter = ((Map<?, ?>) source).entrySet().iterator(); iter.hasNext();) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) iter.next();
setProperty(dest, (String) entry.getKey(), entry.getValue());
}
return;
}
PropertyDescriptor[] descriptors = getPropertyDescriptors(source.getClass());
for (int i = 0; i < descriptors.length; i++) {
PropertyDescriptor d = descriptors[i];
Object value;
try {
value = d.getReadMethod().invoke(source);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot get property '" + d.getName() + "' from object '" + source + "'", e);
}
setProperty(dest, d.getName(), value);
}
}
@SuppressWarnings("unchecked")
public static void setProperty(Object object, String property, Object value) {
if (object instanceof Map) {
((Map<String, Object>) object).put(property, value);
return;
}
PropertyDescriptor descriptor = getPropertyDescriptor(object.getClass(), property);
if (descriptor == null || descriptor.getWriteMethod() == null) {
return;
}
try {
descriptor.getWriteMethod().invoke(object, coerceType(value, descriptor.getPropertyType()));
} catch (Exception e) {
throw new IllegalArgumentException("Cannot set property '" + property + "' from object '" + object + "'", e);
}
}
public static Object getProperty(Object object, String property) {
if (object instanceof Map) {
return ((Map<?, ?>) object).get(property);
}
PropertyDescriptor descriptor = getPropertyDescriptor(object.getClass(), property);
if (descriptor == null || descriptor.getReadMethod() == null) {
return null;
}
try {
return descriptor.getReadMethod().invoke(object);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot get property '" + property + "' from object '" + object + "'", e);
}
}
public static double getDoubleProperty(Object object, String property) {
Object val = getProperty(object, property);
if (val == null) {
return Double.NaN;
}
return ((Number) val).doubleValue();
}
public static Map<String, Object> getProperties(Object object) {
Map<String, Object> properties = new TreeMap<String, Object>();
if (object instanceof Map) {
for (Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
properties.put(entry.getKey() != null ? entry.getKey().toString() : "null", entry.getValue());
}
return properties;
}
Class<?> objectClass = null;
if (object instanceof Class) {
objectClass = (Class<?>) object;
} else {
objectClass = object.getClass();
}
PropertyDescriptor[] descriptors = getPropertyDescriptors(objectClass);
for (int i = 0; i < descriptors.length; i++) {
try {
properties.put(descriptors[i].getName(), descriptors[i].getReadMethod().invoke(object));
} catch (Exception e) {
throw new IllegalArgumentException("Cannot get property '" + descriptors[i].getName() + "' from object '" + object + "'", e);
}
}
return properties;
}
public static PropertyDescriptor[] getPropertyDescriptors(Class<?> cls) {
try {
return Introspector.getBeanInfo(cls).getPropertyDescriptors();
} catch (Exception e) {
throw new IllegalArgumentException("Cannot get descriptors from class '" + cls + "'", e);
}
}
public static PropertyDescriptor getPropertyDescriptor(Class<?> entityClass, String property) {
PropertyDescriptor[] descriptors = getPropertyDescriptors(entityClass);
for (int i = 0; i < descriptors.length; i++) {
PropertyDescriptor d = descriptors[i];
if (d.getName().equals(property)) {
return d;
}
}
return null;
}
public static boolean isInt(String str) {
try {
Integer.parseInt(str);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
public static boolean isLong(String str) {
try {
Long.parseLong(str);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
public static boolean isDouble(String str) {
try {
Double.parseDouble(str);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
public static String join(String[] strings, String delimiter) {
return join(strings, delimiter, 0, strings.length);
}
public static String join(String[] strings, String delimiter, int start, int end) {
int len = end - start;
if (len <= 0) {
return "";
}
if (len == 1) {
return strings[0];
}
StringBuilder buf = new StringBuilder();
int j = end - 1;
for (int i = start; i < end; i++) {
buf.append(strings[i]);
if (i < j) {
buf.append(delimiter);
}
}
return buf.toString();
}
public static String[] split(String str, char delimiter) {
return split(str, delimiter, false);
}
public static String[] split(String str, char delimiter, boolean trim) {
int delimIdx = 0, count = 1, pos = 0, i = 0;
int len = str.length();
do {
delimIdx = str.indexOf(delimiter, pos);
if (delimIdx == -1) {
break;
}
count++;
pos = delimIdx + 1;
} while (pos < len);
pos = 0;
String[] strings = new String[count];
if (trim) {
do {
delimIdx = str.indexOf(delimiter, pos);
if (delimIdx == -1) {
strings[i] = str.substring(pos).trim();
break;
}
strings[i++] = (delimIdx - pos != 0 ? str.substring(pos, delimIdx).trim() : "");
pos = delimIdx + 1;
} while (pos <= len);
} else {
do {
delimIdx = str.indexOf(delimiter, pos);
if (delimIdx == -1) {
strings[i] = str.substring(pos);
break;
}
strings[i++] = (delimIdx - pos != 0 ? str.substring(pos, delimIdx) : "");
pos = delimIdx + 1;
} while (pos <= len);
}
return strings;
}
public static String[] split(String str, String delimiter) {
return split(str, delimiter, false);
}
public static String[] split(String str, String delimiter, boolean trim) {
int delimIdx = 0, count = 1, pos = 0, i = 0;
int len = str.length();
int delimLen = delimiter.length();
do {
delimIdx = str.indexOf(delimiter, pos);
if (delimIdx == -1) {
break;
}
count++;
pos = delimIdx + delimLen;
} while (pos < len);
pos = 0;
String[] strings = new String[count];
if (trim) {
do {
delimIdx = str.indexOf(delimiter, pos);
if (delimIdx == -1) {
strings[i] = str.substring(pos).trim();
break;
}
strings[i++] = (delimIdx - pos != 0 ? str.substring(pos, delimIdx).trim() : "");
pos = delimIdx + delimLen;
} while (pos <= len);
} else {
do {
delimIdx = str.indexOf(delimiter, pos);
if (delimIdx == -1) {
strings[i] = str.substring(pos);
break;
}
strings[i++] = (delimIdx - pos != 0 ? str.substring(pos, delimIdx) : "");
pos = delimIdx + delimLen;
} while (pos <= len);
}
return strings;
}
public static String[] split(String str, char delimiter, String[] strings) {
int delimIdx = 0, pos = 0, i = 0;
int len = str.length();
do {
delimIdx = str.indexOf(delimiter, pos);
if (delimIdx == -1) {
strings[i] = str.substring(pos);
break;
}
strings[i++] = (delimIdx - pos != 0 ? str.substring(pos, delimIdx) : "");
pos = delimIdx + 1;
} while (pos <= len);
return strings;
}
public static String toString(Object obj) {
Class<?> cls = obj.getClass();
if (cls.isArray()) {
int len = Array.getLength(obj);
if (len == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder();
sb.append('[');
int j = len - 1;
for (int i = 0; i < len; i++) {
Object o = Array.get(obj, i);
sb.append(o != null ? o.toString() : "null");
if (i < j) {
sb.append(", ");
}
}
return sb.append(']').toString();
}
StringBuilder buf = new StringBuilder();
buf.append(cls.getSimpleName());
buf.append(" [");
try {
List<Class<?>> classes = new ArrayList<Class<?>>();
while (cls != null) {
classes.add(cls);
cls = cls.getSuperclass();
}
Collection<Field> fields = new LinkedHashSet<Field>();
for (int i = classes.size() - 1; i >= 0; i--) {
Field[] fs = classes.get(i).getDeclaredFields();
for (int j = 0; j < fs.length; j++) {
Field f = fs[j];
if (f.isSynthetic() || Modifier.isStatic(f.getModifiers())) {
continue;
}
fields.add(f);
}
}
int k = 0;
for (Field f : fields) {
if (k > 0) {
buf.append(", ");
}
f.setAccessible(true);
buf.append(f.getName());
buf.append("=");
Object v = f.get(obj);
if (f.getType().isArray()) {
int len = Array.getLength(v);
if (len == 0) {
buf.append("[]");
} else if (len > 100) {
buf.append("[...]");
} else {
buf.append('[');
buf.append(Array.get(v, 0));
for (int i = 1; i < len; i++) {
buf.append(", ");
buf.append(Array.get(v, i));
}
buf.append(']');
}
} else {
buf.append(v);
}
f.setAccessible(false);
k++;
}
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
buf.append("]");
return buf.toString();
}
public static <T extends Comparable<T>> T max(T[] data) {
final int len = data.length;
if (len == 0) {
return null;
}
T max = data[0];
for (int i = 1; i < len; i++) {
T v = data[i];
if (v != null && v.compareTo(max) > 0) {
max = v;
}
}
return max;
}
public static <T extends Comparable<T>> T min(T[] data) {
final int len = data.length;
if (len == 0) {
return null;
}
T min = data[0];
for (int i = 1; i < len; i++) {
T v = data[i];
if (v != null && v.compareTo(min) < 0) {
min = v;
}
}
return min;
}
public static DateTime dateTimeFloor(DateTime dt, Duration millis) {
return new DateTime(dt.getMillis() - (dt.getMillis() % millis.getMillis()));
}
public static DateTime dateTimeFloor(DateTime dt, Period p) {
if (p.getYears() != 0) {
return dt.yearOfEra().roundFloorCopy().minusYears(dt.getYearOfEra() % p.getYears());
} else if (p.getMonths() != 0) {
return dt.monthOfYear().roundFloorCopy().minusMonths((dt.getMonthOfYear() - 1) % p.getMonths());
} else if (p.getWeeks() != 0) {
return dt.weekOfWeekyear().roundFloorCopy().minusWeeks((dt.getWeekOfWeekyear() - 1) % p.getWeeks());
} else if (p.getDays() != 0) {
return dt.dayOfMonth().roundFloorCopy().minusDays((dt.getDayOfMonth() - 1) % p.getDays());
} else if (p.getHours() != 0) {
return dt.hourOfDay().roundFloorCopy().minusHours(dt.getHourOfDay() % p.getHours());
} else if (p.getMinutes() != 0) {
return dt.minuteOfHour().roundFloorCopy().minusMinutes(dt.getMinuteOfHour() % p.getMinutes());
} else if (p.getSeconds() != 0) {
return dt.secondOfMinute().roundFloorCopy().minusSeconds(dt.getSecondOfMinute() % p.getSeconds());
}
return dt.millisOfSecond().roundCeilingCopy().minusMillis(dt.getMillisOfSecond() % p.getMillis());
}
public static boolean isWorkingDay(DateTime dt) {
return dt.getDayOfWeek() <= 5;
}
public static boolean isDate(DateTime dt1, DateTime dt2) {
return dt1.getDayOfYear() == dt2.getDayOfYear() && dt1.getYear() == dt2.getYear();
}
public static boolean isTime(DateTime dt, LocalTime t) {
return isTime(dt, t, 10000);
}
public static boolean isTime(DateTime dt, LocalTime t, long toleranceMillis) {
return Math.abs(dt.getMillisOfDay() - t.getMillisOfDay()) <= toleranceMillis;
}
public static boolean isTime(DateTime dt1, DateTime dt2) {
return isTime(dt1, dt2, 10000);
}
public static boolean isTime(DateTime dt1, DateTime dt2, long toleranceMillis) {
return Math.abs(dt1.getMillisOfDay() - dt2.getMillisOfDay()) <= toleranceMillis;
}
public static boolean isTimeExactly(DateTime dt, LocalTime t) {
return dt.getMillisOfDay() == t.getMillisOfDay();
}
public static boolean isTimeExactly(DateTime dt1, DateTime dt2) {
return dt1.getMillisOfDay() == dt2.getMillisOfDay();
}
public static boolean isBetween(DateTime dt, LocalTime t1, LocalTime t2) {
int md = dt.getMillisOfDay();
return dt.getMillisOfDay() >= t1.getMillisOfDay() && md < t2.getMillisOfDay();
}
public static boolean isAfter(DateTime dt, LocalTime t) {
return dt.getMillisOfDay() > t.getMillisOfDay();
}
public static boolean isAfterOrEqual(DateTime dt, LocalTime t) {
return dt.getMillisOfDay() >= t.getMillisOfDay();
}
public static boolean isBefore(DateTime dt, LocalTime t) {
return dt.getMillisOfDay() < t.getMillisOfDay();
}
public static boolean isBeforeOrEqual(DateTime dt, LocalTime t) {
return dt.getMillisOfDay() <= t.getMillisOfDay();
}
public static boolean isWeekDay(DateTime dt) {
return dt.getDayOfWeek() < DateTimeConstants.SATURDAY;
}
public static LocalTime toLocalTime(String time) {
return DateTimeFormat.forPattern("HH:mm:ss").parseDateTime(time).toLocalTime();
}
public static DateTime toDate(String date) {
return DateTimeFormat.forPattern("yyyyMMdd").parseDateTime(date);
}
public static DateTime toDateTime(String dateTime) {
return DateTimeFormat.forPattern("yyyyMMdd HH:mm:ss").parseDateTime(dateTime);
}
public static double round(double d, int decimals) {
if (d != d) {
return Double.NaN;
}
double n = Math.pow(10, decimals);
return Math.round(d * n) / n;
}
public static double round(double d, double fraction) {
if (d != d) {
return Double.NaN;
}
return Math.round(d * fraction) / fraction;
}
public static double roundSig(double d, int n) {
if (d != d) {
return Double.NaN;
}
if (d == 0) {
return 0;
}
int power = n - (int) Math.ceil(Math.log10(d < 0 ? -d : d));
double magnitude = Math.pow(10, power);
return Math.round(d * magnitude) / magnitude;
}
}