#include "bst.h"

bst::bst(): root(NULL){}

bst::~bst() {
    while(root) {
        remove(root->data);
    }
}

NodeInterface* bst::getRootNode() {
    return root;
}

bool bst::add(int data) {
    if(root == NULL) {
        root = new node(data);
        return true;
    }
    else {
        node* current;
        node* parent;
        current = root;
        while(current) {
            parent = current;
            if(data == current->data) {
                return false;
            }
            if(data > current->data) {
                current = current->right;
            }
            else {
                current = current->left;
            }
        }
        if(data < parent->data) {
            parent->left = new node(data);
            return true;
        }
        else {
            parent->right = new node(data);
            return true;;
        }
    }
    return true;
}

bool bst::remove(int data) {
    bool found = false;
    if(root == NULL) {
        return false;
    }
    node* current;
    node* parent;
    current = root;
    while(current) {
        if(current->data == data) {
            found = true;
            break;
        }
        else {
            parent = current;
            if(data > current->data) {
                current = current->right;
            }
            else if(data < current->data) {
                current = current->left;
            }
        }
    }
    if(!found) {
        return false;
    }
    if(root->data == data) { 
        if(root->right != NULL && root->left == NULL) {
            node* temp;
            temp = root;
            root = root->right;
            delete temp;
            return true;
        }
        if(root->right == NULL && root->left != NULL) {
            node* temp;
            temp = root;
            root = root->left;
            delete temp;
            return true;
        }
        if(root->right != NULL && root->left != NULL) {
            node* temp;
            temp = root;
            root = root->left;
            root->right = temp->right;
            delete temp;
            return true;
        }
        else {
            delete root;
            root = NULL;
            return true;
        }
    }
    if((current->left == NULL) && (current->right == NULL)) {
        if(parent->left == current) {
            parent->left = NULL;
        }
        else {
            parent->right = NULL;
        }
        delete current;
        return true;
    }
    if((current->left == NULL && current->right != NULL) || (current->left != NULL && current->right == NULL)) {
        if(current->left == NULL && current->right != NULL) {
            if(parent->left == current) {
                parent->left = current->right;
                delete current;
            }
            else {
                parent->right = current->right;
                delete current;
            }
        }
        else {
            if(parent->left == current) {
                parent->left = current->left;
                delete current;
            }
            else {
                parent->right = current->left;
                delete current;
            }
        }
        return true;
    }
    if(current->left != NULL && current->right != NULL) {
        node* greatest_right;
        greatest_right = current->right;
        if((greatest_right->left == NULL) && (greatest_right->right == NULL)) {
            current = greatest_right;
            delete greatest_right;
            current->right = NULL;
        }
        else {
            if(current->right->left != NULL) {
                node* left;
                node* temp_left;
                temp_left = current->right;
                left = current->right->left;
                while(left->left != NULL) {
                    temp_left = left;
                    left = left->left;
                }
                current->data = left->data;
                delete left;
                temp_left->left = NULL;
            }
            else {
                node* temp;
                temp = current->right;
                current->data = temp->data;
                current->right = temp->right;
                delete temp;
            }
        }
        return true;
    }
    return true;
}
