package org.phoenicis.javafx.views.common;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.collections.transformation.TransformationList;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* Created by marc on 01.04.17.
*/
public class MappedList<E, F> extends TransformationList<E, F> {
private final Function<? super F, ? extends E> mapper;
private List<E> mappedValues;
public MappedList(ObservableList<? extends F> source, Function<? super F, ? extends E> mapper) {
super(source);
this.mappedValues = source.stream().map(mapper).collect(Collectors.toList());
this.mapper = mapper;
}
@Override
public int getSourceIndex(int index) {
if (index >= size()) {
throw new IndexOutOfBoundsException();
}
return index;
}
@Override
public E get(int index) {
if (index >= size()) {
throw new IndexOutOfBoundsException();
}
return mappedValues.get(index);
}
@Override
public int size() {
return mappedValues.size();
}
private void permutate(Change<? extends F> c) {
int from = c.getFrom();
int to = c.getTo();
if (to > from) {
List<E> clone = new ArrayList<E>(mappedValues);
int[] perm = IntStream.range(0, size()).toArray();
for (int i = from; i < to; ++i) {
perm[i] = c.getPermutation(i);
mappedValues.set(i, clone.get(c.getPermutation(i)));
}
nextPermutation(from, to, perm);
}
}
private void update(Change<? extends F> c) {
int from = c.getFrom();
int to = c.getTo();
if (to > from) {
for (int i = from; i < to; ++i) {
mappedValues.set(i, mapper.apply(getSource().get(i)));
nextUpdate(i);
}
}
}
private void addRemove(Change<? extends F> c) {
int from = c.getFrom();
int to = c.getTo();
for (int index = from + c.getRemovedSize() - 1; index >= from; index--) {
nextRemove(index, mappedValues.remove(index));
}
for (int index = from; index < from + c.getAddedSize(); index++) {
mappedValues.add(index, mapper.apply(getSource().get(index)));
nextAdd(index, index + 1);
}
}
@Override
protected void sourceChanged(Change<? extends F> c) {
beginChange();
while (c.next()) {
if (c.wasPermutated()) {
permutate(c);
} else if (c.wasUpdated()) {
update(c);
} else {
addRemove(c);
}
}
endChange();
}
}