package lighthouse.utils;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ObservableListBase;
import javafx.collections.WeakListChangeListener;
import java.util.ArrayList;
import java.util.List;
/**
* This list is created by dynamically concatenating all the source lists together.
*/
public class ConcatenatingList<T> extends ObservableListBase<T> implements ObservableList<T> {
private List<ObservableList<T>> sources = new ArrayList<>();
private ListChangeListener<T> listener = this::sourceChanged;
@SafeVarargs
public ConcatenatingList(ObservableList<T>... source) {
super();
for (ObservableList<T> s : source) {
sources.add(s);
s.addListener(new WeakListChangeListener<T>(listener));
}
if (sources.isEmpty())
throw new IllegalArgumentException();
}
private int calculateOffset(ObservableList<? extends T> source) {
int cursor = 0;
for (ObservableList<T> ts : sources) {
if (ts == source) return cursor;
cursor += ts.size();
}
return cursor;
}
private void sourceChanged(ListChangeListener.Change<? extends T> c) {
ObservableList<? extends T> source = c.getList();
int offset = calculateOffset(source);
beginChange();
while (c.next()) {
if (c.wasPermutated()) {
int[] perm = new int[c.getTo() - c.getFrom()];
for (int i = c.getFrom(); i < c.getTo(); i++)
perm[i - c.getFrom()] = c.getPermutation(i) + offset;
nextPermutation(c.getFrom() + offset, c.getTo() + offset, perm);
} else if (c.wasUpdated()) {
for (int i = c.getFrom(); i < c.getTo(); i++) {
nextUpdate(i + offset);
}
} else {
if (c.wasRemoved()) {
// Removed should come first to properly handle replacements, then add.
nextRemove(c.getFrom() + offset, c.getRemoved());
}
if (c.wasAdded()) {
nextAdd(c.getFrom() + offset, c.getTo() + offset);
}
}
}
endChange();
}
@Override
public T get(int index) {
for (ObservableList<T> source : sources) {
if (index < source.size()) {
return source.get(index);
} else {
index -= source.size();
}
}
throw new IndexOutOfBoundsException();
}
@Override
public int size() {
return sources.stream().mapToInt(List::size).sum();
}
}