#include "Expression.h"
#include "OperandStack.h"
#include <cassert>

Expression::Expression(istream &is)
{
    TreeNodeStack dataStack;
    Complex operand;
    Node *operandNode1, *operandNode2;
    char buf;

    while (is>>buf)
    {
        if ((buf=='+')||(buf=='-')||(buf=='*')||(buf=='/'))
        {
            dataStack.pop(operandNode2);
            dataStack.pop(operandNode1);
            dataStack.push(new Node(buf, Complex(0,0),
                                    operandNode1, operandNode2));
        }
        else
        {
            is.unget();
            is >> operand;
            dataStack.push(new Node('o', operand, 0, 0));
        }
    }
    dataStack.pop(m_root);
}

Expression::~Expression(void)
{
    freeTree(m_root);
}

void Expression::inorderPrint(ostream &os)
{
    inorderPrint(os, m_root);
}

void Expression::inorderPrint(ostream &os, Node *ptr)
{
    if (ptr == 0) return;
    if (ptr->left) inorderPrint(os, ptr->left);
    if (ptr->op == 'o')
        os << ptr->operand;
    else
        os << ' ' << ptr->op << ' ';

    if (ptr->right) inorderPrint(os, ptr->right);
}

Expression::Expression(const Expression &src)
{
    m_root = cloneTree(src.m_root);
}

void Expression::freeTree(Node *ptr)
{
    if (ptr == 0) return;
    if (ptr->left) freeTree(ptr->left);
    if (ptr->right) freeTree(ptr->right);
    delete ptr;
}

Expression::Node *Expression::cloneTree(Node *ptr)
{
    if (ptr == 0)
        return 0;
    Node *left=cloneTree(ptr->left);
    Node *right=cloneTree(ptr->right);
    return new Node(ptr->op, ptr->operand, left, right);
}

void Expression::perform(char op, Complex &operand1, const Complex &operand2)
{
    if (op == '+')
        operand1.add(operand2);
    else if (op == '-')
        operand1.subtract(operand2);
    else if (op == '*')
        operand1.multiply(operand2);
    else if (op == '/')
        operand1.divide(operand2);
}

Complex Expression::evaluate()
{
    if (m_root == 0) 
        return Complex(0,0);
    else
        return evaluate(m_root);
}

Complex Expression::evaluate(Node *ptr)
{
    Complex left, right;
    if (ptr->op == 'o')
        return ptr->operand;
    assert(ptr->left!=0);
    assert(ptr->right!=0);
    left = evaluate(ptr->left);
    right = evaluate(ptr->right);
    perform(ptr->op, left, right);
    return left;
}

Expression::TreeNodeStack::TreeNodeStack(void):m_top(-1)
{
}


Expression::TreeNodeStack::~TreeNodeStack(void)
{
}


void Expression::TreeNodeStack::push(Node *data)
{
    if (m_top<99)
        m_data[++m_top] = data;
}


int Expression::TreeNodeStack::pop(Node *&data)
{
    if (m_top >= 0)
    {
        data = m_data[m_top--];
        return 1;
    }
    return 0;
}