//  File: bstree.C
//
//  A binary search tree class

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "bstree.h"


// ========================================================
// BSTree member functions


// Constructor
//
BSTree::BSTree() {
   root = NULL ;
}

// Destructor (Beware!)
//
BSTree::~BSTree() {
   delete root ;
}


// Inorder Traversal of a BSTree
//
void BSTree::Inorder() {

   if (root == NULL) return ;

   printf ("(") ;
   root->left.Inorder() ;
   printf(" ") ;
   root->Print() ;
   printf(" ") ;
   root->right.Inorder() ;
   printf (")") ;
}



// Insert functions (overloaded)


void BSTree::Insert(int x) {
   Insert(x,'a') ;  // default data is char 'a'
}


void BSTree::Insert(int x, data c) {
   if (root == NULL) {
      root = new BSTreeNode(x, c) ;
      return ;
   }

   if (x <= root->key) {
      root->left.Insert(x, c) ;
   } else {
      root->right.Insert(x, c) ;
   }
}


// returns pointer to BSTree where the root has key value == x.
// returns NULL, if no such node.
//
BSTree *BSTree::Search(int x) {
   if (root == NULL) return NULL ;

   if (x == root->key) {
      return this ;
   } else if (x < root->key) {
      return root->left.Search(x) ;
   } else {
      return root->right.Search(x) ;
   }
}


// Removes the root node of host subtree.  Can be used in conjunction
// with Search.
//
void BSTree::RemoveRoot() {
   BSTreeNode *temp ;

   if (root == NULL) return ;

   // Otherwise, we have found x
   temp = ExtractRoot() ;

   // temp should be cleaned up
   assert(temp->left.root == NULL) ;
   assert(temp->right.root == NULL) ;

   delete temp ;
}


// returns pointer to BSTree where the root has min key value.
// returns NULL if BSTree is empty.
//
BSTree *BSTree::Min() {
   if (root == NULL) return NULL ;

   if (root->left.root == NULL) { // found min
      return this ;
   } else {
      return root->left.Min() ;
   }
}


// returns pointer to BSTree where the root has max key value.
// returns NULL if BSTree is empty.
//
BSTree *BSTree::Max() {
   if (root == NULL) return NULL ;

   if (root->right.root == NULL) { // found max
      return this ;
   } else {
      return root->right.Max() ;
   }
}


// Returns 1 if tree is empty, returns 1 otherwise
//
int BSTree::IsEmpty() {

   return root == NULL ? 1 : 0 ;
}


// Returns key stored at the root of the tree.
// Crashes if called on empty tree.
//
int BSTree::RootKey() {

   if (root == NULL) {
      fprintf(stderr, "RootKey called on empty tree\n") ;
      exit(1) ;
   }

   return root->key ;
}


// Returns pointer to data stored at the root of the tree.
// Crashes if called on empty tree.
//
data *BSTree::RootDataPtr() {

   if (root == NULL) {
      fprintf(stderr, "RootData called on empty tree\n") ;
      exit(1) ;
   }

   return &(root->stuff) ;
}


// Prints out value in the root of the tree.
// Does nothing if called on empty tree.
//
void BSTree::RootPrint() {

   if (root == NULL) return ;
   root->Print() ;
}


// Protected member functions


// Removes BSTreeNode with smallest key and returns a pointer
// to the node. Returned pointer must be freed after use.
//
BSTreeNode *BSTree::ExtractMin() {
   BSTreeNode *answer ;

   if (root == NULL) return NULL ;

   if (root->left.root == NULL) { // found min
      answer = root ;
      root = root->right.root ;
      answer->right.root = NULL ;
      return answer ;
   } else {
      return root->left.ExtractMin() ;
   }
}


// Removes BSTreeNode at the root and returns a pointer to.
// the root.  Returned pointer must be freed after use.
//
BSTreeNode *BSTree::ExtractRoot() {
   BSTreeNode *answer, *temp ;

   answer = root ;

   // Easy Case 1: tree is a single node
   if (root->left.root == NULL && root->right.root == NULL) {
      root = NULL ;
      return answer ;
   }

   // Easy Case 2: tree has no left child
   if (root->left.root == NULL) {
      root = root->right.root ;
      answer->right.root = NULL ; // fix up answer
      return answer ;
   }

   // Easy Case 3: tree has no right child
   if (root->right.root == NULL) {
      root = root->left.root ;
      answer->left.root = NULL ; // fix up answer
      return answer ;
   }

   // Hard Case: tree has both left and right childern
   temp = root->right.ExtractMin() ;

   // make temp new root
   temp->left = root->left ;
   temp->right = root->right ;
   root = temp ;

   // fix up answer
   answer->left.root = NULL ;
   answer->right.root = NULL ;
   return answer ;
}


// ========================================================
// BSTreeNode member functions

// Constructors

BSTreeNode::BSTreeNode() {
   key = 0 ;
   stuff = 'a' ;

   // Note: left.root and right.root already set to NULL by
   // BSTree default constructor
}


BSTreeNode::BSTreeNode(int x) {
   key = x ;
   stuff = 'a' ;

   // Note: left.root and right.root already set to NULL by
   // BSTree default constructor
}


BSTreeNode::BSTreeNode(int x, data c) {
   key = x ;
   stuff = c ;

   // Note: left.root and right.root already set to NULL by
   // BSTree default constructor
}


void BSTreeNode::Print() {
   printf("[%d,%c]", key, stuff) ;
}


// Protected member functions

// Destructor

BSTreeNode::~BSTreeNode() {
   // Actually, we don't have to do anything
   printf("BSTreeNode Destructor: key=%d, stuff=%c\n", key, stuff) ;
}
