//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <alloc.h>
#include "Unit1.h"
#include "CioinaComplexEval.hpp"
#include "math.h"
#include "math.hpp"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TCioinaComplexEval *ev,*ev1;
DynamicArray<TUserVarRec> a;
Variant *P1,*P2;
//---------------------------------------------------------------------------
int _matherr (struct _exception *a)
{
 if (a->type == DOMAIN)
 {
   throw EInvalidArgument("");
  }
 if (a->type == SING)
 {
   throw EInvalidOp("");
  }
 if (a->type == OVERFLOW)
 {
   throw EOverflow("");
  }
 if (a->type == UNDERFLOW)
 {
   throw EUnderflow("");
  }
 if (a->type == TLOSS)
 {
   throw Exception("TLOSS");
  }
 return 0;
}
//---------------------------------------------------------------------------

Variant __fastcall MyE(PVectorPVariant Pv,int PvCount)
{
 return exp(1);
}
//---------------------------------------------------------------------------

Variant __fastcall MySqrt(PVectorPVariant Pv,int PvCount)
{
 return sqrt(*Pv[0]);
}
//---------------------------------------------------------------------------

Variant __fastcall MySum(PVectorPVariant Pv,int PvCount)
{
Variant s; int i;
 for(s=0,i=0;i<PvCount;i++)s+=*Pv[i];
 return s;
}
//---------------------------------------------------------------------------

Variant __fastcall MyRandom(PVectorPVariant Pv,int PvCount)
{
 return rand();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ParsingError(TObject *Sender)
{
 AnsiString  s,s1;
 int i;
 TCioinaComplexEval *Test = dynamic_cast<TCioinaComplexEval*>(Sender);
 if(Test)
 {
  i=AnsiPos(':',Test->ErrorMessageInfo)+1;
  if(i>1) s1=" : ";else s1="";
  for (;i<=Test->ErrorMessageInfo.Length();i++)s1+=Test->ErrorMessageInfo[i];
  s="";
  switch ( Test->MathException ){
  case EX_NONMATH:s=" : NONMATH";break;
  case EX_Overflow:s=" : Overflow";break;
  case EX_Underflow:s=" : Underflow";break;
  case EX_InvalidArgument:s=" : InvalidArgument";break;
  case EX_ZeroDivide:s=" : ZeroDivide";break;
  case EX_InvalidOp:s=" : InvalidOp";break;
  }

  switch (Test->ErrorNumber){
   case ERR_PARSE:                                   Memo2->Text=("Invalid expression"+s1);break;
   case ERR_BAD_SYNTAX:                              Memo2->Text=("Syntax error"+s1);break;
   case ERR_COMMA_SYNTAX:                            Memo2->Text=("Comma syntax error"+s1);break;
   case ERR_NO_MATH_EXPRESSION_WAS_PARSED:           Memo2->Text=("No math expression was parsed");break;
   case ERR_PARANTHESES_SYNTAX_ERROR:                Memo2->Text=("Mismatched parenthesis");break;
   case ERR_INVALID_DERIVATIVE_VARIABLE_NAME:        Memo2->Text=("Invalid name of derivative variable"+s1);break;
   case ERR_MATH_EXPRESSION_IS_EMPTY:                Memo2->Text=("Mathematical expression is empty");break;
   case ERR_IDENTIFIER_CANNOT_BE_EMPTY:              Memo2->Text=("Identifier cannot be empty");break;
   case ERR_IDENTIFIER_LENGTH:                       Memo2->Text=("Identifier length is too long"+s1);break;
   case ERR_NOT_PASCAL_IDENTIFIER:                   Memo2->Text=("Invalid identifier"+s1);break;
   case ERR_IDENTIFIER_CANNOT_BE_RESERVED_NAME:      Memo2->Text=("Identifier cannot be a reserved name"+s1);break;
   case ERR_IDENTIFIER_ALREADY_EXISTS:               Memo2->Text=("Identifier already exists"+s1);break;
   case ERR_DUBLICATING_USER_IDENTIFIER:             Memo2->Text=("Dublicating user identifier"+s1);break;
   case ERR_UNKNOWN_EXPRESSION:                      Memo2->Text=("Unknown expression"+s1);break;
   case ERR_UNKNOWN_FUNCTION:                        Memo2->Text=("Undefined function"+s1);break;
   case ERR_UNKNOWN_VARIABLE:                        Memo2->Text=("Undefined variable"+s1);break;
   case ERR_BAD_EXPONENTIAL_FORMAT:                  Memo2->Text=("Invalid exponent value"+s1);break;
   case ERR_SET_OriginalMathExpressionString_FALSE:  Memo2->Text=("Set ''OriginalMathExpressionString'' to FALSE for differentiation or for Mathematica 4.1 export");break;
   case ERR_MATH_EXPRESSION_WAS_ERASED:              Memo2->Text=("Mathematical expression string was erased");break;
   case ERR_USE_VerifySyntaxSemanticsAndDerivation:  Memo2->Text=("Use ''VerifySyntaxSemanticsAndDerivation'' for differentiation");break;
   case ERR_DERIVATIVE_EXPRESSION_WAS_ERASED:        Memo2->Text=("Derivative expression string was erased");break;
   case ERR_VARIABLES_AND_VALUES_ARE_DIFFERENT:      Memo2->Text=("Variable count and value caunt do not corespond");break;
   case ERR_MATH_EXPRESSIONS_ARRAY:                  Memo2->Text=("Use ''DoVectorOfMathExpressions'' for calculate a vector of math expression");break;
   case ERR_FUNCTION_NUMBER_MUST_BE_LESS:            Memo2->Text=("Function number must be less"+s1);break;
   case ERR_FUNCTION_ADDRESS_CANNOT_BE_NIL:          Memo2->Text=("Function address cannot be nil"+s1);break;
   case ERR_PROTECTED_EXPRESSION:                    Memo2->Text=("Cannot set value for protected expression"+s1);break;
   case ERR_DEF_FUNC_NAME:                           Memo2->Text=("Invalid function name"+s1);break;
   case ERR_DEF_FUNC_DUBLICATING:                    Memo2->Text=("Dublicating defined function"+s1);break;
   case ERR_DEF_FUNC_IMPLEMENTING:                   Memo2->Text=("Defined function was not implimented"+s1);break;
   case ERR_DEF_FUNC_ARG_COUNT:                      Memo2->Text=("Invalid arguments number for defined function"+s1);break;
   case ERR_DEF_FUNC_ARG_NAME:                       Memo2->Text=("Invalid argument name for defined function"+s1);break;
   case ERR_DEF_FUNC_ARG_DUBLICATING:                Memo2->Text=("Dublicating argument name for defined function"+s1);break;
   case ERR_MULTIPLY:                                Memo2->Text=("Invalid value for *"+s1+s);break;
   case ERR_DIVISION:                                if (Test->MathException==EX_ZeroDivide) Memo2->Text=("Division by 0 ");
                                                     else Memo2->Text=("Invalid value for /"+s1+s);break;
   case ERR_PLUS:                                    Memo2->Text=("Invalid value for +"+s1+s);break;
   case ERR_MINUS:                                   Memo2->Text=("Invalid value for -"+s1+s);break;
   case ERR_POWER:                                   Memo2->Text=("Invalid value for ^"+s1+s);break;
   case ERR_EQUAL:                                   Memo2->Text=("Invalid value for ="+s1+s);break;

  default: if(Test->ErrorNumber>=1 && Test->ErrorNumber<=FunCount)
           {
             if(s=="")Memo2->Text=("Invalid number of function arguments for: "+ UpperCase(aStr[Test->ErrorNumber-1]));
             else Memo2->Text=("Invalid value for "+ UpperCase(aStr[Test->ErrorNumber-1])+s1+s);
            }
            else
              if (Test->ErrorNumber>FunCount)
              {
               if(s=="")Memo2->Text=("Invalid number of function arguments for: "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1]));
               else Memo2->Text=("Invalid value for "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1])+s1+s);
              }
              else Memo2->Text=(Test->ErrorMessageInfo);
  }
 }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::DoMathExpressError(TObject *Sender)
{
 AnsiString  s,s1;
 int i;
 TCioinaComplexEval *Test = dynamic_cast<TCioinaComplexEval*>(Sender);
 if(Test)
 {
  i=AnsiPos(':',Test->ErrorMessageInfo)+1;
  if(i>1) s1=" : ";else s1="";
  for (;i<=Test->ErrorMessageInfo.Length();i++)s1+=Test->ErrorMessageInfo[i];
  s="";
  switch ( Test->MathException ){
  case EX_NONMATH:s=" : NONMATH";break;
  case EX_Overflow:s=" : Overflow";break;
  case EX_Underflow:s=" : Underflow";break;
  case EX_InvalidArgument:s=" : InvalidArgument";break;
  case EX_ZeroDivide:s=" : ZeroDivide";break;
  case EX_InvalidOp:s=" : InvalidOp";break;
  }

  switch (Test->ErrorNumber){
   case ERR_NO_MATH_EXPRESSION_WAS_PARSED:           Memo2->Text=("No math expression was parsed");break;
   case ERR_VARIABLES_AND_VALUES_ARE_DIFFERENT:      Memo2->Text=("Variable count and value caunt do not corespond");break;
   case ERR_MATH_EXPRESSIONS_ARRAY:                  Memo2->Text=("Use ''DoVectorOfMathExpressions'' for calculate a vector of math expression");break;
   case ERR_EXECUTE:                                 Memo2->Text=("Execution error "+s1);break;
   case ERR_DEF_FUNCTION_STACK_OVERFLOW:             Memo2->Text=("Stack overflow"+s1);break;
   case ERR_SYSTEM_STACK_OVERFLOW:                   Memo2->Text=("Fatal error"+s1);break;
   case ERR_MULTIPLY:                                Memo2->Text=("Invalid value for *"+s1+s);break;
   case ERR_DIVISION:                                if (Test->MathException==EX_ZeroDivide) Memo2->Text=("Division by 0 ");
                                                     else Memo2->Text=("Invalid value for /"+s1+s);break;
   case ERR_PLUS:                                    Memo2->Text=("Invalid value for +"+s1+s);break;
   case ERR_MINUS:                                   Memo2->Text=("Invalid value for -"+s1+s);break;
   case ERR_POWER:                                   Memo2->Text=("Invalid value for ^"+s1+s);break;
   case ERR_EQUAL:                                   Memo2->Text=("Invalid value for ="+s1+s);break;
   default: if(Test->ErrorNumber>=1 && Test->ErrorNumber<=FunCount)
            {
             if(s=="")Memo2->Text=("Invalid number of function arguments for: "+ UpperCase(aStr[Test->ErrorNumber-1]));
             else Memo2->Text=("Invalid value for "+ UpperCase(aStr[Test->ErrorNumber-1])+s1+s);
            }
            else
              if (Test->ErrorNumber>FunCount)
              {
               if(s=="")Memo2->Text=("Invalid number of function arguments for: "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1]));
               else Memo2->Text=("Invalid value for "+ UpperCase(Test->UserFunctionName[Test->ErrorNumber-FunCount-1])+s1+s);
              }
              else Memo2->Text=(Test->ErrorMessageInfo);
  }
 }
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{

}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
 DecimalSeparator='.';
 DynamicArray<TUserFuncRec> ar;
 ar.Length=4;
 ar[0].FuncName="MyE";    ar[0].FuncAddress=MyE;    ar[0].VarCount=0;
 ar[1].FuncName="MySum";  ar[1].FuncAddress=MySum;  ar[1].VarCount=MaxFuncParam;
 ar[2].FuncName="MySqrt"; ar[2].FuncAddress=MySqrt; ar[2].VarCount=1;
 ar[3].FuncName="MyRandom"; ar[3].FuncAddress=MyRandom; ar[3].VarCount=-1;
 ev= new TCioinaComplexEval(ar);
 ev->OnVerifySyntaxSemanticsError=ParsingError;
 ev->OnDoMathExpressionError=DoMathExpressError;
 ev1= new TCioinaComplexEval(ar);
 ev1->OnVerifySyntaxSemanticsError=ParsingError;
 ev1->OnDoMathExpressionError=DoMathExpressError;
 ar.Length=0;
 P1= new(Variant);
 P2= new(Variant);
 a.Length=2;
 a[0].StrExpr='x';  a[0].Value=P1;
 a[1].StrExpr='y';  a[1].Value=P2;
 Edit1Change(this);
 Edit2Change(this);
 Memo1Change(this);
 Form1->Caption=ev->VersionInfo(NULL)+"    "+ev->OwnerInfo(NULL);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
 ev->FreeInstance();
 ev1->FreeInstance();
 delete(P1);
 delete(P2);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Memo1Change(TObject *Sender)
{
 TReplaceFlags flag;
 AnsiString s;
 Label4->Caption="Math Expression :";
 Label3->Caption="Result";
 Memo2->Clear();
 s=StringReplace(Trim(Memo1->Text),"\r\n",Edit1->Text,flag);
 ev->VerifySyntaxSemantics(s,a,false);
 if (!(ev->ErrorFlag))
 {
  Label4->Caption="Math Expression : OK";
  Label3->Caption="Result = "+VariantToStr(ev->DoMathExpression());
 }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::CheckBox1Click(TObject *Sender)
{
 if (CheckBox1->Checked)
 {
  CheckBox1->Caption="Space like multiply operator (true)";
  ev->SpaceLikeMultiply=true;
  ev1->SpaceLikeMultiply=true;
  Edit1Change(this);
  Edit2Change(this);
  Memo1Change(this);
 }else
 {
  CheckBox1->Caption="Space like multiply operator (false)";
  ev->SpaceLikeMultiply=false;
  ev1->SpaceLikeMultiply=false;
  Edit1Change(this);
  Edit2Change(this);
  Memo1Change(this);
 }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit1Change(TObject *Sender)
{
  Memo2->Text="";
  ev1->VerifySyntaxSemantics(Edit1->Text);
  if (ev1->ErrorFlag)
  {
   *P1=VarAsType(0,varNull);
   Label5->Caption=VariantToStr(*P1);
   Label3->Caption="Result";
  }else
   {
    *P1=ev1->DoMathExpression();
    Label5->Caption=VariantToStr(*P1);
    Label3->Caption="Result = "+VariantToStr(ev->DoMathExpression());
   };
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Edit2Change(TObject *Sender)
{
  Memo2->Text="";
  ev1->VerifySyntaxSemantics(Edit2->Text);
  if (ev1->ErrorFlag)
  {
   *P2=VarAsType(0,varNull);
   Label6->Caption=VariantToStr(*P2);
   Label3->Caption="Result";
  }else
   {
    *P2=ev1->DoMathExpression();
    Label6->Caption=VariantToStr(*P2);
    Label3->Caption="Result = "+VariantToStr(ev->DoMathExpression());
   };
}
//---------------------------------------------------------------------------

