package er.neo4jadaptor.utils.iteration;
import java.util.Iterator;
/**
* Having tree of the fixed depth, where each node is an iterator and this iterator values are child nodes, this class provides
* uniform way to iterate over such tree's leaves.
*
* @author jsobanski
*
* @param <N> node type
* @param <L> leaf type
*/
public class MultiLevelIterator <N, L> implements Iterator<L> {
private final Iterator<?> [] iterators;
protected int idx = 0;
public MultiLevelIterator(Iterator<N> rootIterator, int depth) {
this.iterators = new Iterator[depth];
iterators[0] = rootIterator;
}
private int depth() {
return iterators.length;
}
@SuppressWarnings("unchecked")
public boolean hasNext() {
while (lastIterator() == null || ! lastIterator().hasNext()) {
if (idx == 0 && ! iterators[idx].hasNext()) {
return false;
}
// proceed backwards when necessary
while (idx > 0 && ! iterators[idx].hasNext()) {
iterators[idx] = null;
idx--;
}
// proceed forward when possible
while (idx != depth()-1 && iterators[idx].hasNext()) {
int nextLevel = idx+1;
N node = (N) iterators[idx].next();
iterators[nextLevel] = createThisLevelIterator(node, nextLevel);
idx = nextLevel;
}
}
return lastIterator() != null && lastIterator().hasNext();
}
/**
* Creates the next level iterator for the current iterator value being <code>currVal</code>.
*
* @param currVal
* @param resultLevelIndex
* @return current level iterator
*/
protected Iterator<?> createThisLevelIterator(N currVal, int resultLevelIndex) {
return ((Iterable<?>) currVal).iterator();
}
@SuppressWarnings("unchecked")
private Iterator<L> lastIterator() {
return (Iterator<L>) iterators[iterators.length-1];
}
public L next() {
return lastIterator().next();
}
public void remove() {
lastIterator().remove();
}
}