package xapi.collect.impl; import xapi.collect.api.CollectionOptions; import xapi.collect.api.IntTo; import xapi.collect.api.ObjectTo; import xapi.collect.proxy.CollectionProxy; import xapi.fu.In1Out1; import xapi.fu.In2Out1; import xapi.fu.Out2; import javax.inject.Provider; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; public abstract class ObjectToAbstract<K,V> implements ObjectTo<K,V> { public static abstract class ManyAbstract<K,V> extends ObjectToAbstract<K,IntTo<V>> implements ObjectTo.Many<K,V> { private Class<V> componentType; @SuppressWarnings("unchecked") public ManyAbstract( Class<K> keyType, Class<V> valueType, CollectionProxy<K,IntTo<V>> store, Provider<Iterable<Entry<K,IntTo<V>>>> iteratorProvider, Comparator<K> keyComparator, Comparator<IntTo<V>> valueComparator) { super(keyType, Class.class.cast(IntTo.class),// ya, that's what java generics require... store, iteratorProvider, keyComparator, valueComparator); this.componentType = valueType; } @Override public IntTo<V> getOrCompute(K key, In1Out1<K, IntTo<V>> factory) { IntTo<V> existing = get(key); if (existing == null) { existing = factory.io(key); put(key, existing); } return existing; } @Override public Class<?> componentType() { return componentType; } } private final CollectionProxy<K,V> store; private Provider<Iterable<Entry<K,V>>> iterator; @SuppressWarnings("rawtypes") private Comparator keyComparator; @SuppressWarnings("rawtypes") private Comparator valueComparator; private Class<K> keyType; private Class<V> valueType; public ObjectToAbstract( Class<K> keyType, Class<V> valueType, CollectionProxy<K,V> store, Provider<Iterable<Entry<K,V>>> iteratorProvider, Comparator<K> keyComparator, Comparator<V> valueComparator ) { this.keyType = keyType; this.valueType = valueType; this.store = store; this.iterator = iteratorProvider; this.keyComparator = keyComparator; this.valueComparator = valueComparator; } protected Collection<V> newCollection() { return new ArrayList<V>(); } protected Map<K,V> newMap() { return new HashMap<K, V>(); } /** * @return - The class of the type used for keys. */ @Override public Class<K> keyType() { return keyType; } /** * @return - The class of the type used for values.<br> * Note that this may not be the value type V; {@link ObjectTo.Many} uses IntTo<V> */ @Override public Class<V> valueType() { return valueType; } /** * @return - The class of the root component type of values. * Where {@link ObjectTo.Many#valueType()} returns IntTo<V>.class, * getComponentType() will return V.class */ @Override public Class<?> componentType() { return valueType; } @Override public Iterable<Entry<K,V>> entries() { return iterator.get(); } @Override public V[] toArray() { return store.toArray(); } @Override public Collection<V> toCollection(Collection<V> into) { if (into == null) { into = newCollection(); } fillCollection(into); return into; } protected void fillCollection(Collection<V> into) { for (Entry<K, V> key : entries()) { into.add(key.getValue()); } } protected void fillMap(Map<K,V> into) { for (Entry<K, V> key : entries()) { into.put(key.getKey(), key.getValue()); } } @Override public Map<K,V> toMap(Map<K,V> into) { if (into == null) { into = newMap(); } fillMap(into); return into; } @Override public ObjectTo<K,V> clone(CollectionOptions options) { ObjectTo<K,V> map = null; return map; } @Override @SuppressWarnings("unchecked") public boolean containsKey(Object key) { for (Entry<K,V> entry : entries()) { if (keyComparator.compare(entry.getKey(), key) == 0) return true; } return false; } @Override @SuppressWarnings("unchecked") public boolean containsValue(Object value) { for (Entry<K,V> entry : entries()) { if (valueComparator.compare(entry.getValue(), value) == 0) return true; } return false; } @Override public V get(Object key) { return store.get(key); } @Override public V put(Entry<K, V> item) { return store.put(item); } @Override public V remove(Object key) { return store.remove(key); } @Override public void putAll(Iterable<Entry<K,V>> items) { for (Entry<K,V> item : items) { assert item != null; put(item.getKey(), item.getValue()); } } @Override public void addAll(Iterable<Out2<K, V>> items) { for (Out2<K,V> item : items) { assert item != null; put(item.out1(), item.out2()); } } @Override public void removeAll(Iterable<K> items) { for (K key : items) { remove(key); } } @Override public Iterable<K> keys() { return new EntryKeyAdapter<K, V>(entries()); } @Override public Iterable<V> values() { return new EntryValueAdapter<K, V>(entries()); } @Override public int size() { return store.size(); } @Override public void clear() { store.clear(); } @Override public boolean isEmpty() { return store.isEmpty(); } @Override public boolean readWhileTrue(In2Out1<K, V, Boolean> callback) { for (Entry<K, V> e : entries()) { if (!callback.io(e.getKey(), e.getValue())) { return false; } } return true; } }