//<PLAINTEXT>
package Trees;

import java.util.*;

/**
 * BinaryTree.java
 *
 *
 * Created: Mon Mar 31 15:45:25 2003
 *
 * @author <a href="mailto:shapiro@cse.buffalo.edu">Stuart C. Shapiro</a>
 */

public class BinaryTree {
    private boolean empty;
    private BinaryTree left, right;
    private Object contents;

    /**
     * Creates a new empty <code>BinaryTree</code> instance.
     *
     */
    public BinaryTree (){
	empty = true;
	contents = null;
	left = null;
	right = null;
    }

    /**
     * Creates a new <code>BinaryTree</code> instance.
     *
     * @param value contents of this node of this tree.
     * @param lt the left sub-<code>BinaryTree</code> of this tree.
     * @param rt the right sub-<code>BinaryTree</code> of this tree.
     */
    public BinaryTree (Object value, BinaryTree lt, BinaryTree rt) {
	empty = false;
	contents = value;
	left = lt;
	right = rt;
    }
    
    /**
     * Determines if this binary tree is empty.
     *
     * @return <code>true</code> if this binary tree is empty;
     * otherwise, <code>false</code>.
     */
    public boolean isEmpty () {
	return empty;
    }

    /**
     * Constructs and returns a new <code>BinaryTree</code> leaf node.
     *
     * @param value the <code>Object</code> to be stored in this leaf.
     * @return a <code>BinaryTree</code> leaf node.
     */
    public static BinaryTree newLeaf(Object value) {
	BinaryTree tree = new BinaryTree();
	tree.setContents(value);
	return tree;
    }

    /**
     * Determines if this binary tree is a leaf node.
     *
     * @return true if this binary tree is non-empty and has an empty
     * left subtree and an empty right subtree.
     */
    public boolean isLeaf() {
	return !empty && left.isEmpty() && right.isEmpty();
    }

    /**
     * Makes this binary tree non-empty, by giving it empty subtrees.
     */
    private void makeNonEmpty() {
	empty = false;
	left = new BinaryTree();
	right = new BinaryTree();
    }

    /**
     * Makes this binary tree empty.
     */
    public void makeEmpty() {
	empty = true;
	contents = null;
	left = null;
	right = null;
    }

    /**
     * Get the value of contents.
     * @return value of contents.
     */
    public Object getContents() {
	return contents;
    }
	
    /**
     * Set the value of contents.
     * @param v  Value to assign to contents.
     */
    public void setContents(Object  v) {
	if (empty) makeNonEmpty();
	this.contents = v;
    }
	
    /**
     * Get the value of left.
     * @return value of left.
     * @exception NoSuchElementException if this tree has no left subtree.
     */
    public BinaryTree getLeft() {
	if (left == null) {throw new NoSuchElementException();}
	return left;
    }
	
    /**
     * Set the value of left.
     * @param v  Value to assign to left.
     */
    public void setLeft(BinaryTree  v) {
	if (empty) makeNonEmpty();
	this.left = v;
    }
	
    /**
     * Get the value of right.
     * @return value of right.
     * @exception NoSuchElementException if this tree has no right subtree.
     */
    public BinaryTree getRight() {
	if (right == null) {throw new NoSuchElementException();}
	return right;
    }
	
    /**
     * Set the value of right.
     * @param v  Value to assign to right.
     */
    public void setRight(BinaryTree  v) {
	if (empty) makeNonEmpty();
	this.right = v;
    }

    /**
     * Returns the height of this binary tree, considering the height
     * of a leaf to be 0.
     *
     * @return the height of this binary tree.
     */
    public int height() {
	if (empty) return -1;
	return 1 +  Math.max(left.height(), right.height());
    }

    /**
     * Returns the number of nodes in this binary tree.
     *
     * @return the size (number of nodes) in this binary tree.
     */
    public int size() {
	if (empty) return 0;
	return 1 + left.size() + right.size();
    }

    /**
     * Returns a <code>String</code> representation of this binary tree.
     *
     * @return a <code>String</code> representation of this binary tree.
     */
    public String toString() {
	if (empty) return "()";
	if (isLeaf()) return "(" + contents + ")";
	return "(" + contents
	    + " " + left.toString()
	    + " " + right.toString()
	    + ")";
    }

    /**
     * Tests the BinaryTree class.
     *
     * @param args a <code>String[]</code> value
     */
    public static void main (String[] args) {
	BinaryTree tree =
	    new BinaryTree("1",
			   new BinaryTree("2",
					  newLeaf("4"),
					  new BinaryTree("5",
							 newLeaf("7"),
							 new BinaryTree())
					  ),
			   new BinaryTree("3",
					  new BinaryTree(),
					  newLeaf("6")));
	System.out.println("tree = " + tree);
	System.out.println("Its height = " + tree.height());
	System.out.println("Its size = " + tree.size());
    } // end of main ()
    

}// BinaryTree
