#include "Eval.h"

unsigned int next_exp(char* ins, unsigned int off, char* subx, double* v);

TreeNode::TreeNode() {
    parent=this;
    children=0;
    numc=0;
    data=new Data;
    data->val=0;
    data->token=0;
 };

TreeNode::TreeNode(TreeNode &N) {
    parent=this;
    if (!data) data=new Data;
    data->token=N.data->token;
    data->val=N.data->val;
    if (N.numc==0) {numc=0; children=0;}
    else {
        TLNode *p=N.children;
        TLNode *q=children=new TLNode;
        for(int i=0; i<N.numc; i++) {
            q->TNp=new TreeNode(N[i], this);
            p=p->next;
            if (p) {
                q->next=new TLNode;
                q=q->next;
            }
        }
    }
    numc=N.numc;
};

TreeNode::TreeNode( TreeNode &N, TreeNode *par) {
    parent=par;
    if (!data) data=new Data;
    data->token=N.data->token;
    data->val=N.data->val;
    if (N.numc==0) {numc=0; children=0;}
    else {
        TLNode *p=N.children;
        TLNode *q=children=new TLNode;
        for(int i=0; i<N.numc; i++) {
            q->TNp=new TreeNode(N[i], this);
            p=p->next;
            if (p) {
                q->next=new TLNode;
                q=q->next;
            }
        }
    }
    numc=N.numc;
};
TreeNode::TreeNode(char *instr) {
    parent=this;
    children=0;
    numc=0;
    data=new Data;
    data->val=0; data->token=0;
    TreeNode *p=new TreeNode;
    p->data=new Data;
    p->data->token=instr[1];
    addChild(*p);
    TreeNode1(instr, 2);
};

void TreeNode::TreeNode1(char *instr, unsigned int offset) {
    TreeNode *p;
    char sub[81]; double val; unsigned int nextoff=offset;
    while(nextoff) {
        nextoff=next_exp(instr, nextoff, sub, &val);
        if (!nextoff) return;
        if (!sub[0]) {
            p=new TreeNode;
            p->data->val=val;
            p->parent=this;
        }
        else {
            p=new TreeNode(sub);
        }
        addChild(*p);
    }
    return;

};
TreeNode& TreeNode::operator[]( unsigned int index) {
    TLNode *p=children;
    int i;
    for (i=0; i<index; i++, p=p->next);
    return *(p->TNp);
};

double Tree::eval() {
    return root->eval();
};

double TreeNode::eval() {
    double value;
    int i;
    if (data->val) return data->val;
    value=this->operator[](1).eval();
    switch (children->TNp->data->token) {
        case '+': for (i=2;i<numc;i++) value+=this->operator[](i).eval(); break;
        case '*': for (i=2;i<numc;i++) value*=this->operator[](i).eval(); break;
        case 'M': for (i=2;i<numc;i++)
                    if (value<(this->operator[](i).eval()))
                        value=this->operator[](i).eval();
                  break;
        case 'm': for (i=2;i<numc;i++)
                    if (value>(this->operator[](i).eval()))
                        value=this->operator[](i).eval();
                  break;
        case 'A': for (i=2;i<numc;i++) value+=this->operator[](i).eval();
                  value/=numc;
                  break;
        case '-': value-=this->operator[](2).eval();
        case '/': value/=this->operator[](2).eval();
    }
    return value;
};

unsigned int TreeNode::addChild(TreeNode& child) {
    child.parent=this;
    TLNode *p=children;
    if (children) {
        for (int i=0; i<numc-1; i++) p=p->next;
        assert(0!=(p->next=new TLNode));
        p->next->TNp=&child;
        p->next->next=0;
    }
    else {
        p=children=new TLNode;
        p->next=0;
        p->TNp=&child;
    }
    numc+=1;
    return numc;
};

unsigned int next_exp(char* ins, unsigned int off, char* subx, double* v) {
    unsigned int sxsz, num_par, rv, sz = strlen(ins);
    istrstream ststr(ins, sz);
    char c;
    ststr.seekg(off);
    ststr >> c;
    off = ststr.tellg() - 1;

    switch(c) {
       case ')': rv = 0;
                   	  subx[0] = '\0';
                      (*v) = 0.0;
                      break;
       case '.': case '1': case '2': case '3': case '4': case '5': case '6':
       case '7': case '8': case '9': case '0': ststr.putback(c);
                                               ststr >> (*v);
                                               rv = ststr.tellg();
                                               subx[0] = '\0';
                                               break;
       case '-': ststr >> (*v);
                 (*v) *= -1.0;
                 rv = ststr.tellg();
                 subx[0] = '\0';
                 break;
       case '(': num_par = 1;
                 while (num_par > 0) {
              	     ststr >> c;
                     if (c == '(') num_par++;
                     else if (c == ')') num_par--;
                 }
         		 rv = ststr.tellg();
                 sxsz = rv - off;
                 for(int i = off; i < rv; i++) subx[i - off] = ins[i];
                 subx[sxsz] = '\0';
                 (*v) = 0.0;
                 break;
    }
    return(rv);
}


int main() {
    char instr[MAX_EXP_SIZE + 1], nl, ans;
    do {
      cout << "Input string to be evaluated:" << endl << "> ";
      cin.get(instr, MAX_EXP_SIZE, '\n');
      cin.get(nl);
      TreeNode fnode(instr);
      cout << "And the value is: " << fnode.eval() << endl;
      cout << endl << "\tAnother? (y or n): ";
      cin >> ans;
      cin.get(nl);
   } while ((ans == 'y') || (ans == 'Y'));
    return 0;

}

