//
// Calculator.cpp
//
#include "StdAfx.h"

// Ignore truncation warnings
#pragma warning(disable: 4786)

#include "FiniteStateMachine.h"
#include "Logging.h"
#include "math.h"
#include "float.h"
// 
// May need to modify operand type and value if mixed math,
// hence the need to pass the complete operand 
//
static int parens=0;
typedef  double (*DblFcnPtr1arg)(double a);
typedef  double (*DblFcnPtr2arg)(double a, double b);

// Revamped STL because it missed a few operators 
#include "mystack.h"




//----------------------------------------------------------------------
//
// OPERATOR handling: + - * / ** etc.
//
// character strings are used to match against to find operator. Problem
// not solved is ** versus *. ** is just tested first. Unclear how
// to handle this problem.
// 
//----------------------------------------------------------------------


typedef enum { 
        opNULL=0,   
        opPOWER=1,  
        opPLUS=2, 
        opMINUS=3, 
        opTIMES=4, 
        opDIVIDE=5, 
        opEQ=6, 
        opNE=7,
        opLT=8, 
        opLE=9, 
        opGT=10, 
        opGE=11, 
        opAND=12, 
        opOR=13 , 
        opNOT=14, 
        opLFPAREN=15,
        opRTPAREN=16,
        opASIN=17,
        opATAN=18,
        opCOS=19,
        opEXP=20,
        opLOG=21,
        opLOG10=22,
        opSIN=23,
        opSQRT=24,
        opTAN=25,
        opCOMMA=26,
        opENDMARK=17
}  OPTYPE;


struct operations 
{
    static double add(double a, double b) { return a+b; }
    static double sub(double a, double b) { return a-b; }
    static double mult(double a, double b) { return a*b; }
    static double div(double a, double b) { return a/b; }
    static double equals(double a, double b) { return  a == b ; }
    static double ne(double a, double b) { return  a != b ; }
    static double ge(double a, double b) { return  a >= b ; }
    static double gt(double a, double b) { return  a > b ; }
    static double le(double a, double b) { return  a <= b ; }
    static double lt(double a, double b) { return  a <b ; }
    static double and(double a, double b) { return ((int) a) && ((int) b) ; }
    static double or(double a, double b) { return ((int) a) || ((int) b) ; }
    static double bitand(double a, double b) { return ((int) a) & ((int) b) ; }
    static double bitor(double a, double b) { return ((int) a) | ((int) b) ; }
    
};

// 
// Kludge to allow power "**" to be checked before times "*"
// Better to use regular expression  or pattern match.
//
struct OPTOKEN {
    String op;
    int operands;
    int  rank;
    OPTOKEN(String n_op, int n_operands, int n_rank){ 
        op=n_op;
        operands=n_operands;
        rank=n_rank;
    }
};
OPTOKEN optoken[28] =  {
    OPTOKEN(String(L""),   0,     0), 
        OPTOKEN(String(L"**"),  2,    15), /* POWER*/
        OPTOKEN(String(L"+"),   2,   12), /* PLUS */
        OPTOKEN(String(L"-"),   2,   12), /* MINUS */
        OPTOKEN(String(L"*"),   2,    13), /* TIMES*/
        OPTOKEN(String(L"/"),   2,    13), /* DIVIDE*/
        OPTOKEN(String(L"=="),  2,   9), /* EQ */
        OPTOKEN(String(L"!="),  2,  10), /* NE*/
        OPTOKEN(String(L"<"),   2, 10), /* LT*/
        OPTOKEN(String(L"<="), 2,   10), /* LE*/
        OPTOKEN(String(L">"),  2,  10), /* GT*/
        OPTOKEN(String(L">="),  2,  10), /* GE*/
        OPTOKEN(String(L"&&"), 2,  5), /* AND*/
        OPTOKEN(String(L"||"), 2,   4), /* OR*/
        OPTOKEN(String(L"!"),  1, 14), /* NOT*/
        OPTOKEN(String(L"("),  0, 1), 
        OPTOKEN(String(L")"),  0, 1), 
        OPTOKEN(String(L"ASIN"),  1, 1),
        OPTOKEN(String(L"ATAN"),  1, 1),
        OPTOKEN(String(L"COS"),  1, 1), 
        OPTOKEN(String(L"EXP"),  1, 1), 
        OPTOKEN(String(L"LOG"),  1, 1), 
        OPTOKEN(String(L"LOG10"),  1, 1),
        OPTOKEN(String(L"SIN"),  1, 1), 
        OPTOKEN(String(L"SQRT"),  1, 1),
        OPTOKEN(String(L"TAN"),  1, 1), 
        OPTOKEN(String(L","),  0, 2), 
        OPTOKEN(String(L"end-mark"), 0,  1)
};

OPTYPE findOpToken(String token)
{
    for(int i=0; i< 28; i++){
        if(!optoken[i].op.CompareNoCase(token)) return (OPTYPE) i;
    }
    return (OPTYPE) 0; 
}

struct CToken
{
    String type;
    String value;
    union {
        OPTYPE optype;
        double dvalue;
        int ivalue;
    };
};


// 
//----------------------------------------------------------------------
// int getNextToken(String &line, CToken & token )
//
//
//----------------------------------------------------------------------
//
int getNextToken(String &line, CToken & token )
{
    int j=0;
    WCHAR match;
    int i=0;
    
    token.type.Nullify();
    token.value.Nullify();
    token.optype=opNULL;
    
    line.LeftTrim();
    // check for quoted string as token 
    if(line.Size()==0) return 0;
    if(line[i] == L'(' ){
        token.value=L"(";
        token.optype=findOpToken(token.value);
        token.type=L"left-paren";
        line=line.Mid(2);
        return(1);
    }
    if(line[i] == L')' ){
        token.value=L")";
        token.optype=findOpToken(token.value);
        token.type=L"right-paren";
        line=line.Mid(2);
        return(1);
    }

    if(line[i] == L',' ){
        token.value=line[i];
        token.optype=findOpToken(token.value);
        token.type=L"operator";
        line=line.Mid(2);
        return(1);
    }
    
    if((line[i] == L'\'') || (line[i] == L'\"'))
    {
        match=line[i];
        int n=line.Find(match,ffNone, 1);
        
        if(n==0) return 0;
        token.value=line.Mid(1,n-1);
        token.type=match;
        line=line.Mid(n+1);
        return(1);
    }
    
#if 0
    // Match operand without number
    if((line[i]==L'+') || (line[i]==L'-') /*&& !iswdigit(line[i+1])*/){
        token.value=line[i];
        token.optype=findOpToken(token.value);
        token.type=L"operator";
        line=line.Mid(2);
        return 1;
    }
#endif
    while(wcsrchr(L"*/><=|&!+-", line[i])) i++;
    if(i>0) 
    {
        token.value=line.Mid(1,i);
        token.optype=findOpToken(token.value);
        token.type=L"operator";
        if(optoken[token.optype].operands==1) token.type=L"unaryoperator";
        line=line.Mid(i+1);
        return 1;
    }
    
    // Match regular alphanumeric token 
    //    if(!iswalnum(line[i]) && (line[i]!=L'_'))   return(0);
    
    if(iswdigit(line[i]))  {
        int n;
        n  = swscanf((BSTR) line,L"%lf%n", &token.dvalue, &i);
        if(n>0) { 
            token.type=L"number";
            line=line.Mid(i+1);
            return 1;
        }
        /**
        // Not double try integer - shouldn't need this
        int j;
        n  = swscanf((BSTR) line,L"%d%n", &token.ivalue, &j);
        if(n>0) { 
        token.type=L"integer";
        line=line.Mid(i+1);
        return 1;
        }
        */
        return 0;
        
    }
    
    while(i<line.Size() && (iswalpha(line[i]) || (line[i]==L'_'))) i++;
    if(i>0) {
        token.value=line.Mid(1,i);
        token.type=L"token";
        line=line.Mid(i+1);
        DblFcnPtr1arg mathfcn=0;
        token.optype=findOpToken(token.value);
        if(token.optype!=0) token.type="unaryoperator";
        
        // Requires 2 arguments */
#if 0
        if(!strcmp(token,"ATAN2")) mathfcn=atan2;
        if(!strcmp(token,"POW")) mathfcn=pow;
#endif
        return 1;
    }
    return 0;
}


/**
@include CalculatorDescription.html
*/
class CCalculator : public CFiniteStateMachine
{
public:
    String expression;
    String errmessage;
    std::mystack<double> operands;
    std::mystack<OPTYPE> operators;
    CToken token;
    CToken lookaheadtoken;
    String line;
    double result;
    bool echo;
    CCalculator(String expr=L"")
    {
        setName(L"Calculator"); 
        line=expr;
        setupFSM();
        resetFSM();
    }
    ~CCalculator()
    {
        operands.clear();
        operators.clear();
    }
    
    /**
    * Get the next token from the line. If no token remaining, set end-mark as token.
    * Process token type as event. 
    * @return S_OK always.
    */
    
    CToken getNextToken()
    {
        CToken token;
        if(::getNextToken(line, token) >0) {
        }
        else token.type=L"end-mark";
        return token;
        
    }

    /**
    * Evaluates a operation as given by an OPTYPE op,  
    * and operands from the operand stack. 
    * Pops number of operands depending on operator type,
    * calculates, and pushes the result back on the operand stack.
    * @return 0 ok.
    * @return 1 couldn't find matching operation based on operator.
    */

    static int opEVAL(OPTYPE op, std::mystack<double> &operands)
    {
        if(optoken[op].operands==2) CLogging::Log.log("Evaluate Op %S  with %f and %f to give", (BSTR) optoken[op].op, operands.peek(0), operands.peek(1));
        if(optoken[op].operands==1) CLogging::Log.log("Evaluate Op %S  with %f to give", (BSTR) optoken[op].op, operands.peek(0));
        
        if(operands.size()< optoken[op].operands) return -1;
        // Do arithmetic 
        switch(op) {
            // Handle Binary Ops 
        case opNULL:   break;
        case opPLUS:  operands.push(operands.pop()+operands.pop()); break;
        case opMINUS: operands.push(-operands.pop()+operands.pop()); break;
        case opTIMES:  operands.push(operands.pop()*operands.pop()); break;
        case opDIVIDE: 
            { double a = operands.pop();
              double b= operands.pop();
              operands.push(b/a);
//              operands.swap(); operands.push(operands.pop()/operands.pop()); 
            }
            break;
        case opEQ: operands.push(operands.pop() == operands.pop()); break;
        case opNOT: operands.push(!(int) operands.pop()); break;
        case opNE: operands.push(operands.pop() != operands.pop()); break;
        case opLT: operands.push(operands.pop()>=operands.pop()); break;
        case opLE: operands.push(operands.pop()>operands.pop()); break;
        case opGT: operands.push(operands.pop()<=operands.pop()); break;
        case opGE: operands.push(operands.pop()<operands.pop()); break;
        case opAND: operands.push(operands.pop() && operands.pop()); break;
        case opOR: operands.push(operands.pop() || operands.pop()); break;
            //    case opPOWER: c=(int) pow((double) a , (double) b); break;
        case opASIN: 
            operands.push(asin(operands.pop()));             break;
        case opATAN:
            operands.push(atan(operands.pop()));             break;
        case opCOS:
            operands.push(cos(operands.pop()));             break;
        case opEXP:
            operands.push(exp(operands.pop()));             break;
        case opLOG:
            operands.push(log(operands.pop()));             break;
        case opLOG10:
            operands.push(log10(operands.pop()));             break;
        case opSIN:
            operands.push(sin(operands.pop()));             break;
        case opSQRT:
            operands.push(sqrt(operands.pop()));             break;
        case opTAN:
            operands.push(tan(operands.pop()));             break;
        case opCOMMA: break;  // skip, should have count of operands
        default: 
            return 1;
        }
        CLogging::Log.log(" Result %f\n", operands.top());
        return 0;
    }
    /**
    * Stack number action.
    * If current token is of type operator, then push token.optype onto operators stack;
    * else raise internal fail event "Expecting Operator".
    * @return S_OK always. States handles errors.
    */    
    HRESULT stackNumber(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("stackNumber action\n");
        ::Sleep(5);
        if(token.type==L"number") operands.push(token.dvalue);
        else handleEvent(new CFSMFailedEvent("fail", "Expecting Number"));
        return S_OK;
    }
    
    /**
    * Condition to check if valid signed number, when expecting regular number/operand.
    * If current token is of type opPLUS or opMINUS, then determine sign, and 
    * do lookahead of next token. If next token type is of number, return true, otherwiswe false. 
    * If current token is not of type opPLUS or opMINUS, then return false.
    * @return true unary operator with number, false otherwise.
    */
    bool checkSignedNumber()
    {    
        bool truth;
        if((token.optype==opPLUS) || (token.optype==opMINUS)){
            int sign=0;
            if(token.optype==opPLUS) sign=1;
            if(token.optype==opMINUS) sign=-1;
            if(lookaheadtoken.type==L"number") truth= true;
            else truth=false;
        }
        else truth=false;

        CLogging::Log.log("checkSignedNumber condition = %s\n",( (truth)? "true" : "false"));
        return truth;
    }
    
    /**
    * Stack signed number, when expecting regular number/operand.
    * If current token is of type opPLUS or opMINUS, then determine sign, and 
    * do lookahead (cheating yes.) by getting next token. If type is of number, push
    * number on operands stack, else issue internal Fail event "Expecting number after sign".
    * If current token is not of type opPLUS or opMINUS, then issue internal Fail event  Illegal Operator".
    * @return S_OK always. States handles errors.
    */
    HRESULT stacksignednumber(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        // This will double check conditional guardian, 
        CLogging::Log.log("allowsignednumber action\n");
        if((token.optype==opPLUS) || (token.optype==opMINUS)){
            int sign=0;
            if(token.optype==opPLUS) sign=1;
            if(token.optype==opMINUS) sign=-1;
            if(sign==0) handleEvent(new CFSMFailedEvent("fail", "Internal Error Handling sign"));
            if(lookaheadtoken.type==L"number"){
                operands.push(sign*lookaheadtoken.dvalue);
                // This is the part that's a bit clunky.
                lookaheadtoken=getNextToken();
            }
            else handleEvent(new  CFSMFailedEvent("fail", "Expecting number after sign"));
        }
        else handleEvent(new CFSMFailedEvent("fail", "Illegal Operator"));
        return S_OK;
    }

    /**
    * Action to stack unary operator on operator stack.
    * If current token is not unary operator, issue internal Fail event "Expecting Unary Operator".
    * @return S_OK always. States handles errors.
    */
    HRESULT stackunaryoperator(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("allowunaryoperator action\n");
        if(optoken[token.optype].operands ==1) {
            operators.push(token.optype);
            return S_OK;
        }
        else handleEvent(new CFSMFailedEvent("fail", "Expecting Unary Operator"));
        return S_OK;
    }

    /**
    * Stack operator action.
    * If current token is of type operator, then push token.optype onto operators stack;
    * else raise internal fail event "Expecting Operator".
    * @return S_OK always. States handles errors.
    */
    HRESULT stackOperator(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("stackOperator action\n");
        if(token.type==L"operator") operators.push(token.optype);
        else handleEvent(new CFSMFailedEvent("fail", "Expecting Operator"));
        return S_OK;
    }
    

    /**
    * Stack left parenthesis action.
    * @return S_OK always. 
    */
    HRESULT stackLeftParen(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("stackLeftParen action\n");
        operators.push(token.optype);
        return S_OK;
    }

    /**
    * Dummy nop action.
    * @return S_OK always.
    */    
    HRESULT noOperation(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        return S_OK;
        
    }
    
    /**
    * Unstack operators that are of greater precedence than the current operator.
    * If the operator on the top is of greater rank than the current token operator,
    * evaluate the top of the operator stack.
    */
    HRESULT unstackGEOperator(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("unstackGEOperator action\n");
        if(operators.size()<1) return S_OK;
        if(optoken[operators.top()].rank > optoken[token.optype].rank){
            opEVAL(operators.pop(),operands);
        }
        ::Sleep(4);
        
        return S_OK;
    }
    /**
    * Unstack all operators on the operator stack. 
    * If operators evaluation is missing operand, raise internal fail event, "Missing Operaand".
    * @return S_OK always. State transitions handle failures.
    */    
    HRESULT unstackAllOperators(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("unstackAllOperators action\n");
        while((operators.size()>1 && optoken[operators.top()].rank > optoken[opENDMARK].rank) ) {
            if(opEVAL(operators.pop(),operands)<0){
                handleEvent(new CFSMFailedEvent("fail", "Missing Operaand"));
                break;
            }
        }
        ::Sleep(2);
        return S_OK;
    }
    

    /**
    * Terminate calculation. Should be opENDMARK on the operators stack. 
    * If proper ending, sets done flag to -1 so calculation loop ends.
    * Otherwise, the calculation failed, and issue internal failed event.
    * @return S_OK even when transition to fail state. 
    */
    HRESULT terminate(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("terminate action\n");
        if((operands.size()>1) && (operators.top()!=opENDMARK) ){
            handleEvent(new CFSMFailedEvent("fail", "Failed calculation"));
        }
        else {
            m_doneFlag=1;
            result=operands.pop();
        }
        return S_OK;
    }

    /**
    * Failure of some sort. If Event is of type CFSMFailedEvent then log error message.
    * Otherwise, specify non-specific error.
    * Sets done flag to -1.

    * @return S_OK error message logged. 
    */
    HRESULT fail(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("fail action\n");
        // Problems with using CRuntime and CObject
#if 0
        if(event->IsKindOf( RUNTIME_CLASS( CFSMFailedEvent ) ) ) // this is a bug if you don't use a pointer
//        CRuntimeClass* prt = event->GetRuntimeClass();
        //if(!strcmp( prt->m_lpszClassName, "CFSMFailedEvent" ) )
        {
            //if IsKindOf is true, then cast is all right
            CFSMFailedEvent * failedevent= (CFSMFailedEvent *) event;
            errmessage= failedevent->errmessage;
        }
        else {
            errmessage=L"Fail: Non Specific Reason";
        }
#endif
            errmessage=L"Fail: Non Specific Reason";
        m_doneFlag=-1;
        return S_OK;
    }

    /**
    * Failure of some signed number sort.
    * If current token is not of type opPLUS or opMINUS, then issue internal Fail event  Illegal Operator".
    * Else lookahead token  was not a number so issue internal Fail event "Expecting number after sign".    
    * Sets done flag to -1.
    * @return S_OK error message logged. 
    */
    HRESULT failedSignedNumber(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        CLogging::Log.log("failedSignedNumberr action\n");
        if(!((token.optype==opPLUS) || (token.optype==opMINUS)))
            errmessage=L"Failed: Illegal Operator";
        else 
            errmessage=L"Failed: Expecting number after sign";
        m_doneFlag=-1;;
        return S_OK;
    }

    /**
    * If top operator is left parenthesis, then unstack and evaluate operators.
    * Has kludge to check for unary operator such as fcn in fcn(x) before (
    * Obvious kludge as some  are fcn(x,y), to be handled later
    * If operators is not opLFPAREN then issue internal fail event because of  "Mismatched Parentheses".
    * @return S_OK even if failed. 
    */
    HRESULT unstackIfLeftParen(CFiniteStateMachine * fsm, CFSMEvent * event)
    {
        if(operators.top() == opLFPAREN){
            operators.pop();
            // Check for unary operator such as fcn in fcn(x) before (
            // Obvious kludge as some  are fcn(x,y), to be handled later
            if((operators.size()>1) && optoken[operators.top()].operands==1) {
                if(opEVAL(operators.pop(),operands)<0){
                    handleEvent(CFSMFailedEvent("fail", "Missing Operaand"));
                }
            }
        }
        else handleEvent(new CFSMFailedEvent("fail", "Mismatched Parentheses"));
        return S_OK;
        
    }

    
    /** 
    * Setup assigns event, actions, and state transition to all states in the calculator.
    */
    void setupFSM(){
        // As long as there is this within this list, can't save to file
        CFSMTransitionPtr transition;
        this->firstState= String("EXPECTING-OPERAND");
        
        transition=addTransition("EXPECTING-OPERAND",    "operator",    "EXPECTING-OPERATOR",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stacksignednumber, L"stacksignednumber"), 
            NULL);    
        transition->addCondition(new CFSMCondition(this,(FSMConditionFunction)  &CCalculator::checkSignedNumber, L"checkSignedNumber" ));

        transition=addTransition("EXPECTING-OPERAND",    "operator",    "EXPECTING-OPERATOR",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::failedSignedNumber, L"failedSignedNumber"), 
            NULL);    
        transition->addCondition(new CFSMCondition(this,(FSMConditionFunction)  &CCalculator::checkSignedNumber, L"NOT(checkSignedNumber)", true ));


        addTransition("EXPECTING-OPERAND",    "unaryoperator",    "EXPECTING-OPERAND",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stackunaryoperator, L"allowunaryoperator"), 
            NULL);    
        addTransition("EXPECTING-OPERAND",    "number",    "EXPECTING-OPERATOR",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stackNumber, L"stackNumber"),
            NULL);    
        addTransition("EXPECTING-OPERAND",    "left-paren",     "EXPECTING-OPERAND",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stackLeftParen, L"stackLeftParen"),
            NULL);    
        addTransition("EXPECTING-OPERAND",    "end-mark",  "TERMINATE-PROGRAM",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::terminate, L"terminate"),
            NULL);    
        addTransition("EXPECTING-OPERAND",    "fail",  "FAILED",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::fail, L"fail"),
            NULL);    
        
        // after stacking operand, expect an operator
        addTransition("EXPECTING-OPERATOR",    "operator",    "EXPECTING-OPERAND",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::unstackGEOperator,  L"unstackGEOperator"),
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stackOperator,  L"stackOperator"),
            NULL);    
        addTransition("EXPECTING-OPERATOR",    "number",    "FAILED",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::noOperation, L"noOperation"),
            NULL);    
        addTransition("EXPECTING-OPERATOR",    "right-paren",     "EXPECTING-OPERATOR",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::unstackAllOperators, L"unstackAllOperators"),
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::unstackIfLeftParen, L"unstackIfLeftParen"),
            NULL);    
        addTransition("EXPECTING-OPERATOR",    "end-mark",  "TERMINATE-PROGRAM",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::unstackAllOperators, L"unstackAllOperators"),
            NULL);    
        addTransition("EXPECTING-OPERATOR",    "fail",  "FAILED",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::fail, L"fail"),
            NULL);    
        
        addTransition("TERMINATE-PROGRAM",    "end-mark",  "TERMINATE-PROGRAM",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::terminate,  L"terminate"),
            NULL);    
        
        
        addTransition("TERMINATE-PROGRAM",    "fail",  "FAILED",  
            new CFSMAction(this, (FSMObjectFunction)  &CCalculator::fail,  L"fail"),
            NULL);    
        
        
    }

    /**
    * Reset calculator FSM and looping logic. 
    * Set looping doneFlag to false.
    * CFiniteStateMachine::resetFSM();
    * Clear operators stack, operands stack, and push opENDMARK onto operators stack.
    */
    HRESULT resetFSM()
    {
        m_doneFlag=false;
        CFiniteStateMachine::resetFSM();
        operators.clear();
        operands.clear();
        operators.push(opENDMARK);
        errmessage=L"";
        return S_OK;
    }
    
    /**
    * Calculate is the main function for the class. It accepts an expression, resets the logic,
    * and loops parsing and then transitioning the FSM to handle the token. 
    * @return result as a string. Error message if failed.
    */
    String calculate(String expression)
    {    
        String answer=L"";
        line=expression;
        resetFSM();
        lookaheadtoken=getNextToken();
        while(!isDone())
        {
            CLogging::Log.log("\n");
            CLogging::Log.log("Current State %S\n", (BSTR) getCurrentStateName());
            token=lookaheadtoken;
            lookaheadtoken=getNextToken();
            handleEvent((BSTR) token.type);
            CLogging::Log.log("Event = %S", (BSTR) token.type);
//            CLogging::Log.log("Token Type = %S, Test = %S", (BSTR) token.type, (BSTR) line);
            if(token.type==L"operator") CLogging::Log.log(" Token Value = %S\n", (BSTR) optoken[token.optype].op);
            else if(token.type==L"number") CLogging::Log.log("Token Value = %f\n", token.dvalue);
            else CLogging::Log.log("\n");

            updateFSM();
        }

        if(errmessage==L""){
            answer.Append("%f", result);
            return answer;
        }
        else  return errmessage;
    }
    
    
};

void testCalculator()
{
    String test=L"hello world 123 * 456E1";
    CToken token;
    /**
    while(getNextToken(test, token) >0) {
    CLogging::Log.log("Token Type = %S, Test = %S", (BSTR) token.type, (BSTR) test);
    if(token.type==L"token") CLogging::Log.log("Token Value = %S\n", (BSTR) token.value);
    else if(token.type==L"integer") CLogging::Log.log("Token Value = %d\n", token.ivalue);
    else if(token.type==L"double") CLogging::Log.log("Token Value = %f\n", token.dvalue);
    else CLogging::Log.log("\n");
    }
    */
    
    CCalculator * calc = new CCalculator(L"123 * 456E1");
    calc->IncRef();
    calc->debug=9;
    calc->echo=true;
    CLogging::Log.log(1, "\nBefore Testing Calculator Pointer Info\n%S", (BSTR) CFSMState::classInfo());

    CLogging::Log.log("Calculate -22*4=%S\n", (BSTR) calc->calculate(L"-22*4"));
    CLogging::Log.log("Calculate -*22+4=%S\n", (BSTR) calc->calculate(L"*22+4"));
    CLogging::Log.log("Calculate 2+2+4=%S\n", (BSTR) calc->calculate(L"2+2+4"));
    CLogging::Log.log("Calculate 1==1=%S\n", (BSTR) calc->calculate(L"1==1"));
    CLogging::Log.log("Calculate 0==1=%S\n", (BSTR) calc->calculate(L"0==1"));
    CLogging::Log.log("Calculate !(0==1)=%S\n", (BSTR) calc->calculate(L"!(0==1)"));
    CLogging::Log.log("Calculate (6-2)*5=%S\n", (BSTR) calc->calculate(L"(6-2)*5"));
    CLogging::Log.log("Calculate sqrt(2+2)+6=%S\n", (BSTR) calc->calculate(L"sqrt(2+2)+6"));

    CLogging::Log.log(1, "\n\nDone Testing, now release to avoid leaks");
    CLogging::Log.log(1, "\nDone Testing Calculator Pointer Info\n%S", (BSTR) CFSMState::classInfo());
    CLogging::Log.flush();
    String html=calc->toHTML();
    String timing=calc->timingToHTML();
    timing.SaveFile("calculatorTiming.html");
    html.SaveFile("calculator.html");
//    html.SaveFile("D:\\omac\\omacapi\\fsmlibnew\\doc\\calculatorFSM.html");
    calc->forceCurrentState("EXPECTING-OPERAND");
    CFSMEventPtr ptr;
    calc->processEvent(ptr=new CFSMFailedEvent("fail", "Missing Operand"));
    html=calc->toHTML(-1);
    html.SaveFile("failedCalculatorHTML.html");
    calc->releaseFSM();
    calc->DecRef();
}



class CMacroFSM : public CCalculator
{
public:
    /*
    BEGIN_STATE_MAP
        FIRST_STATE_MAP_ENTRY(EXPECTING-OPERAND)
        STATE_MAP_ENTRY(EXPECTING-OPERATOR)
        STATE_MAP_ENTRY(TERMINATE-PROGRAM)
        STATE_MAP_ENTRY(FAILED)
    END_STATE_MAP
    */    
    BEGIN_TRANSITION_MAP(CMacroFSM)
        TRANSITION_FIRST_STATE_ENTRY(EXPECTING-OPERAND)
        TRANSITION_ENTRY_WITH_ACTION(EXPECTING-OPERAND, operator, EXPECTING-OPERATOR,  new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stacksignednumber, L"stacksignednumber"))    

        TRANSITION_ENTRY_WITH_ACTION(EXPECTING-OPERAND, operator, EXPECTING-OPERATOR,  new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stacksignednumber, L"stacksignednumber"))    
        ADD_TRANSITION_CONDITION(this, CCalculator, checkSignedNumber)
        

        TRANSITION_ENTRY(EXPECTING-OPERAND, operator, EXPECTING-OPERATOR)
        ADD_TRANSITION_ACTION(this, CCalculator, failedSignedNumber)
        ADD_INVERTED_TRANSITION_CONDITION(this, CCalculator, checkSignedNumber) 

        TRANSITION_ENTRY_WITH_ACTION(EXPECTING-OPERAND, unaryoperator, EXPECTING-OPERAND,    new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stackunaryoperator, L"allowunaryoperator"))
        TRANSITION_ENTRY_WITH_ACTION(EXPECTING-OPERAND, number,        EXPECTING-OPERATOR, new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stackNumber, L"stackNumber"))    
        TRANSITION_ENTRY_WITH_ACTION(EXPECTING-OPERAND, left-paren,    EXPECTING-OPERAND, new CFSMAction(this, (FSMObjectFunction)  &CCalculator::stackLeftParen, L"stackLeftParen"))    
        TRANSITION_ENTRY_WITH_ACTION(EXPECTING-OPERAND, end-mark,      TERMINATE-PROGRAM,new CFSMAction(this, (FSMObjectFunction)  &CCalculator::terminate, L"terminate"))    
        TRANSITION_ENTRY(EXPECTING-OPERAND,    fail,  FAILED)
        ADD_TRANSITION_ACTION(this, CCalculator, fail)
        
        // after stacking operand, expect an operator
        TRANSITION_ENTRY(EXPECTING-OPERATOR,    operator,    EXPECTING-OPERAND)
        ADD_TRANSITION_ACTION(this, CCalculator, unstackGEOperator)
        ADD_TRANSITION_ACTION(this, CCalculator, stackOperator)

        TRANSITION_ENTRY(EXPECTING-OPERATOR,  number,  FAILED)
        ADD_TRANSITION_ACTION(this, CCalculator, noOperation)

        TRANSITION_ENTRY(EXPECTING-OPERATOR,  right-paren,  EXPECTING-OPERATOR)
        ADD_TRANSITION_ACTION(this, CCalculator, unstackAllOperators)
        ADD_TRANSITION_ACTION(this, CCalculator, unstackIfLeftParen)

        TRANSITION_ENTRY(EXPECTING-OPERATOR, end-mark,  TERMINATE-PROGRAM)
        ADD_TRANSITION_ACTION(this, CCalculator, unstackAllOperators)

        TRANSITION_ENTRY(EXPECTING-OPERATOR, fail,  FAILED)
        ADD_TRANSITION_ACTION(this, CCalculator,fail)
        
        TRANSITION_ENTRY_WITH_ACTION(TERMINATE-PROGRAM, end-mark, TERMINATE-PROGRAM,  new CFSMAction(this, (FSMObjectFunction)  &CCalculator::terminate,  L"terminate"))        
        
        TRANSITION_ENTRY_WITH_ACTION(TERMINATE-PROGRAM, fail,  FAILED,  new CFSMAction(this, (FSMObjectFunction)  &CCalculator::fail,  L"fail"))    

        END_TRANSITION_MAP
        
        

};

void macroTest()
{

    /*
    CMacroFSM macrofsm;
    CFSMStatePtr * states = macrofsm.getFSMStates();
    CLogging::Log.log("MACRO STATES DUMP\n");
    for(int i=0; states[i]!=NULL; i++) {
        CLogging::Log.log("State[%d]=%S\n", i, (BSTR) states[i]->getName());
        states[i]=NULL;
    }
*/
    CMacroFSM  calc;
    calc.IncRef();
    calc.debug=9;
    calc.echo=true;
    CLogging::Log.log("Calculate (120*4)/(6*5)=%S\n", (BSTR) calc.calculate(L"(120*4)/(6*5)"));
    calc.releaseFSM();
}