/* binarysearchtree.cpp: method implementations for binary search tree */

#include "binarysearchtree.h"

/**
* Implements an unbalanced binary search tree.
* Note that all "matching" is based on the < method.
*/

/**
* Construct the tree.
*/
BinarySearchTree::BinarySearchTree( const string & notFound )
    : ITEM_NOT_FOUND( notFound ), root( NULL ) {
    RightLinksFollowed = 0;
    LeftLinksFollowed = 0;
    num_nodes = 0;
}


/**
* Copy constructor.
*/
BinarySearchTree::BinarySearchTree( const BinarySearchTree & rhs )
    : ITEM_NOT_FOUND( rhs.ITEM_NOT_FOUND ), root( NULL ) {
    *this = rhs;
}

/**
* Destructor for the tree.
*/
BinarySearchTree::~BinarySearchTree( ) {
    makeEmpty( );
}

/**
* Insert x into the tree; duplicates are ignored.
*/

void BinarySearchTree::insert( const string & x ) {
    insert( x, root );
}

/**
* Remove x from the tree. Nothing is done if x is not found.
*/
void BinarySearchTree::remove( const string & x ) {
    remove( x, root );
}

/**
* Returns the number of left links followed so far in the tree.
*/
int BinarySearchTree::GetLeftLinksFollowed( ) const {
    return LeftLinksFollowed;
}

/**
* Returns the number of right links followed so far in the tree.
*/

int BinarySearchTree::GetRightLinksFollowed( ) const {
    return RightLinksFollowed;
}

/**
* Returns the cardinality (number of nodes) in the tree.
*/

int BinarySearchTree::card_of( ) const {
    return num_nodes;
}


double BinarySearchTree::exp_path_length( )
/*
**  Calculate the expected path length of the tree
**  This is the public version, without a parameter.
**  NOTE that it recursively invokes int_path_length()
*/
{
    // YOUR CODE HERE
    return -99.0;  // stub, remove after writing your code
}

int BinarySearchTree::int_path_length(BinaryNode *t, int depth) {
    // Your code here
    return -99; // remove after writing your code
}

/**
* Find the smallest item in the tree.
* Return smallest item or ITEM_NOT_FOUND if empty.
*/

const string & BinarySearchTree::findMin( ) const {
    return elementAt( findMin( root ) );
}

/**
* Find the largest item in the tree.
* Return the largest item of ITEM_NOT_FOUND if empty.
*/

const string & BinarySearchTree::findMax( ) const {
    return elementAt( findMax( root ) );
}

/**
* Find item x in the tree.
* Return the matching item or ITEM_NOT_FOUND if not found.
*/
const string & BinarySearchTree::find( const string & x ) const {
    return elementAt( find( x, root ) );
}

/**
* Make the tree logically empty.
*/

void BinarySearchTree::makeEmpty( ) {
    // call the private makeEmpty() routine
    makeEmpty( root );
}

/**
* Test if the tree is logically empty.
* Return true if empty, false otherwise.
*/

bool BinarySearchTree::isEmpty( ) const {
    return root == NULL;
}

/**
* Print the tree contents in sorted order.
*/

void BinarySearchTree::printTree( ) const {
    if ( isEmpty( ) )
        cout << "Empty tree" << endl;
    else
        printTree( root );
}

/**
* Deep copy.
*/

const BinarySearchTree & BinarySearchTree::operator=( const BinarySearchTree & rhs ) {
    if ( this != &rhs ) {
        makeEmpty( );
        root = clone( rhs.root );
    }
    return *this;
}

/**
* Internal method to get element field in node t.
* Return the element field or ITEM_NOT_FOUND if t is NULL.
*/
const string & BinarySearchTree::elementAt( BinaryNode *t ) const {
    return t == NULL ? ITEM_NOT_FOUND : t->element;
}

/**
* Internal method to insert into a subtree.
* x is the item to insert.
* t is the node that roots the tree.
* Set the new root.
*/
void BinarySearchTree::insert( const string & x, BinaryNode * & t ) const {
    if ( t == NULL ) {
        t = new BinaryNode( x, NULL, NULL );
    } else if ( x < t->element ) {
        insert( x, t->left );
    } else if ( t->element < x ) {
        insert( x, t->right );
    } else
        ;
}

/**
* Internal method to remove from a subtree.
* x is the item to remove.
* t is the node that roots the tree.
* Set the new root.
*/
void BinarySearchTree::remove( const string & x, BinaryNode * & t ) const {
    if ( t == NULL )
        return;   // Item not found; do nothing
    if ( x < t->element )
        remove( x, t->left );
    else if ( t->element < x )
        remove( x, t->right );
    else if ( t->left != NULL && t->right != NULL ) { // Two children
        t->element = findMin( t->right )->element;
        remove( t->element, t->right );
    } else {
        BinaryNode *oldNode = t;
        t = ( t->left != NULL ) ? t->left : t->right;
        delete oldNode;
    }
}

/**
* Internal method to find the smallest item in a subtree t.
* Return node containing the smallest item.
*/

BinaryNode * BinarySearchTree::findMin( BinaryNode *t ) const {
    if ( t == NULL )
        return NULL;
    if ( t->left == NULL )
        return t;
    return findMin( t->left );
}

/**
* Internal method to find the largest item in a subtree t.
* Return node containing the largest item.
*/

BinaryNode * BinarySearchTree::findMax( BinaryNode *t ) const {
    if ( t != NULL )
        while ( t->right != NULL )
            t = t->right;
    return t;
}

/**
* Internal method to find an item in a subtree.
* x is item to search for.
* t is the node that roots the tree.
* Return node containing the matched item.
*/
BinaryNode * BinarySearchTree::find( const string & x, BinaryNode *t ) const {
    if ( t == NULL )
        return NULL;
    else if ( x < t->element ) {
        return find( x, t->left );
    } else if ( t->element < x ) {
        return find( x, t->right );
    } else
        return t;    // Match
}
/****** NONRECURSIVE VERSION*************************

BinaryNode *
BinarySearchTree::find( const string & x, BinaryNode *t ) const
{
while( t != NULL )
if( x < t->element )
t = t->left;
else if( t->element < x )
t = t->right;
else
return t;    // Match

return NULL;   // No match
}
*****************************************************/

/**
* Internal method to make subtree empty.
*/

void BinarySearchTree::makeEmpty( BinaryNode * & t ) const {
    if ( t != NULL ) {
        makeEmpty( t->left );
        makeEmpty( t->right );
        delete t;
    }
    t = NULL;
}

/**
* Internal method to print a subtree rooted at t in sorted order.
*/

void BinarySearchTree::printTree( BinaryNode *t ) const {
    if ( t != NULL ) {
        printTree( t->left );
        cout << t->element << endl;
        printTree( t->right );
    }
}

/**
* Internal method to clone subtree.
*/
BinaryNode * BinarySearchTree::clone( BinaryNode * t ) const {
    if ( t == NULL )
        return NULL;
    else
        return new BinaryNode( t->element, clone( t->left ), clone( t->right ) );
}