//Derek McQuay 647465151 CS 235 Fall 2012 midterm 1
#include "polylist.h"

polylist::polylist(): head(NULL) {}
polylist::~polylist() {clear();}

void polylist::insert(string term) {
    vector<string> v = parse_expression(term);
    if(!is_valid(v)) {
        return;
    }
    if(v.size() == 1) { //expression of the form x
        if(v[0][0] == '-') {
            insertTail(0, -1, v[0][1]);
        }
        else {
            insertTail(0, 1, v[0][0]);
        }
    }
    if(v.size() == 2) { // expresion of the form 2 x
        int exp = atoi(v[0].c_str());
        insertTail(0, exp, v[1][0]);
    }
    if(v.size() == 3) {    // expression of the form x ^ 4
        int exp = atoi(v[2].c_str());
        int after_exp = 0;
        if(exp == 0) {
            if(v[0][0] == '-') {
                insertTail(exp, -1, v[0][0]);
            }
            else {
                insertTail(exp, 1, v[0][0]);
            }
        }
        node* node_ptr = head;
        while(node_ptr != NULL) {
            if(node_ptr->exponent <= exp) {
                after_exp++;
                break;
            }
            after_exp++;
            node_ptr = node_ptr->next;
        }
        string before = at(after_exp - 1);
        vector<string> previous_vector = parse_expression(before);
        if(previous_vector.size() == 1) {
            if(node_ptr == head) {
                if(node_ptr == head && size() == 0) {
                    if(v[0][0] == '-') {
                        insertHead(exp, -1, v[0][0]);
                    }
                    else {
                        insertHead(exp, 1, v[0][0]);
                    }
                }
                else if(node_ptr->exponent == exp) {
                    node_ptr->coefficient += 1;
                    if(node_ptr->coefficient == 0) {
                        remove(exp);
                    }
                }
                else {
                    if(v[0][0] == '-') {
                        insertHead(exp, -1, v[0][1]);
                    }
                    else {
                        insertHead(exp, 1, v[0][0]);
                    }
                }
            }
            else {
                node_ptr->coefficient += 1;
                if(node_ptr->coefficient == 0) {
                    remove(exp);
                }
            }
        }
        if(previous_vector.size() == 2) {
            if(v[0][0] == '-') {
                insertHead(exp, -1, v[0][1]);
            }
            else {
                insertHead(exp, 1, v[0][0]);
            }
        }
        if(previous_vector.size() == 3) { 
            int insertionNodeExponent = atoi(previous_vector[2].c_str());
            if(insertionNodeExponent == exp) {
                node* node_ptr2 = head;
                while(node_ptr2 != NULL) {
                    if(node_ptr2->exponent == exp) {
                        if(v[0][0] == '-') {
                            node_ptr2->coefficient -= 1;
                        }
                        else {
                            node_ptr2->coefficient += 1;
                        }
                        if(node_ptr2->coefficient == 0) {
                            remove(exp);
                        }
                    }
                    node_ptr2 = node_ptr2->next;
                }
            }
            else{
                if(v[0][0] == '-') {
                    insertAfter(exp, -1, v[0][1], insertionNodeExponent); 
                }
                else {
                    insertAfter(exp, 1, v[0][0], insertionNodeExponent); 
                }
            }
        }
        if(previous_vector.size() == 4) {
            int insertionNodeExponent = atoi(previous_vector[3].c_str());
            if(insertionNodeExponent == exp) {
                node* node_ptr2 = head;
                while(node_ptr2 != NULL) {
                    if(node_ptr2->exponent == exp) {
                        node_ptr2->coefficient += 1;
                        if(node_ptr2->coefficient == 0) {
                            remove(exp);
                        }
                    }
                    node_ptr2 = node_ptr2->next;
                }
            }
            else {
                if(v[0][0] == '-') {
                    insertAfter(exp, -1, v[0][1], insertionNodeExponent);
                }
                else {
                    insertAfter(exp, 1, v[0][0], insertionNodeExponent);
                }
            }
        }
    }
    if(v.size() == 4) {               //expression of the form "2 x ^ 3"
        int coef = atoi(v[0].c_str());
        int exp = atoi(v[3].c_str());
        int after_exp = 0;
        node* node_ptr = head;
        if(exp == 0) {
            insertTail(exp, coef, v[1][0]);
            return;
        }
        while(node_ptr != NULL) {
            if(node_ptr->exponent <= exp) {
                break;
            }
            after_exp++;
            node_ptr = node_ptr->next;
        }
        string before = at(after_exp - 1);
        vector<string> previous_vector = parse_expression(before);
        if(previous_vector.size() == 1) {
            if(node_ptr == head) {
                if(node_ptr == head && size() == 0) {
                    insertHead(exp, coef, v[1][0]);
                }
                else if(node_ptr->exponent == exp) {
                    node_ptr->coefficient += coef;
                    if(node_ptr->coefficient == 0) {
                        remove(exp);
                    }
                }
                else {
                    insertHead(exp, coef, v[1][0]);
                }
            }
            else {
                node_ptr->coefficient += coef;
                if(node_ptr->coefficient == 0) {
                    remove(exp);
                }
            }
        }
        if(previous_vector.size() == 2) {
            insertHead(exp, coef, v[1][0]);
        }
        if(previous_vector.size() == 3) {
            int insertionNodeExponent = atoi(previous_vector[2].c_str());
            if(node_ptr->exponent == exp) {
                node* node_ptr2 = head;
                while(node_ptr2 != NULL) {
                    if(node_ptr2->exponent == exp) {
                        node_ptr2->coefficient += coef;
                        if(node_ptr2->coefficient == 0) {
                            remove(exp);
                        }
                    }
                    node_ptr2 = node_ptr2->next;
                }
            }
            else{
                insertAfter(exp, coef, v[1][0], insertionNodeExponent); 
            }
        }
        if(previous_vector.size() == 4) {
            int insertionNodeExponent = atoi(previous_vector[3].c_str());
            if(node_ptr == NULL) {
                insertTail(exp, coef, v[1][0]);
            }
            else {
                if(node_ptr->exponent == exp) {
                    node* node_ptr2 = head;
                    while(node_ptr2 != NULL) {
                        if(node_ptr2->exponent == exp) {
                            node_ptr2->coefficient += coef;
                            if(node_ptr2->coefficient == 0) {
                                remove(exp);
                            }
                        }
                        node_ptr2 = node_ptr2->next;
                    }
                }
                else {
                    insertAfter(exp, coef, v[1][0], insertionNodeExponent);
                }
            }
        }
    }
}

void polylist::clear() {
    node* node_ptr = head;
    while(head) {
        node_ptr = head;
        head = head->next;
        delete node_ptr;
    }
}

string polylist::at(int index) {
    if(index < 0) {
        return "invalid";
    }
    if(size() <= index) {
        return "invalid";
    }
    node* node_ptr = head;
    for(int i = 0; i < index; i++){
        node_ptr = node_ptr->next;
    }
    if(head == NULL)
        return "invalid";
    stringstream s;
    s << *node_ptr;
    return s.str();
}

int polylist::size() {
    int size_of_list = 0;
    node* node_ptr = head;
    while(node_ptr != NULL) {
        size_of_list++;
        node_ptr = node_ptr->next;
    }
    return size_of_list;
}

string polylist::printList() {
    stringstream s;
    if(head == NULL)
        return "";
    node* node_ptr = head;
    while(node_ptr != NULL) {
        if(node_ptr->next == NULL) {
            s << *node_ptr;
            return s.str();
        }
        else {
            s << *node_ptr << " + ";
            node_ptr = node_ptr->next;
        }
    }
    return s.str();
}

void polylist::remove(int exponent) {
    node* node_ptr = head;
    if(node_ptr->exponent == exponent) {
        node* ptr = head;
        head = head->next;
        delete ptr;
        return;
    }
    while(node_ptr != NULL) {
        if(node_ptr->next == NULL)
            return;
        if(node_ptr->next->exponent == exponent) {
            node* ptr = node_ptr->next;
            node_ptr->next = node_ptr->next->next;
            delete ptr;
        }
        node_ptr = node_ptr->next;
    }
}

void polylist::insertHead(int exponent, int coefficient, char variable) {
    head = new node(exponent, coefficient, variable, head);
}

void polylist::insertTail(int exponent, int coefficient, char variable) {
    if(head == NULL) {
        insertHead(exponent, coefficient, variable);
        return;
    }
    node* node_ptr = head;
    while(node_ptr != NULL) {
        if(node_ptr->next == NULL) {
            if(node_ptr->exponent == exponent) {
                node_ptr->coefficient += coefficient;
                if(node_ptr->coefficient == 0) {
                    remove(exponent);
                }
            }
            else{
                node_ptr->next = new node(exponent, coefficient, variable, NULL);
                break;
            }
        }
        node_ptr = node_ptr->next;
    }
}

void polylist::insertAfter(int exponent, int coefficient, char variable, int insertionNodeExponent) {
    node* node_ptr = head;
    while(node_ptr != NULL) {
        if(node_ptr->exponent == insertionNodeExponent) {
            if(head == node_ptr) {
                insertHead(exponent, coefficient, variable);
            }
            else{
                node* temp = new node(exponent, coefficient, variable, NULL);
                temp->next = node_ptr->next;
                node_ptr->next = temp;
            }
        }
        node_ptr = node_ptr->next;
    }
}

bool is_valid(vector<string> expression) {
    if(expression.empty()) {    //if expression is size 0
        return false;
    }
    if(expression.size() == 1) {          //if expression is size one. only case if "x"
        if(expression[0][0] == '-') {
            if(expression[0] == "-x")
                return true;
            if(!isalpha(expression[0][1]) or expression[0].size() > 1) {
                return false;
            }
        }
        else if(!isalpha(expression[0][0]) or expression[0].size() > 1) {
            return false;
        }
        return true;
    }
    if(expression.size() == 2) {        //if expression is size two, only case is of form "2 x"
        for(unsigned int i = 0; i < expression[0].size(); i++) {
            if(expression[0][0] != '-') {
                if(!isdigit(expression[0][i])) {
                    return false;
                }
            }
        }
        if(!isalpha(expression[1][0]) or expression[1].size() > 1) {
            return false;
        }
        return true;
    }
    if(expression.size() == 3) {     //if expression is size three, only case is of form "x ^ 1"
        if(expression[0][0] == '-') {
            if(expression[0] == "-x")
                return true;
            if(!isalpha(expression[0][1]) or expression[0].size() > 1) {
                return false;
            }
        }
        else if(!isalpha(expression[0][0]) or expression[0].size() > 1) {
            return false;
        }
        if(expression[1] != "^") {
            return false;
        }
        for(unsigned int i = 0; i < expression[2].size(); i++) {
            if(!isdigit(expression[2][i])) {
                return false;
            }
        }
        return true;
    }
    if(expression.size() == 4) {      //if expression is size four, only case is of form "1 x ^ 1"
        for(unsigned int i = 0; i < expression[0].size(); i++) {
            if(expression[0][0] != '-') {
                if(!isdigit(expression[0][i])) {
                    return false;
                }
            }
        }
        if(!isalpha(expression[1][0]) or expression[1].size() > 1) {
            return false;
        }
        if(expression[2] != "^") {
            return false;
        }
        for(unsigned int i = 0; i < expression[3].size(); i++) {
            if(!isdigit(expression[3][i])) {
                return false;
            }
        }
        return true;
    }
    return 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;
}
