package nebula.data;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import com.google.common.base.Function;
import com.google.common.collect.ForwardingList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class SmartList<I, V extends Timable> extends ForwardingList<V> {
final List<V> values;
final Map<I, V> indexedValues;
final Map<I, Integer> indexedIndex;
private List<DataListener<V>> listeneres;
final Function<V, I> indexFunction;
@Override
protected List<V> delegate() {
return values;
}
public SmartList(Function<V, I> indexFunction) {
this.indexFunction = indexFunction;
this.values = new CopyOnWriteArrayList<V>();
this.indexedValues = Maps.newHashMap();
this.indexedIndex = Maps.newHashMap();
this.listeneres = Lists.newArrayList();
}
public <T extends DataListener<V>> T addListener(T listener) {
for (V v : values) {
listener.onAdd(v);
}
listeneres.add(listener);
return listener;
}
/*
* public <K> Classificator<K, V> classify(Function<V, K> indexerFunction) {
* return new DataClassificator<K, V>(values, indexerFunction); }
*
* public <K> Classificator<K, V> liveClassify(Function<V, K>
* indexerFunction) { DataClassificator<K, V> classificator = new
* DataClassificator<K, V>(values, indexerFunction);
* listeneres.add(classificator); return classificator; }
*
* public List<V> filter(Predicate<V> filterFunction) { return new
* DataFilter<V>(values, filterFunction).get(); }
*
* public ClassifiableFilter<V> liveFilter(Predicate<V> filterFunction) {
* DataFilter<V> filter = new DataFilter<V>(values, filterFunction);
* listeneres.add(filter); return filter; }
*/
public V get(I key) {
return this.indexedValues.get(key);
}
@Override
public void add(int index, V v) {
for (DataListener<V> listener : this.listeneres) {
listener.onAdd(v);
}
I key = indexFunction.apply(v);
this.indexedValues.put(key, v);
this.indexedIndex.put(key, index);
super.add(index, v);
}
@Override
public boolean add(V v) {
I key = indexFunction.apply(v);
if (!this.indexedValues.containsKey(key)) {
for (DataListener<V> listener : this.listeneres) {
listener.onAdd(v);
}
boolean result = super.add(v);
this.indexedValues.put(key, v);
this.indexedIndex.put(key, values.size() - 1);
return result;
} else {
V oldData = this.indexedValues.get(key);
int index = this.indexedIndex.get(key);
this.values.set(index, v);
this.indexedValues.put(key, v);
for (DataListener<V> listener : this.listeneres) {
listener.onUpdate(oldData, v);
}
}
return true;
}
public Set<I> keySet() {
return this.indexedValues.keySet();
}
public boolean containsKey(String key) {
return this.indexedIndex.containsKey(key);
}
@Override
public V set(int index, V element) {
return super.set(index, element);
}
@Override
public boolean addAll(Collection<? extends V> c) {
boolean status = false;
for (V v : c) {
status = this.add(v) && status;
}
return status;
}
@Override
public V remove(int index) {
for (DataListener<V> listener : this.listeneres) {
listener.onRemove(this.get(index));
}
I key = indexFunction.apply(this.get(index));
this.indexedValues.remove(key);
this.indexedIndex.remove(key);
return super.remove(index);
}
@Override
public boolean removeAll(Collection<?> collection) {
throw new UnsupportedOperationException("Cann't remove all");
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object v) {
for (DataListener<V> listener : this.listeneres) {
listener.onRemove((V) v);
}
I key = indexFunction.apply((V) v);
this.indexedValues.remove(key);
this.indexedIndex.remove(key);
return super.remove(v);
}
}