#include "array_call_rewrite.h"
#include "assert.h"
#include "utils.h"
#include "dbug.h"
#include "memory.h"
#include "symbol_table.h"
#include "traverse.h"
#include "tree_basic.h"
#include "mymacros.h"
#include "free.h"
#include <string.h>

struct INFO
{
    node* call_node;
};

static info* info_init(void)
{
    info* result;

    DBUG_ENTER("info_init");

    result = (info*)MEMmalloc(sizeof(struct INFO));

    result->call_node = NULL;

    DBUG_RETURN(result);
}

static void info_free(info* inf)
{
    DBUG_ENTER("info_free");

    MEMfree(inf);
}

node* ACRcall(node* arg_node, info* arg_info)
{
    info old_info = *arg_info;

    arg_info->call_node = arg_node;

    CALL_PARAMS(arg_node) = ACRexprs(CALL_PARAMS(arg_node), arg_info);

    *arg_info = old_info;
    return arg_node;
}

node* ACRexprs(node* arg_node, info* arg_info)
{
    if (!arg_node) return arg_node;

    node* expr = EXPRS_EXPR(arg_node);
    node* result = arg_node;

    if (!arg_info->call_node)
        goto end;

    if (NODE_TYPE(expr) != N_var || !TY_IS_ARRAY(VAR_STLINK(expr)->type) || VAR_IS_ARRAYIDX(expr))
        goto end;

    struct st_entry_arr* arr_var = (struct st_entry_arr*)VAR_STLINK(expr);

    node* prev_exprs = NULL;
    node* cur_exprs = NULL;

    for (int i = 0; i < arr_var->n_dims; ++i, prev_exprs = cur_exprs)
    {
        node* var = TBmakeVar(strdup(arr_var->dim_vars[i]->name), NULL);
        VAR_STLINK(var) = arr_var->dim_vars[i];
        VAR_RELFRAMENO(var) = VAR_RELFRAMENO(expr);

        cur_exprs = TBmakeExprs(var, NULL);

        if (i == 0) result = cur_exprs;

        if (prev_exprs) EXPRS_NEXT(prev_exprs) = cur_exprs;
    }

    EXPRS_NEXT(prev_exprs) = arg_node;

end:
    EXPRS_NEXT(arg_node) = ACRexprs(EXPRS_NEXT(arg_node), arg_info);

    return result;
}


node* ACRdoRewrite(node* syntaxtree)
{
    DBUG_ENTER("ACRdoRewrite");

    info* arg_info = info_init();

    TRAVpush(TR_acr);
    syntaxtree = TRAVdo(syntaxtree,arg_info);
    TRAVpop();

    info_free(arg_info);

    DBUG_RETURN(syntaxtree);
}