/* errors.c */

#include "computorv1.h"

static void print_context_input()
{
    ft_dprintf(STDERR_FILENO, "\ninput : %s\n", input_g_err);
}

static void print_context_tokens()
{
    int i;

    ft_putchar_fd('\n', STDERR_FILENO);
    i = 0;
    while (tokens_g_err[i].type != TOKEN_END)
    {
        ft_dprintf(STDERR_FILENO, "token[%2i] - type : ", i);

        if (tokens_g_err[i].type == TOKEN_VARIABLE)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_VARIABLE");
        else if (tokens_g_err[i].type == TOKEN_NUMBER_INT)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_NUMBER_INT");
        else if (tokens_g_err[i].type == TOKEN_NUMBER_DOUBLE)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_NUMBER_DOUBLE");
        else if (tokens_g_err[i].type == TOKEN_POWER)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_POWER");
        else if (tokens_g_err[i].type == TOKEN_SIGN_PLUS)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_SIGN_PLUS");
        else if (tokens_g_err[i].type == TOKEN_SIGN_MINUS)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_SIGN_MINUS");
        else if (tokens_g_err[i].type == TOKEN_FACTOR_MULT)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_FACTOR_MULT");
        else if (tokens_g_err[i].type == TOKEN_FACTOR_DIV)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_FACTOR_DIV");
        else if (tokens_g_err[i].type == TOKEN_EQUAL)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_EQUAL");
        else if (tokens_g_err[i].type == TOKEN_END)
            ft_dprintf(STDERR_FILENO, "%20s", "TOKEN_END");

        ft_putstr(" - value : ");

        if (tokens_g_err[i].type == TOKEN_NUMBER_INT)
        {
            ft_dprintf(STDERR_FILENO, "%i\n", tokens_g_err[i].value_int);
        }
        else if (tokens_g_err[i].type == TOKEN_NUMBER_DOUBLE)
        {
            dprintf(STDERR_FILENO, "%g\n", tokens_g_err[i].value_double);
        }
        else
        {
            ft_dprintf(STDERR_FILENO, "%c\n", tokens_g_err[i].value_char);
        }
        i++;
    }
    ft_putchar_fd('\n', STDERR_FILENO);
}

static void print_context_terms()
{
    int i;

    ft_putchar_fd('\n', STDERR_FILENO);
    i = 0;
    while (terms_g_err[i].position != TERM_END)
    {
        ft_dprintf(STDERR_FILENO, "term[%2i] - ", i);

        // position
        ft_dprintf(STDERR_FILENO, "%8s : ", "position");
        if (terms_g_err[i].position == TERM_LEFT)
            ft_dprintf(STDERR_FILENO, "%10s", "TERM_LEFT");
        else if (terms_g_err[i].position == TERM_RIGHT)
            ft_dprintf(STDERR_FILENO, "%10s", "TERM_RIGHT");
        else
            ft_dprintf(STDERR_FILENO, "%10s", "");

        // sign
        ft_dprintf(STDERR_FILENO, " | %4s : ", "sign");
        if (terms_g_err[i].sign == TERM_PLUS)
            ft_dprintf(STDERR_FILENO, "%10s", "TERM_PLUS");
        else if (terms_g_err[i].sign == TERM_MINUS)
            ft_dprintf(STDERR_FILENO, "%10s", "TERM_MINUS");
        else
            ft_dprintf(STDERR_FILENO, "%10s", "");

        // coefficient
        dprintf(STDERR_FILENO, " | %10s : %13g", "coefficient", terms_g_err[i].coefficient);

        // exponent
        ft_dprintf(STDERR_FILENO, " | %8s : %d\n", "exponent", terms_g_err[i].exponent);
        i++;
    }
    ft_putchar_fd('\n', STDERR_FILENO);
}

static void print_context_polynom()
{
    dprintf(STDERR_FILENO, "\npolynom[a]: %10g\n", polynom_g_err->a);
    dprintf(STDERR_FILENO, "polynom[b]: %10g\n", polynom_g_err->b);
    dprintf(STDERR_FILENO, "polynom[c]: %10g\n", polynom_g_err->c);
}

void print_state()
{
    ft_dprintf(STDERR_FILENO, "\nSTATE :\n");
    if (input_g_err)
        print_context_input();
    if (tokens_g_err)
        print_context_tokens();
    if (terms_g_err)
        print_context_terms();
    if (polynom_g_err)
        print_context_polynom();
}

int stop_errors(e_program_error err, const char *details, ...)
{
    // the base error message
    const char *msg = "error: error type is out of range";

    // map error codes to messages
    const char *error_messages[ERROR_SENTINEL] = {
        [ERROR_BASE] = "undefined error",
        [ERROR_UNKNOWN_TOKEN] = "LEXER - unknown token",
        [ERROR_NUMBER_TOO_BIG] = "LEXER - number is too big",
        [ERROR_PARSING] = "PARSER - too much terms to parse",
        [ERROR_TOKEN_POSITION] = "PARSER - token position is not good in grammar",
        [ERROR_VAR_DIFF] = "PARSER - expression must only contain one variable",
        [ERROR_TOKEN_COUNT] = "LEXER - token count error",
        [ERROR_TERM_COUNT] = "PARSER - term count error",
    };

    // override msg if err is in the error_messages array
    if (err >= ERROR_BASE && err < ERROR_SENTINEL)
    {
        msg = error_messages[err];
    }

    // print context
    print_state();

    // print the base message
    ft_dprintf(STDERR_FILENO, "error: (%i) %s - details: ", err, msg);

    // print the formatted details
    va_list args;
    va_start(args, details);
    ft_vdprintf(STDERR_FILENO, details, args);
    va_end(args);

    ft_putchar_fd('\n', STDERR_FILENO);

    exit(err);
}