
package brs;

/**
 * Models the binary tree structure using the state pattern and the visitor
 * pattern. Provides only structural behaviors and a hook to execute any
 * visitor algorithm.
 * Exercise: Override the toString() method anonymous inner visitor classes.
 * @author Dung X. Nguyen - Copyright 2002 - All rights reserved.
 */
public class BiTree {
    /**
     * the state of this BiTree.
     */
    private ANode _rootNode;
    
    /**
     * Initializes this BiTree to the empty state.
     */
    public BiTree () {
        _rootNode = EmptyNode.Singleton;
    }
    
    /**
     * Gets the root data of this BiTree if it exists.
     * @return the root data element of this BiTree if it exists.
     * @exception NoSuchElementException if this BiTree is empty.
     */
    public Object getRootDat() {
        return _rootNode.getRootDat (this);
    }
    
    /**
     * Sets the root data element to a given object.
     * @param dat the new root data.
     * @exception NoSuchElementException if this BiTree is empty.
     */
    public void setRootDat(Object dat) {
        _rootNode.setRootDat (dat, this);
    }
    
    /**
     * Gets the left subtree of this BiTree if it exists.
     * @return the left subtree of this BiTree if it exists.
     * @exception NoSuchElementException if this BiTree is empty.
     */
    public BiTree getLeftSubTree() {
        return _rootNode.getLeftSubTree (this);
    }
    
    /**
     * Gets the right subtree of this BiTree if it exsists.
     * @return the right subtree of this BiTree if it exists.
     * @exception NoSuchElementException if this BiTree is empty.
     */
    public BiTree getRightSubTree() {
        return _rootNode.getRightSubTree (this);
    }
    
    /**
     * Attaches a new left subtree to the left of this BiTree, allowing this
     * BiTree to grow to the left.
     * @param biTree to replace the current left subtree.
     * @exception NoSuchElementException if this BiTree is empty.
     */
    public void setLeftSubTree(BiTree biTree) {
        _rootNode.setLeftSubTree(biTree, this);
    }
    
    /**
     * Attaches a new right subtree to the left of this BiTree, allowing this
     * BiTree to grow to the right.
     * @param biTree to replace the current right subtree.
     * @exception NoSuchElementException if this BiTree is empty.
     */
    public void setRightSubTree(BiTree biTree) {
        _rootNode.setRightSubTree(biTree, this);
    }
    
    /**
     * Inserts a root element to this BiTree.
     * Allows for state change from empty to non-empty.
     * @param dat the new root data.
     * @exception IllegalStateException if this BiTree has more than one element.
     */
    public void insertRoot(Object dat) {
        _rootNode.insertRoot(dat, this);
    }
    
    /**
     * Removes and returns the root data element of this BiTree.
     * @return the root data element of this BiTree.
     * @exception NoSuchElementException if this BiTree is empty.
     * @exception IllegalStateException if one of the subtrees is not empty.
     */
    public Object remRoot() {
        return _rootNode.remRoot(this);
    }
    
    /**
     * Hook to execute any algorithm that presents itself as a visitor to this
     * BiTree.
     * @param algo a visitor to a BiTree.
     * @param inp the input for the algo visitor.
     * @return the output for the execution of algo.
     */
    public Object execute(IVisitor algo, Object... inp) {
        return _rootNode.execute(this, algo, inp);
    }
    
    public String toString () {
        return (String)execute (ToString.Singleton);
        // EXERCISE FOR STUDENTS: The above line of code does not conform to the
        // state pattern because it does not forward the request to the state.
        // Rewrite the code to conform to the state pattern.  You will need to add
        // appropriate methods to the states.  Review what we did with toString()
        // for linear recursive structures.
    }
    
    /**
     * Changes this BiTree to a given new node (i.e. state).
     * @param node a new root node (i.e.state) for this BiTree.
     */
    final void setRootNode(ANode node) {
        _rootNode = node;
    }
    
    /**
     * Returns the current node (i.e. state) of this BiTree.
     * @return the current root node (state) of this BiTree.
     */
    final ANode getRootNode() {
        return _rootNode;
    }
}

