package xapi.collect.impl;
import xapi.annotation.inject.SingletonDefault;
import xapi.collect.api.ClassTo;
import xapi.collect.api.CollectionOptions;
import xapi.collect.api.Fifo;
import xapi.collect.api.IntTo;
import xapi.collect.api.ObjectTo;
import xapi.collect.api.ObjectTo.Many;
import xapi.collect.api.StringDictionary;
import xapi.collect.api.StringTo;
import xapi.collect.proxy.CollectionProxy;
import xapi.collect.proxy.MapOf;
import xapi.collect.service.CollectionService;
import xapi.platform.AndroidPlatform;
import xapi.platform.GwtDevPlatform;
import xapi.platform.JrePlatform;
import xapi.util.X_Runtime;
import static java.util.Collections.synchronizedMap;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@GwtDevPlatform
@JrePlatform
@AndroidPlatform
@SingletonDefault(implFor=CollectionService.class)
public class CollectionServiceDefault implements CollectionService{
static final Comparator<String> STRING_CMP = new Comparator<String>() {
@Override
public int compare(final String o1, final String o2) {
if (o1 == null) {
return o2 == null ? 0 : "".compareTo(o2);
}
return o1.compareTo(o2 == null ? "" : o2);
}
};
static final Comparator<Enum<?>> ENUM_CMP = new Comparator<Enum<?>>() {
@Override
public int compare(final Enum<?> o1, final Enum<?> o2) {
if (o1 == null) {
return o2 == null ? 0 : -o2.ordinal();
}
return o1.ordinal() - (o2 == null ? 0 : o2.ordinal());
}
};
public static final Comparator<Class<?>> CLASS_CMP = new Comparator<Class<?>>() {
@Override
public int compare(final Class<?> o1, final Class<?> o2) {
if (o1 == null) {
return o2 == null ? 0 : -o2.hashCode();
}
return o1.hashCode() - (o2 == null ? 0 : o2.hashCode());
}
};
static final Comparator<Number> NUMBER_CMP = new Comparator<Number>() {
@Override
public int compare(Number o1, Number o2) {
if (o1==null) {
o1=0;
}
if (o2==null) {
o2=0;
}
final double delta = o1.doubleValue() - o2.doubleValue();
if (Math.abs(delta)<0.0000000001) {
return 0;
}
return delta < 0 ? -1 : 1;
}
};
static final Comparator<Object> OBJECT_CMP = new Comparator<Object>() {
@Override
@SuppressWarnings({"unchecked","rawtypes"})
public int compare(final Object o1, final Object o2) {
if (o1 instanceof Comparable) {
return ((Comparable)o1).compareTo(o2);
}
return System.identityHashCode(o1) - System.identityHashCode(o2);
}
};
@SuppressWarnings({ "unchecked", "rawtypes" })
private final CollectionProxy<Class<?>,Comparator<?>> comparators =
newProxy(Class.class, Comparator.class, CollectionOptions.asConcurrent(true).build());
public CollectionServiceDefault() {
comparators.entryFor(Object.class).setValue(OBJECT_CMP);
comparators.entryFor(String.class).setValue(STRING_CMP);
comparators.entryFor(Enum.class).setValue(ENUM_CMP);
comparators.entryFor(Class.class).setValue(CLASS_CMP);
comparators.entryFor(Number.class).setValue(NUMBER_CMP);
comparators.entryFor(Byte.class).setValue(NUMBER_CMP);
comparators.entryFor(Short.class).setValue(NUMBER_CMP);
comparators.entryFor(Integer.class).setValue(NUMBER_CMP);
comparators.entryFor(Long.class).setValue(NUMBER_CMP);
comparators.entryFor(Float.class).setValue(NUMBER_CMP);
comparators.entryFor(Double.class).setValue(NUMBER_CMP);
}
protected <K, V> Map<K,V> newMap(final CollectionOptions opts) {
if (opts.insertionOrdered()) {
if (opts.concurrent()) {
// TODO: something with better performance...
// Perhaps supersource ConcurrentSkipListMap,
// and remove all the contention-worries that plague its implementation
// (why pay to handle concurrent threads in a single-threaded environment?)
return synchronizedMap(new LinkedHashMap<K, V>());
} else {
return new LinkedHashMap<K, V>();
}
}
if (X_Runtime.isMultithreaded()) {
return new ConcurrentHashMap<K,V>();
} else {
return new HashMap<K,V>();
}
}
@Override
public <Type, Generic extends Type> IntTo<Type> newList(final Class<Generic> cls, final CollectionOptions opts) {
return new IntToList<>(cls);
}
@Override
public <E, Generic extends E> IntTo<E> newSet(
Class<Generic> cls, CollectionOptions opts
) {
return new IntToSet<>(cls, opts);
}
@Override
public <K,V> ObjectTo<K,V> newMap(final Class<K> key, final Class<V> cls, final CollectionOptions opts) {
return new MapOf<K,V>(this.<K, V>newMap(opts), key, cls);
}
@Override
public <V, Generic extends V> ClassTo<V> newClassMap(final Class<Generic> cls, final CollectionOptions opts) {
return new ClassToDefault<V>(this.<Class<?>, V>newMap(opts), cls);
}
@Override
public <V, Generic extends V> StringTo<V> newStringMap(final Class<Generic> cls, final CollectionOptions opts) {
return new StringToAbstract<>(cls, this.<String, V>newMap(opts));
}
public <K, V, Key extends K, Value extends V> CollectionProxy<K, V> newProxy(
Class<Key> keyType, Class<Value> valueType, CollectionOptions opts) {
if (opts.insertionOrdered()) {
if (opts.concurrent()) {
return new MapOf<>(synchronizedMap(new LinkedHashMap<>()), keyType, valueType);
} else {
return new MapOf<>(new LinkedHashMap<>(), keyType, valueType);
}
}
if (opts.concurrent()) {
return new MapOf<>(new ConcurrentHashMap<>(), keyType, valueType);
} else {
return new MapOf<>(new HashMap<>(), keyType, valueType);
}
}
@SuppressWarnings({
"unchecked", "unused"
})
private <V> Comparator<V> getComparator(Class<?> cls) {
Comparator<?> cmp = null;
while ((cmp = comparators.get(cls))==null) {
cls = cls.getSuperclass();
}
return (Comparator<V>)cmp;
}
@Override
public <K,V> Many<K,V> newMultiMap(final Class<K> key, final Class<V> cls, final CollectionOptions opts) {
return new ObjectToManyList<>(key, cls, this.<K, IntTo<V>>newMap(opts));
}
@Override
public <V, Generic extends V> ClassTo.Many<V> newClassMultiMap(final Class<Generic> cls, final CollectionOptions opts) {
return new ClassToManyList<>(cls, this.<Class<?>, IntTo<V>>newMap(opts));
}
@Override
public <V, Generic extends V> StringTo.Many<V> newStringMultiMap(final Class<Generic> cls,
final CollectionOptions opts) {
// TODO honor opts
if (opts.insertionOrdered()) {
return new StringToManyList<>(cls,
// ick... we'll get a fast, insertion ordered concurrent map. For now, just make it synchronized :-(
opts.concurrent() ? synchronizedMap(new LinkedHashMap<>()) : new LinkedHashMap<>()
, opts);
}
return new StringToManyList<>(cls, opts);
}
@Override
public <V> StringDictionary<V> newDictionary(Class<V> cls) {
return new StringDictionaryDefault<V>(cls);
}
@Override
public <V> Fifo<V> newFifo() {
return new SimpleFifo<V>();
}
}