package xapi.collect.impl;
import xapi.collect.X_Collect;
import xapi.collect.api.CollectionOptions;
import xapi.collect.api.IntTo;
import xapi.collect.api.ObjectTo;
import xapi.collect.api.StringTo;
import xapi.fu.In2Out1;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class IntToManyList <X> implements IntTo.Many<X>{
private final StringTo.Many<X> map;
private final Class<X> componentClass;
private int max;
public IntToManyList(final Class<X> componentClass) {
this.map = X_Collect.newStringMultiMap(componentClass, new TreeMap<String, IntTo<X>>());
this.componentClass = componentClass;
}
@Override
public Iterable<IntTo<X>> forEach() {
return map.values();
}
public Class<Integer> keyType() {
return Integer.class;
}
public Class<IntTo<X>> valueType() {
return Class.class.cast(IntTo.class);
}
@Override
public boolean add(final IntTo<X> item) {
updateMax();
map.put(Integer.toString(max++), item);
return true;
}
private void updateMax() {
// TODO limit this brute force approach so that sparse arrays don't suffer
while (map.containsKey(Integer.toString(max++))) {
;
}
}
@Override
public void add(final int key, final X item) {
assert item == null || componentClass == null || componentClass.isAssignableFrom(item.getClass());
map.get(Integer.toString(key)).add(item);
}
@Override
public boolean addAll(final Iterable<IntTo<X>> items) {
updateMax();
for (final IntTo<X> item : items) {
map.put(Integer.toString(max++), item);
}
return true;
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(final IntTo<X>... items) {
updateMax();
for (final IntTo<X> item : items) {
map.put(Integer.toString(max++), item);
}
return true;
}
@Override
public boolean insert(final int pos, final IntTo<X> item) {
if (pos > max) {
max = pos+1;
}
map.put(Integer.toString(pos), item);
return false;
}
@Override
public boolean contains(final IntTo<X> value) {
if (value == null) {
return false;
}
main:
for (final IntTo<X> item : map.values()) {
if (item.size() == value.size()) {
for (int i = item.size(); i-->0;) {
if (!equals(item.get(i), value.get(i))) {
continue main;
}
}
return true;
}
}
return false;
}
private boolean equals(final X x, final X x2) {
return x == null ? x2 == null : x.equals(x2);
}
@Override
public IntTo<X> at(final int index) {
return map.get(Integer.toString(index));
}
@Override
public int indexOf(final IntTo<X> value) {
if (value == null) {
return -1;
}
final String[] keys = map.keyArray();
main:
for (int i = keys.length; i-->0;) {
final String key = keys[i];
final IntTo<X> item = map.get(key);
if (item.size() == value.size()) {
for (int j = item.size(); j-->0;) {
if (!equals(item.get(j), value.get(j))) {
continue main;
}
}
return Integer.parseInt(key);
}
}
return -1;
}
@Override
public boolean remove(final int index) {
return map.remove(Integer.toString(index)) != null;
}
@Override
public boolean findRemove(final IntTo<X> value, final boolean all) {
if (value == null) {
return false;
}
boolean success = false;
final String[] keys = map.keyArray();
main:
for (int i = keys.length; i-->0;) {
final String key = keys[i];
final IntTo<X> item = map.get(key);
if (item.size() == value.size()) {
for (int j = item.size(); j-->0;) {
if (!equals(item.get(j), value.get(j))) {
continue main;
}
}
if (!all) {
return true;
}
success = true;
}
}
return success;
}
@Override
public void set(final int index, final IntTo<X> value) {
if (index > max) {
max = index+1;
}
map.put(Integer.toString(index), value);
}
@Override
public void push(final IntTo<X> value) {
updateMax();
map.put(Integer.toString(max++), value);
}
@Override
public IntTo<X> pop() {
updateMax();
max--;
final IntTo<X> items = map.remove(Integer.toString(max));
if (items != null) {
return items;
}
final String[] keys = map.keyArray();
Arrays.sort(keys);
return map.remove(keys[keys.length-1]);
}
@Override
public List<IntTo<X>> asList() {
final List<IntTo<X>> list = newList();
final String[] keys = map.keyArray();
Arrays.sort(keys);
for (final String key : keys) {
list.add(map.get(key));
}
return list;
}
@Override
@SuppressWarnings("unchecked")
public Set<IntTo<X>> asSet() {
final Set<IntTo<X>> set = newSet();
if (map instanceof StringToAbstract) {
set.addAll(((StringToAbstract<IntTo<X>>)map).valueSet());
} else {
for (final IntTo<X> value : map.values()) {
set.add(value);
}
}
return set;
}
@Override
public Deque<IntTo<X>> asDeque() {
final Deque<IntTo<X>> deque = newDeque();
final String[] keys = map.keyArray();
Arrays.sort(keys);
for (final String key : keys) {
deque.add(map.get(key));
}
return deque;
}
protected List<IntTo<X>> newList() {
return new ArrayList<IntTo<X>>();
}
protected Set<IntTo<X>> newSet() {
return new LinkedHashSet<IntTo<X>>();
}
protected Deque<IntTo<X>> newDeque() {
return new ArrayDeque<IntTo<X>>();
}
protected Map<Integer, IntTo<X>> newMap() {
return new TreeMap<Integer, IntTo<X>>();
}
@Override
public ObjectTo<Integer, IntTo<X>> clone(final CollectionOptions options) {
throw new UnsupportedOperationException();
}
@Override
public IntTo<X> put(final Entry<Integer, IntTo<X>> item) {
return map.put(Integer.toString(item.getKey()), item.getValue());
}
@Override
public Entry<Integer, IntTo<X>> entryFor(final Object key) {
final String asString = String.valueOf(key);
final int asInt = Integer.parseInt(asString);
return new Entry<Integer, IntTo<X>>() {
@Override
public Integer getKey() {
return asInt;
}
@Override
public IntTo<X> getValue() {
return map.get(asString);
}
@Override
public IntTo<X> setValue(final IntTo<X> value) {
return map.put(asString, value);
}
};
}
@Override
public IntTo<X> get(final Object key) {
assertValid(key);
return map.get(String.valueOf(key));
}
private void assertValid(final Object key) {
assert Integer.parseInt(String.valueOf(key)) >= Integer.MIN_VALUE;
}
@Override
@SuppressWarnings("unchecked")
public void setValue(final Object key, final Object value) {
assertValid(key);
if ((Integer)key > max) {
max = (Integer)key;
}
map.put(String.valueOf(key), (IntTo<X>)value);
}
@Override
public IntTo<X> remove(final Object key) {
assertValid(key);
if (key.equals(max-1)) {
max--;
}
return map.remove(String.valueOf(key));
}
@Override
public int size() {
return map.size();
}
@Override
public IntTo<X>[] toArray() {
updateMax();
@SuppressWarnings("unchecked")
final
IntTo<X>[] results = new IntTo[max];
for (int i = max;i-->0;) {
results[i] = map.get(String.valueOf(i));
}
assert noNegatives() : "Cannot use .toArray on an IntTo.Many with negative key values: "+Arrays.asList(map.keyArray());
return results;
}
private boolean noNegatives() {
for (final String key : map.keyArray()) {
if (Integer.parseInt(key) < 0) {
return false;
}
}
return true;
}
@Override
@SuppressWarnings({
"rawtypes", "unchecked"
})
public Collection<IntTo<X>> toCollection(Collection<IntTo<X>> into) {
if (into == null) {
into = newList();
}
if (map instanceof StringToAbstract) {
into.addAll(((StringToAbstract) map).valueSet());
} else {
final String[] keys = map.keyArray();
Arrays.sort(keys);
for (final String key : keys) {
into.add(map.get(key));
}
}
return into;
}
@Override
public Map<Integer, IntTo<X>> toMap(Map<Integer, IntTo<X>> into) {
if (into == null) {
into = newMap();
}
for (final String key : map.keyArray()) {
into.put(Integer.parseInt(key), map.get(key));
}
return into;
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public void clear() {
map.clear();
max = 0;
}
@Override
public boolean readWhileTrue(In2Out1<Integer, IntTo<X>, Boolean> callback) {
for (int i = 0, m = size(); i < m; i++ ) {
if (!callback.io(i, get(i))) {
return false;
}
}
return true;
}
}