package ch.akuhn.hapax.index;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import ch.akuhn.foreach.Each;
public class AssociativeList<E> implements Cloneable, Iterable<E> {
public static final int NONE = -1;
private List<E> list;
private Map<E,Integer> map;
public AssociativeList() {
map = new HashMap<E,Integer>();
list = new ArrayList<E>();
}
public AssociativeList(Iterable<E> collection) {
this();
for (E each: collection) this.add(each);
}
public AssociativeList(AssociativeList<E> index) {
map = new HashMap<E,Integer>(index.map);
list = new ArrayList<E>(index.list);
}
/*default*/ int add(E element) {
if (element == null) throw new IllegalArgumentException();
Integer index = map.get(element);
if (index == null) {
index = list.size();
map.put(element, index);
list.add(element);
}
return index;
}
/*default*/ int remove(E element) {
Integer index = map.remove(element);
if (index == null) return NONE;
list.remove(index.intValue());
for (Map.Entry<E, Integer> each: map.entrySet()) {
Integer eachIndex = each.getValue();
if (eachIndex > index) each.setValue(eachIndex - 1);
}
return index;
}
@Override
public AssociativeList<E> clone() {
return new AssociativeList<E>(this);
}
public int get(E element) {
Integer index = map.get(element);
return index == null ? NONE : index;
}
public E get(int index) {
if (index >= list.size()) return null;
return list.get(index);
}
@Override
public Iterator<E> iterator() {
return Collections.unmodifiableCollection(list).iterator();
}
public int size() {
return list.size();
}
public boolean contains(E element) {
return map.containsKey(element);
}
public Iterable<Each<E>> withIndices() {
return new Iterable<Each<E>>() {
@Override
public Iterator<Each<E>> iterator() {
return new Iter<E>(list.iterator());
}
};
}
private static class Iter<E> implements Iterator<Each<E>> {
private Iterator<E> iterator;
private Each<E> each = new Each<E>();
private int index = 0;
/*default*/ Iter(Iterator<E> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Each<E> next() {
if (!hasNext()) throw new NoSuchElementException();
each.value = iterator.next();
each.index = index++;
return each;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
public List<E> asList() {
return new ArrayList<E>(list);
}
}