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

#include <vcl.h>
#pragma hdrstop

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

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TCioinaEval *ev;
//---------------------------------------------------------------------------
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;
}
//---------------------------------------------------------------------------

long double __fastcall MyE(PVectorPTReal Pv,int PvCount)
{
 return exp(1);
}
//---------------------------------------------------------------------------

long double __fastcall MySqrt(PVectorPTReal Pv,int PvCount)
{
 return sqrt(*Pv[0]);
}
//---------------------------------------------------------------------------

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

void __fastcall TForm1::ParsingError(TObject *Sender)
{
 AnsiString  s,s1;
 int i;
 TCioinaEval *Test = dynamic_cast<TCioinaEval*>(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;
 TCioinaEval *Test = dynamic_cast<TCioinaEval*>(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");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::Button1Click(TObject *Sender)
{
 TReplaceFlags flag;
 AnsiString s;

 Memo2->Clear();
 flag<<rfReplaceAll;
 s=StringReplace(Trim(Memo1->Text),"\r\n",Edit1->Text,flag);
 ev->VerifySyntaxSemanticsAndDerivation(s,"",Edit1->Text,true);
 if (!(ev->ErrorFlag)) Memo2->Text=ev->DerivativeExpressionString;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
 DecimalSeparator='.';
 DynamicArray<TUserFuncRec> ar;
 ar.Length=3;
 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;
 ev= new TCioinaEval(ar);
 ev->OnVerifySyntaxSemanticsError=ParsingError;
 ev->OnDoMathExpressionError=DoMathExpressError;
 ar.Length=0;
 Form1->Caption="Differentiate "+ev->OwnerInfo(NULL);
}
//---------------------------------------------------------------------------

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



