//TreeNode.java

/**
 * Models a node in a binary tree.
 *
 * @author Zach Tomaszewski
 * @version Oct 19, 2006
 */
public class TreeNode<E> implements Comparable<TreeNode<E>>{

  private E data;
  private TreeNode<E> left;
  private TreeNode<E> right;


  /**
   * Creates a new leaf node.  It's left and right subtrees are both null.
   *
   * @param data  The data this new node will contain.
   */
  public TreeNode(E data) {
    this(data, null, null);
  }

  /**
   * Creates a new node.
   *
   * @param data   The data this node will contain.
   * @param left   This new node's left subtree.
   * @param right  This new node's right subtree.
   */
  public TreeNode(E data, TreeNode<E> left, TreeNode<E> right) {
    this.data = data;
    this.left = left;
    this.right = right;
  }


  /**
   * Compares the given node to this one, based on the data the two nodes
   * contain. If the data elements are Comparable, the two nodes are ordered
   * based on the results of comparing the two data elements.  Otherwise,
   * the result is 0.  Not consistent with <code>equals</code>.
   *
   * @param node   The node to compare to this one.
   * @return <code>this.data.compareTo(node.data)</code> if that data is
   *         <code>Comparable</code>; otherwise, 0.
   *
   * @see java.lang.Comparable#compareTo(java.lang.Object)
   */
  public int compareTo(TreeNode<E> node) {
    if (this.data instanceof Comparable) {
      /* Next line generates a warning, but it's (quite) safe due to the
       * instanceof check above.  I want nodes to be comparable,
       * regardless of the nature of their contents.
       */
      return ((Comparable<E>) this.data).compareTo(node.data);
    }else {
      return 0;
    }
  }


  /**
   * Returns the data object contained by this node.
   */
  public E getData() {
    return data;
  }

  /**
   * Returns the left subtree of this node.
   */
  public TreeNode<E> getLeft() {
    return left;
  }

  /**
   * Returns the right subtree of this node.
   */
  public TreeNode<E> getRight() {
    return right;
  }


  /**
   * Returns true if both of this node's subtrees are null.
   */
  public boolean isLeaf() {
    return (this.left == null && this.right == null);
  }

  /**
   * Sets this node's data field to contain the given data object.
   */
  public void setData(E data) {
    this.data = data;
  }

  /**
   * Sets this node's left pointer to point to the given tree/node.
   */
  public void setLeft(TreeNode<E> tree) {
    this.left = tree;
  }

  /**
   * Sets this node's right pointer to point to the given tree/node.
   */
  public void setRight(TreeNode<E> tree) {
    this.right = tree;
  }

  /**
   * Returns a string representation of this node.
   * Basically: "[data]", where data is the results of
   * the data's <code>toString()</code> method.
   */
  public String toString() {
    return "[" + this.data + "]";
  }

}//end class
