/*
    File: exprobj.c
    Auth: Brian Allen Vanderburg II
    Date: Tuesday, April 29, 2003
    Desc: Functions for the exprObj type

    This file is part of ExprEval.
*/

/* Includes */
#include "exprincl.h"

#include "exprpriv.h"
#include "exprmem.h"

/* Internal functions */
static void exprFreeNodeData(exprNode *node);


/* Function to create an expression object */
int exprCreate(exprObj **obj, exprFuncList *flist, exprValList *vlist, exprValList *clist,
    exprBreakFuncType breaker, void *userdata)
    {
    exprObj *tmp;

    /* Allocate memory for the object */
    tmp = exprAllocMem(sizeof(exprObj));

    if(tmp == NULL)
        return EXPR_ERROR_MEMORY;


    /* Assign data */
    tmp->flist = flist;
    tmp->vlist = vlist;
    tmp->clist = clist;
    tmp->breakerfunc = breaker;
    tmp->userdata = userdata;
    tmp->breakcount = 100000; /* Default breaker count setting */
    tmp->breakcur = 0;

    /* Update pointer */
    *obj = tmp;

    return EXPR_ERROR_NOERROR;
    }


/* Free the expression */
int exprFree(exprObj *obj)
    {
    if(obj == NULL)
        return EXPR_ERROR_NOERROR;

    /* First free the node data */
    exprFreeNodeData(obj->headnode);
    exprFreeMem(obj->headnode);

    /* Free ourself */
    exprFreeMem(obj);

    return EXPR_ERROR_NOERROR;
    }

/* Clear expression, keep lists, etc */
int exprClear(exprObj *obj)
    {
    if(obj == NULL)
        return EXPR_ERROR_NOERROR;

    /* Free the node data only, keep function, variable, constant lists */
    exprFreeNodeData(obj->headnode);
    exprFreeMem(obj->headnode);

    obj->headnode = NULL;
    obj->parsedbad = 0;
    obj->parsedgood = 0;

    return EXPR_ERROR_NOERROR;
    }


/* Get functions to get information about the expression object */

/* Get the function list */
exprFuncList *exprGetFuncList(exprObj *obj)
    {
    return (obj == NULL) ? NULL : obj->flist;
    }

/* Get the variable list */
exprValList *exprGetVarList(exprObj *obj)
    {
    return (obj == NULL) ? NULL : obj->vlist;
    }

/* Get the constant list */
exprValList *exprGetConstList(exprObj *obj)
    {
    return (obj == NULL) ? NULL : obj->clist;
    }

/* Get the breaker function */
exprBreakFuncType exprGetBreakFunc(exprObj *obj)
    {
    return (obj == NULL) ? NULL : obj->breakerfunc;
    }

/* Check for break status */
int exprGetBreakResult(exprObj *obj)
    {
    if(obj == NULL)
        return 0;

    if(obj->breakerfunc == NULL)
        return 0;

    return (*(obj->breakerfunc))(obj);
    }

/* Get the user data */
void *exprGetUserData(exprObj *obj)
    {
    return (obj == NULL) ? NULL : obj->userdata;
    }


/* Set functions to set certain data */

/* Set user data */
void exprSetUserData(exprObj *obj, void *userdata)
    {
    if(obj)
        obj->userdata = userdata;
    }


/* Set breaker count */
void exprSetBreakCount(exprObj *obj, int count)
    {
    if(obj)
        {
        /* If count is negative, make it positive */
        if(count < 0)
            count = -count;

        obj->breakcount = count;

        /* Make sure the current value is not bigger than count */
        if(obj->breakcur > count)
            obj->breakcur = count;
        }
    }

/* Get error position */
void exprGetErrorPosition(exprObj *obj, int *start, int *end)
    {
    if(obj)
        {
        if(start)
            *start = obj->starterr;

        if(end)
            *end = obj->enderr;
        }
    }

/* This function will free a node's data */
static void exprFreeNodeData(exprNode *node)
    {
    int pos;

    if(node == NULL)
        return;

    /* free data based on type */
    switch(node->type)
        {
        case EXPR_NODETYPE_ADD:
        case EXPR_NODETYPE_SUBTRACT:
        case EXPR_NODETYPE_MULTIPLY:
        case EXPR_NODETYPE_DIVIDE:
        case EXPR_NODETYPE_EXPONENT:
        case EXPR_NODETYPE_NEGATE:
        case EXPR_NODETYPE_MULTI:
            /* Free operation data */
            if(node->data.oper.nodes)
                {
                for(pos = 0; pos < node->data.oper.nodecount; pos++)
                    exprFreeNodeData(&(node->data.oper.nodes[pos]));

                exprFreeMem(node->data.oper.nodes);
                }

            break;


        case EXPR_NODETYPE_VALUE:
            /* Nothing to free for value */
            break;

        case EXPR_NODETYPE_VARIABLE:
            /* Nothing to free for variable */
            break;

        case EXPR_NODETYPE_FUNCTION:
            /* Free data of each subnode */
            if(node->data.function.nodes)
                {
                for(pos = 0; pos < node->data.function.nodecount; pos++)
                    exprFreeNodeData(&(node->data.function.nodes[pos]));

                /* Free the subnode array */
                exprFreeMem(node->data.function.nodes);
                }

            /* Free reference variable list */
            if(node->data.function.refs)
                exprFreeMem(node->data.function.refs);

            break;

        case EXPR_NODETYPE_ASSIGN:
            /* Free subnode data */
            if(node->data.assign.node)
                {
                exprFreeNodeData(node->data.assign.node);

                /* Free the subnode */
                exprFreeMem(node->data.assign.node);
                }

            break;
        }
    }


