package org.core4j;

import java.util.Stack;

public class DepthFirstIterator<T> extends ReadOnlyIterator<T> {

  private final Func1<T, Enumerable<T>> childrenFn;
  private final Stack<T> stack = new Stack<T>();

  public DepthFirstIterator(T startingNode, Func1<T, Enumerable<T>> childrenFn) {
    this.childrenFn = childrenFn;
    this.stack.add(startingNode);
  }

  @Override
  protected IterationResult<T> advance() throws Exception {

    // first child
    for (T child : childrenFn.apply(stack.peek())) {
      stack.push(child);
      return IterationResult.next(child);
    }

    // no children
    while (stack.size() > 1) {
      T currentNode = stack.pop();

      // look for next sibling
      boolean foundSelf = false;
      for (T sibling : childrenFn.apply(stack.peek())) {
        if (foundSelf) {
          stack.push(sibling);
          return IterationResult.next(sibling);
        }
        if (sibling.equals(currentNode)) {
          foundSelf = true;
        }
      }
      // no sibling found, move up and try again

    }

    return IterationResult.done();
  }
}
