//<PLAINTEXT>
package Trees;

import java.util.*;

/**
 * IteratedBinaryTree.java
 *
 *
 * Created: Fri Apr 18 14:26:39 2003
 *
 * @author <a href="mailto:shapiro@cse.buffalo.edu">Stuart C. Shapiro</a>
 * @version
 */

public class IteratedBinaryTree extends BinaryTree {
    public IteratedBinaryTree (){
	super();
    }

    public IteratedBinaryTree (Object value, BinaryTree lt, BinaryTree rt) {
	super(value, lt, rt);
    }

    public static BinaryTree newLeaf(Object value) {
	IteratedBinaryTree tree = new IteratedBinaryTree();
	tree.setContents(value);
	return tree;
    }

    public BTPreIterator preIterator() {
	return new BTPreIterator(this);
    }

    public BTInIterator inIterator() {
	return new BTInIterator(this);
    }

    private class BTPreIterator implements Iterator {

	/**
	 * Every node in the todo stack must still be visited, and its
	 * left and right subtrees must be traversed.
	 *
	 */
	private Stack todo;

	public BTPreIterator (IteratedBinaryTree root) {
	    todo = new Stack();
	    if (!root.isEmpty()) {
		todo.push(root);
	    }
	    
	}

	public boolean hasNext() {
	    return !todo.isEmpty();
	}

	public Object next() {
	    return ((IteratedBinaryTree)nextNode()).getContents();
	}

	public Object nextNode() {
	    if (!hasNext()) {throw new NoSuchElementException();}
	    IteratedBinaryTree next = (IteratedBinaryTree)todo.pop();
	    if (!next.getRight().isEmpty()) {
		todo.push(next.getRight());
	    }
	    if (!next.getLeft().isEmpty()) {
		todo.push(next.getLeft());
	    }
	    return next;
	}

    public IteratedBinaryTree nextLeaf() {
	IteratedBinaryTree node;
	while (hasNext()) {
	    node = (IteratedBinaryTree)nextNode();
	    if (((IteratedBinaryTree)node).isLeaf()) {return node;}
	} // end of while (hasNext())
	return null;
    }

	public void remove() {
	    throw new UnsupportedOperationException();
	}

    } // BTPreIterator

    private class BTInIterator implements Iterator {

	/**
	 * Every node in the todo stack must still be visited, and its
	 * right subtree must be traversed, but its left subtree has
	 * already been traversed.
	 *
	 */
	private Stack todo;

	public BTInIterator (IteratedBinaryTree root) {
	    todo = new Stack();
	    if (!root.isEmpty()) {
		todo.push(root);
		pushLeftBranch();
	    }
	}

	private void pushLeftBranch() {
	    while (!((IteratedBinaryTree)todo.peek()).getLeft().isEmpty()) {
		todo.push(((IteratedBinaryTree)todo.peek()).getLeft());
	    }
	}

	public boolean hasNext() {
	    return !todo.isEmpty();
	}

	public Object next() {
	    return ((IteratedBinaryTree)nextNode()).getContents();
	}


	public Object nextNode() {
	    if (!hasNext()) {throw new NoSuchElementException();}
	    IteratedBinaryTree next = (IteratedBinaryTree)todo.pop();
	    if (!next.getRight().isEmpty()) {
		todo.push(next.getRight());
		pushLeftBranch();
	    }
	    return next;
	}

    public IteratedBinaryTree nextLeaf() {
	IteratedBinaryTree node;
	while (hasNext()) {
	    node = (IteratedBinaryTree)nextNode();
	    if (((IteratedBinaryTree)node).isLeaf()) {
		return node;
	    }
	} // end of while (hasNext())
	return null;
    }

	public void remove() {
	    throw new UnsupportedOperationException();
	}

    } // BTInIterator
    
    public static void printLeaves (IteratedBinaryTree tree) {
	IteratedBinaryTree node;
	BTPreIterator it = tree.preIterator();
	node = it.nextLeaf();
	while (node != null) {
	    System.out.println(node.getContents());
	    node = it.nextLeaf();
	}
    }

    public static boolean equalFringe(IteratedBinaryTree t1,
				      IteratedBinaryTree t2) {
	IteratedBinaryTree node1, node2;
	BTPreIterator it1 = t1.preIterator();
	BTPreIterator it2 = t2.preIterator();
	node1 = it1.nextLeaf();
	node2 = it2.nextLeaf();
	while (node1 != null && node2 != null) {
	    if (!node1.getContents().equals(node2.getContents())) {
		return false;
	    }
	    node1 = it1.nextLeaf();
	    node2 = it2.nextLeaf();
	}
	return node1 == node2;
    }

	/**
	 * Tests the InteratedBinaryTree class.
	 *
	 * @param args a <code>String[]</code> value
	 */
	public static void main (String[] args) {
	    IteratedBinaryTree tree =
		new IteratedBinaryTree("1",
				       new IteratedBinaryTree("2",
							      newLeaf("4"),
							      new IteratedBinaryTree("5",
										     newLeaf("7"),
										     new IteratedBinaryTree())
							      ),
				       new IteratedBinaryTree("3",
							      new IteratedBinaryTree(),
							      newLeaf("6")));
	    System.out.println("tree = " + tree);
	    System.out.println("Its height = " + tree.height());
	    System.out.println("Its size = " + tree.size());
	
	    BTPreIterator preIt = tree.preIterator();
	    System.out.println("Preorder Traversal:");
	    while (preIt.hasNext()) {
		System.out.print(preIt.next() + " ");
	    } // end of while (preIt.hasNext())
	    System.out.println();

	    BTInIterator inIt = tree.inIterator();
	    System.out.println("Inorder Traversal:");
	    while (inIt.hasNext()) {
		System.out.print(inIt.next() + " ");
	    } // end of while (inIt.hasNext())
	    System.out.println();
	
	    IteratedBinaryTree tree2 =
		new IteratedBinaryTree("1",
				       new IteratedBinaryTree("2",
							      newLeaf("4"),
							      new IteratedBinaryTree()),
				       new IteratedBinaryTree("3",
							      newLeaf("7"),
							      newLeaf("6")));

	    System.out.println("tree2 = " + tree2);
	    System.out.println("Leaves of tree:");
	    printLeaves(tree);
	    System.out.println("Leaves of tree2:");
	    printLeaves(tree2);
	    System.out.println("equalFringe(tree, tree2) = "
			       + equalFringe(tree, tree2));
	} // end of main ()

    }// IteratedBinaryTree
