#include "br_tree.h"

br_tree::br_tree():root(NULL), h(false){}

vector<string> parse_expression(string expression) { //parses expression with " " being the delimeter
    vector<string> results;
    string s;
    for(unsigned int i = 0; i < expression.length(); i++) {
        char c = expression[i];
        if(c != ' ') {
            s += c;
        }
        else {
            if(s != "") {
                results.push_back(s);
                s.clear();
            }
        }
    }
    if(s != "") {
        results.push_back(s);
    }
    return results;
}

bool br_tree::in_tree(string data) {
    bool found = false;
    br_node* current;
    br_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;
            }
        }
    }
    return found;
}

RedBlackNodeInterface* br_tree::getRootNode() {
    return root;
}

void br_tree::add(string word) {
    if(in_tree(word)) {
        return;
    }
    if(root == NULL) {
        root = new br_node(word);
        root->color = 1;
        return;
    }
    br_node* current;
    br_node* cur_parent;
    current = root;
    while(current) {
        cur_parent = current;
        if(word > current->data) {
            current = current->right;
        }
        else {
            current = current->left;
        }
    }
    if(word < cur_parent->data) {
        cur_parent->left = new br_node(word);
        cur_parent->left->parent = cur_parent;
        br_node* child_added = cur_parent->left;
        if(cur_parent->color == 0 && child_added->color == 0) {
            balance(cur_parent->left);
        }
        return;
    }
    else {
        cur_parent->right = new br_node(word);
        cur_parent->right->parent = cur_parent;
        br_node* child_added = cur_parent->right;
        if(cur_parent->color == 0 && child_added->color == 0) {
            balance(cur_parent->right);
        }
        return;
    }
}

void br_tree::balance(br_node* cur) {
    if((cur->data == root->data) || (cur->parent->data == root->data)) {
        return;
    }
    if((cur->parent->parent->right != NULL) && (cur->parent->parent->left != NULL)) {
        if((cur->parent->parent->left->color == 0) && (cur->parent->parent->right->color == 0)) {
            cur->parent->parent->left->color = 1;
            cur->parent->parent->right->color = 1;
            cur->parent->parent->color = 0;
            balance(cur->parent->parent);
            return;
        }
    }
    if((cur->parent->color == 0) && (cur->color == 0)) { 
        if((cur->parent->left != NULL) && (cur->parent->parent->left != NULL)) {
            if((cur->parent->left->data == cur->data) && (cur->parent->parent->left->data == cur->parent->data)) {
                //case III left
                br_node* temp = cur->parent->parent;
                if(cur->parent->right == NULL) {
                    temp->left = cur->parent->right;
                }
                else {
                    temp->left = cur->parent->right;
                    cur->parent->right->parent = temp;
                }
                cur->parent->right = temp;
                if(temp->parent != NULL) {
                    if(temp->parent->right->data == temp->data) {
                        temp->parent->right = cur->parent;
                    }
                    else {
                        temp->parent->left = cur->parent;
                    }
                }
                else {
                    root = cur->parent;
                }
                cur->parent->parent = temp->parent;
                temp->parent = cur->parent;
                cur->parent->color = 1;
                temp->color = 0;
                balance(cur->parent);
                return;
            }
        }
        if((cur->parent->left != NULL) && (cur->parent->parent->right != NULL)) {
            if((cur->parent->left->data == cur->data) && (cur->parent->parent->right->data == cur->parent->data)){
                //case II right
                br_node* temp1 = cur->parent->parent;
                br_node* temp2 = cur->parent;
                if(cur->right == NULL) {
                    temp2->left = cur->right;
                }
                else {
                    temp2->left = cur->right;
                    cur->right->parent = temp2;
                }
                cur->right = temp2;
                temp2->parent = cur;
                cur->parent = temp1;
                temp1->right = cur;
                balance(temp2);
                return;
            }
        }
        if((cur->parent->right != NULL) && (cur->parent->parent->left != NULL)) {
            if((cur->parent->right->data == cur->data) && (cur->parent->parent->left->data == cur->parent->data)){
                //case II left
                br_node* temp1 = cur->parent->parent;
                br_node* temp2 = cur->parent;
                if(cur->left == NULL) {
                    temp2->right = cur->left;
                }
                else {
                    temp2->right = cur->left;
                    cur->left->parent = temp2;
                }
                cur->left = temp2;
                temp2->parent = cur;
                cur->parent = temp1;
                temp1->left = cur;
                balance(temp2);
                return;
            }
        }
        if((cur->parent->right != NULL) && (cur->parent->parent->right != NULL)) {
            if((cur->parent->right->data == cur->data) && (cur->parent->parent->right->data == cur->parent->data)) {
                //case III right
                br_node* temp = cur->parent->parent;
                if(cur->parent->left == NULL) {
                    temp->right = cur->parent->left;
                }
                else {
                    temp->right = cur->parent->left;
                    cur->parent->left->parent = temp;
                }
                cur->parent->left = temp;
                if(temp->parent != NULL) {
                    if(temp->parent->right->data == temp->data) {
                        temp->parent->right = cur->parent;
                    }
                    else {
                        temp->parent->left = cur->parent;
                    }
                }
                else {
                    root = cur->parent;
                }
                cur->parent->parent = temp->parent;
                temp->parent = cur->parent;
                cur->parent->color = 1;
                temp->color = 0;
                balance(cur->parent);
                return;
            }
        }
    }
    if(root->color == 0) {
        root->color = 1;
        return;
    }
    balance(cur->parent);
}

void br_tree::addPhrase(string words) {
    vector<string> parsed_string = parse_expression(words);
    for(unsigned int i = 0; i < parsed_string.size(); i++) {
        add(parsed_string[i]);
    }
}

void br_tree::remove(string word) {
    if(!(in_tree(word))) {
        return;
    }
    if(root == NULL) {
        return;
    }
    br_node* current;
    br_node* parent;
    current = root;
    while(current) {
        if(current->data == word) {
            break;
        }
        else {
            parent = current;
            if(word > current->data) {
                current = current->right;
            }
            else if(word < current->data) {
                current = current->left;
            }
        }
    }
    if(current->color == 1) {
        h = true;
    }
    else {
        h = false;
    }
    root = del_leaf(root, word);
}

br_node* br_tree::del_leaf(br_node* root, string data) {
    br_node* temp;
    if(root == NULL) {
        return root;
    }
    else {
        if(data < root->data) {
            root->left = del_leaf(root->left, data);
            if(h) {
                cout << "2" << endl;
                bal_del(root->left);
            }
        }
        else {
            if(data > root->data) {
                root->right = del_leaf(root->right, data);
                if(h) {
                    cout << "3" << endl;
                    cout << root->data << endl;
                    bal_del(root->right);
                }
            }
            else {
                temp = root;
                if(temp->right == NULL) {
                    root = temp->left;
                    delete temp;
                }
                else {
                    if(temp->left == NULL) {
                        root = temp->right;
                        delete temp;
                    }
                    else {
                        temp->left = del(temp->left, temp);
                        if(h) {
                            cout << "4" << endl;
                            if(h) {
                                bal_del(temp);
                            }
                        }
                    }
                }
            }
        }
    }
    return root;
}

void br_tree::bal_del(br_node* x) {
    //cout << "bal_del(" << x->data << ")" << endl;
    if(x == NULL) {
        return;
    }
    while(x != root && x->color == 1) {
        if(x == x->parent->left) {
            br_node* w = x->parent->right;
            if(w == NULL) {
                return;
            }
            if(w->right == NULL || w->left == NULL) {
                return;
            }
            if(w != NULL && w->right != NULL && w->left != NULL) {
                if(w->color == 0) {
                    cout << "case 1 first" << endl;
                    w->color = 1;                //Case 1
                    x->parent->color = 0;      //Case 1
                    left_rot(x->parent);      //Case 1
                    w = x->parent->right;        //Case 1
                }
                else if(w->left->color == 1 && w->right->color == 1) {
                    cout << "case 2 first" << endl;
                    w->color = 1;                //Case 2
                    x = x->parent;               //Case 2
                }
                else {
                    if(w->right->color == 1) {
                        cout << "case 3 first" << endl;
                        w->left->color = 1;      //Case 3
                        w->color = 0;            //Case 3
                        right_rot(w);         //Case 3
                        w = x->parent->right;    //Case 3
                    }
                    cout << "case 4 first" << endl;
                    w->color = x->parent->color; //Case 4
                    x->parent->color = 1;        //Case 4
                    w->right->color = 1;         //Case 4
                    left_rot(x->parent);
                    x = root;
                }
            }
        }
        else {
            br_node* w = x->parent->left;
            if(w == NULL) {
                return;
            }
            if(w->right == NULL || w->left == NULL) {
                return;
            }
            if(w->color == 0) {
                cout << "case 1 second" << endl;
                w->color = 1;                 //Case 1
                x->parent->color = 0;         //Case 1
                right_rot(x->parent);      //Case 1
                w = x->parent->left;          //Case 1
            }
            else if(w->right->color == 1 && w->left->color == 1) {
                cout << "case 2 second" << endl;
                w->color = 0;                 //Case 2
                x = x->parent;                //Case 2
            }
            else {
                if(w->left->color == 1) {
                    cout << "case 3 second" << endl;
                    w->right->color = 1;      //Case 3
                    w->color = 0;             //Case 3
                    left_rot(w);           //Case 3
                    w = x->parent->left;      //Case 3
                }
                cout << "case 4 second" << endl;
                w->color = x->parent->color;  //Case 4
                x->parent->color = 1;         //Case 4
                w->left->color = 1;           //Case 4
                right_rot(x->parent);
                x = root;
            }
        }
    }
    x->color = 1;
}

br_node* br_tree::del(br_node* succ, br_node* n) {
    br_node* temp = succ;
    if(succ->right != NULL) {
        succ->right = del(succ->right, n);
    }
    else {
        br_node* current;
        br_node* parent;
        current = root;
        while(current) {
            if(current->data == succ->data) {
                break;
            }
            else {
                parent = current;
                if(succ->data > current->data) {
                    current = current->right;
                }
                else if(succ->data < current->data) {
                    current = current->left;
                }
            }
        }
        if(root->left->data == succ->data) {
            root->data = succ->data;
            n->right = root->right;
            succ = succ->left;
            delete temp;
            return succ;
        } 
        else if(root->right->data == succ->data) {
            root->data = succ->data;
            n->right = root->right;
            succ = succ->right;
            delete temp;
            return succ;
        }
        temp = succ;
        n->data = succ->data;
        succ = succ->left;
        delete temp;
    }
    return succ;
}

void br_tree::right_rot(br_node* x) {
    br_node* y = x->left;
    x->left = y->right;
    if(y->right != NULL) {
        y->right->parent = x;
    }
    y->parent = x->parent;
    if(x->parent == NULL) {
        root = y;
    }
    else if(x == x->parent->right) {
        x->parent->right = y;
    }
    else {
        x->parent->left = y;
    }
    y->right = x;
    x->parent = y;
}

void br_tree::left_rot(br_node* x) {
    br_node* y = x->right;
    x->right = y->left;
    if(y->left != NULL) {
        y->left->parent = x;
    } 
    y->parent = x->parent;
    if(x->parent == NULL) {
        root = y;
    }
    else if(x == x->parent->left) {
        x->parent->left = y;
    }
    else {
        x->parent->right = y;
    }
    y->left = x;
    x->parent = y;
}

void br_tree::printer(br_node* node, int a) {
    a++;
    if(node == NULL) {
        return;
    }
    printer(node->right, a); 
    for(int i = 0; i <= a; i++) {
        cout << "\t";
    }
    printf("%s %d", node->data.c_str(), node->color);
    cout << endl << endl;
    printer(node->left, a);
}

string br_tree::printTree() {
    string tree;
    if(root == NULL) {
        return "";
    }
    cout << root->data << endl;
    cout << endl;
    printer(root, 0);
    cout << endl;
    return tree;
}
