#include "dmlib.h"
#include "dmeval.h"
#include "dmargs.h"


BOOL    optBenchmark = FALSE,
        optFloor = FALSE;
char *  optExpression = "";


DMOptArg optList[] =
{
    { 0, '?', "help",       "Show this help", OPT_NONE },
    { 1, 'v', "verbose",    "Be more verbose", OPT_NONE },
    { 2, 'b', "benchmark",  "Run in benchmark mode", OPT_NONE },
    { 3, 'e', "expression", "Next argument is the expression", OPT_ARGREQ },
    { 4, 'f', "floor",      "Clamp/floor the result value", OPT_NONE },
};

const int optListN = sizeof(optList) / sizeof(optList[0]);


void argShowHelp()
{
    dmPrintBanner(stdout, dmProgName, "[options] [-e] '<expression>'");
    dmArgsPrintHelp(stdout, optList, optListN);
}


BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
{
    switch (optN)
    {
    case 0:
        argShowHelp();
        exit(0);
        break;

    case 1:
        dmVerbosity++;
        break;
    
    case 2:
        optBenchmark = TRUE;
        break;

    case 3:
        optExpression = optArg;
        break; 

    case 4:
        optFloor = TRUE;
        break;

    default:
        dmError("Unknown option '%s'.\n", currArg);
        return FALSE;
    }
    
    return TRUE;
}


BOOL argHandleNonOpt(char *currArg)
{
    optExpression = currArg;
    return TRUE;
}


int main(int argc, char *argv[])
{
    DMEvalContext *ev = dmEvalContextNew();
    DMEvalNode *expr = NULL;
    DMValue result, t, f = 44100.0f;
    int ret;

    dmInitProg("evaltest", "evaltest", "0.1", NULL, NULL);

    // Parse arguments
    if (!dmArgsProcess(argc, argv, optList, optListN,
        argHandleOpt, argHandleNonOpt, FALSE))
        exit(1);


    // Register some variables
    dmEvalContextAddVar(ev, "t", &t);
    dmEvalContextAddVar(ev, "f", &f);


    // Parse expression
    ret = dmEvalParseExpr(ev, optExpression, &expr);
    dmMsg(1, "parse ret=%d\n", ret);
    if (ev->err)
        dmError("%s\n", ev->errStr);

    if (dmVerbosity > 0)
        dmEvalPrintOpTree(stdout, ev, expr);
    
    if (ret != 0)
        return -1;
    
    // Benchmark or execute
    dmEvalContextClear(ev);

    if (optBenchmark)
    {
        dmMsg(0, "Benchmarking ...\n");
        for (t = 0; t < 12500000; t++)
            ret = dmEvalTreeExecute(ev, expr, &result);
    }
    else
    {
        ret = dmEvalTreeExecute(ev, expr, &result);
        printf("%1.5f\n", optFloor ? (int) result : result);
    }

    dmMsg(1, "eval ret=%d\n", ret);

    dmEvalContextClose(ev);
    dmEvalTreeFree(expr);

    return 0;
}
