import java.util.*;

class AVLTree {
	 private final static int PRINT_LEVELS = 4;
	 private TreeNode root;
	 
	 /*
	  * constructor
	  */
	 public AVLTree() {
		  root = null;
	 }

	 /*
	  * public search
	  */
	 public Object search(Comparable key) {
		  return search(key, root);
	 }

	 /*
	  * public insert
	  */
	 public void insert(Comparable key) {
		  if(root == null) {
				root = new TreeNode(key);
				return;
		  }

		  // insert the node in the tree
		  insert(key, root, null);
	 }

	 /*
	  * public delete
	  */
	 public Object delete(Comparable key) {
		  TreeNode data = new TreeNode(null);
		  delete(key, root, null, data);
		  return data.key;
	 }

	 /*
	  * private search
	  */
	 private Object search(Comparable key, TreeNode subRoot) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }

	 /*
	  * private insert
	  */
	 private boolean insert(Comparable key, TreeNode subRoot, TreeNode prev) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }

	 /*
	  * private delete
	  *
	  * The arguments to this method are a bit of a kludge because
	  * Java doesn't support pointers - at least not in any good way. :{
	  * So if on return from this method the key value in TreeNode data is
	  * set to null, then the key wasn't found. Otherwise, the node was
	  * found and it's key value is set to the appropriate value.
	  */
	 private boolean delete(Comparable key, TreeNode subRoot,
									TreeNode prev, TreeNode data) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }
				
	 /*
	  * balanceTree
	  */
	 private void balanceTree(TreeNode subRoot, TreeNode prev) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }

	 /*
	  * rotateLeft
	  */
	 private void rotateLeft(TreeNode subRoot, TreeNode prev) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }

	 /*
	  * rotateRight
	  */
	 private void rotateRight(TreeNode subRoot, TreeNode prev) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }

	 /*
	  * rotateRightLeft
	  */
	 private void rotateRightLeft(TreeNode subRoot, TreeNode prev) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }

	 /*
	  * rotateLeftRight
	  */
	 private void rotateLeftRight(TreeNode subRoot, TreeNode prev) {
		  /*
			* INSERT YOUR CODE HERE.
			*/
	 }

	 /*
	  * printTree
	  */
	 public void printTree() {
		  if(root == null) {
				System.out.println("Tree is empty");
				return;
		  }
		  
		  LinkedList queue = new LinkedList();
		  Vector nodes = new Vector();
		  int level = 0;

		  // enqueue the root
		  queue.add(root);

		  // now print out each level - if a node is null, just enqueue null
		  while(level < PRINT_LEVELS) {
				for(int i=0; i<(int)Math.pow(2, level); i++) {
					 TreeNode tmp = (TreeNode)queue.removeFirst();
					 nodes.add(tmp);
					 if(tmp != null) {
						  queue.add(tmp.left);
						  queue.add(tmp.right);
					 }
					 else {
						  queue.add(null);
						  queue.add(null);
					 }
				}
				printLevel(nodes, level);
				nodes.clear();
				level++;
		  }
	 }

	 /*
	  * printLevel
	  */
	 private void printLevel(Vector nodes, int level) {
		  // tab over for the first node in the level
		  //for(int i=0; i<28-(level*(15-(2*level))); i++)
		  for(int i=0; i<30-(15*level - 2*Math.pow(level, 2)); i++)
				System.out.print(" ");

		  // printing out the node - no sibling
		  if(nodes.size() == 1) {
				TreeNode tmp = (TreeNode)nodes.get(0);
				System.out.print(tmp.key + "(" + tmp.balFactor + ")");
		  }

		  // every other node has or could have a sibling
		  else {
				for(int i=0; i<nodes.size(); i+=2) {
					 TreeNode tmp = (TreeNode)nodes.get(i);

					 // print out the first node if it exists
					 if(tmp != null)
						  System.out.print(tmp.key + "(" + tmp.balFactor + ")");
					 else
						  System.out.print("\t");

					 // tab over to it's sibling
					 for(int j=0; j<(-8*level+28); j++)
						  System.out.print(" ");

					 // now print out the sibling if it exists
					 tmp = (TreeNode)nodes.get(i+1);
					 if(tmp != null)
						  System.out.print(tmp.key + "(" + tmp.balFactor + ")");
					 else
						  System.out.print("\t");

					 // tab over to it's cousin
					 for(int j=0; j<(PRINT_LEVELS-level); j++)
						  System.out.print("   ");
				}
		  }

		  // done with this level
		  System.out.print("\n\n");
	 }

	 /*
	  * minValue
	  */
	 private int minValue(int x, int y) {
		  return (x < y) ? x : y;
	 }
	 
	 /*
	  * maxValue
	  */
	 private int maxValue(int x, int y) {
		  return (x > y) ? x : y;
	 }
}
