// Level-order iterator for binary trees.
// (c) 1998, 2001 duane a. bailey

/**
 * An iterator for traversing binary trees constructed from
 * BinaryTrees.  The iterator performs minimal work before
 * traversal.  Every node is considered after every non-trivial
 * ancestor or left cousin, and before any non-trivial descendant or
 * right cousin.
 * LevelOrderIterator finishes when
 * all descendants of the start node have been considered.
 * @author, 2001 duane a. bailey
 */

public class BTLevelorderIterator<E> 
{
    /**
     * The root of the subtree being traversed.
     */
    protected BinaryTreeNode<E> root; // root of traversed subtree
    /** 
     * Queue of nodes that maintain the state of the iterator.
     */
    protected Queue<BinaryTreeNode<E>> todo;  // queue of unvisited relatives

    /**
     * Construct a new level-order iterator of a tree.
     *
     * @post Constructs an iterator to traverse in level order
     * @param root The root of the subtree to be traversed.
     */
    public BTLevelorderIterator(BinaryTreeNode<E> root)
    {
        todo = new LinkedList<BinaryTreeNode<E>>();
        this.root = root;
        reset();
    }   

    /**
     * Reset iterator to beginning of traversal.
     *
     * @post Resets the iterator to root node
     */
    public void reset()
    {
        todo.clear();
        // empty queue, add root
        if (!root.isEmpty()){
            todo.add(root);
        } 
    }

    /**
     * Return true if more nodes are to be considered.
     *
     * @post Returns true iff iterator is not finished
     * 
     * @return True if more nodes are to be considered.
     */
    public boolean hasNext()
    {
        return !todo.isEmpty();
    }

    /**
     * Returns currently considered value and increments iterator.
     *
     * @pre hasNext();
     * @post Returns current value, increments iterator
     * 
     * @return Value considered before iterator is incremented.
     */
    public E next() {
        BinaryTreeNode<E> current = todo.dequeue();
        E result = current.value();
        if (!current.left().isEmpty()){
            todo.enqueue(current.left());
        }
        if (!current.right().isEmpty()) {
            todo.enqueue(current.right());
        }
        return result;
    }
}

