#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "calc.h"

#define BUF_LEN 1024
#define TEMP_FILE "temp.txt"

static int calc_result(calc_syntax_node *node, void *ib)
{
    calc_syntax_node **child;
    wchar_t *str, *ch;
    int res = 0, sign = 1, temp, op;

    switch (node->type)
    {
    case CALC_EXP_NODE:
        temp = 0;
        for (child = node->children; *child; ++child)
        {
            int num = 0;

            if ((*child)->type == CALC_ADDOP_NODE)
            {
                sign = calc_result(*child, ib);
            }
            else
            {
                num = calc_result(*child, ib);
                temp += sign * num;
            }
        }
        res = temp;
        break;
    case CALC_TERM_NODE:
        temp = 1;
        op = 1;
        for (child = node->children; *child; ++child)
        {
            int num = 1;

            if ((*child)->type == CALC_MULOP_NODE)
            {
                op = calc_result(*child, ib);
            }
            else
            {
                num = calc_result(*child, ib);
                temp = op ? temp * num : temp / num;
            }
        }
        res = temp;
        break;
    case CALC_FACTOR_NODE:
        res = calc_result(*node->children, ib);
        break;
    case CALC_NUMBER_NODE:
        str = calc_get_input_string(node, ib);
        if (str && str[0])
        {
            int num = 0;
            for (ch = str; *ch; ++ch)
            {
                if (*ch >= L'0' && *ch <= L'9')
                    num = (num * 10) + (*ch - L'0');
            }
            res = num;
        }
        break;
    case CALC_GROUP_NODE:
        if (node->children[1])
            res = calc_result(node->children[1], ib);
        break;
    case CALC_ADDOP_NODE:
        str = calc_get_input_string(node, ib);
        if (str && str[0])
        {
            if (str[0] == L'+')
                res = 1;
            else
                res = -1;
        }
        free(str);
        break;
    case CALC_MULOP_NODE:
        str = calc_get_input_string(node, ib);
        if (str && str[0])
        {
            if (str[0] == L'*')
                res = 1;
            else
                res = 0;
        }
        free(str);
        break;
    }

    return res;
}


int main(int argc, char* argv[])
{
    char buf[BUF_LEN];
    calc_syntax_node *exp;
    void *input = 0, *errors = 0;

    while (1)
    {
        fprintf(stdout, "Please enter an expression (Enter to quit): ");
        fgets(buf, BUF_LEN, stdin);

        if (strlen(buf) > 1)
        {
            FILE *f = fopen(TEMP_FILE, "w");


            fwrite(buf, sizeof(char), strlen(buf), f);
            fclose(f);

            if (calc_parse(TEMP_FILE, &exp, &input, &errors))
            {
                int res = calc_result(exp, input);
                fprintf(stdout, "Result: %d\n\n", res);
            }
            else
            {
                int i, num = calc_num_errors(errors);
                for (i = 0; i < num; ++i)
                {
                    calc_error_rec *rec = calc_get_error(errors, i);
                    fprintf(stderr, "error: %ls\n", rec->str);
                }
            }

            calc_destroy_error_list(errors);
            calc_destroy_input_buffer(input);
        }
        else
        {
            break;
        }
    }

    return 0;
}

