#include "sopnamsp.h"
#include "machdefs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include "sophyainit.h"
#include "timing.h"
#include "cexpre.h"
#include "rpneval.h"
#include "commander.h"

/* -------------- Programme test de SOPHYA   tcmd.cc  
   Test des classes Timer , CExpressionEvaluator , 
   RPNExpressionEvaluator , Commander  , 
   csh> tcmd commander
   csh> tcmd cexptst
   csh> tcmd rpntst
   csh  tcmd timer
   ------ R. Ansari ---- 2003-2007    --------------- */

class TCmdExecutor : public CmdExecutor {
public:
  TCmdExecutor(Commander& cmd);
  virtual ~TCmdExecutor() { }

  virtual int Execute(string& keyw,vector<string>& args, string& toks);
};

TCmdExecutor::TCmdExecutor(Commander& cmd)
{ 
string hgrp = "TCmdExecutor";
string usage,kw;

kw = "ls";
usage = "ls: Execute /usr/bin/ls \n";
cmd.RegisterCommand(kw, usage, this, hgrp);
kw = "mv";
usage = "mv: Execute /usr/bin/mv \n";
cmd.RegisterCommand(kw, usage, this, hgrp);
kw = "cp";
usage = "cp: Execute /usr/bin/cp \n";
cmd.RegisterCommand(kw, usage, this, hgrp);
}

int TCmdExecutor::Execute(string& kw, vector<string>& args, string& toks)
{
  if ((kw!="ls")&&(kw!="mv")&&(kw!="cp"))  return 99; 
  string cmd;
  if (kw == "ls")     cmd = "/usr/bin/ls " ; 
  else if (kw == "mv") cmd = "/usr/bin/mv " ;
  else if (kw == "cp") cmd = "/usr/bin/cp " ;
  else cmd = "/usr/bin/echo " ;
  for(int kk=0; kk<args.size(); kk++)  { cmd += args[kk]; cmd += ' '; }
  cout << "TCmdExecutor::Execute() : Executing " << cmd << endl;
  return system(cmd.c_str());
}

int  InputLoop(Commander & cmd);
int tst_cexpreval();  // Test de CExpressionEvaluator 
int tst_rpneval();    // Test de RPNEvaluator 
int tst_timer();      // Test de Timer

/* --Main-- */
int main(int narg, char *arg[])
{

  if (narg < 2) {
    cout << " Usage: tcmd S=commander/cexptst/rpntst/timer \n" 
	 << "  S= commander: Commader class test \n"
	 << "  S= cexptst: CExpressionEvaluator class test \n"
	 << "  S= rpntst: RPNExpressionEvaluator class test \n"
	 << "  S= timer: Timer class test \n" << endl;
    return 0;
  }
  string opt = arg[1];
  SophyaInit();
  InitTim();
  int rc = 0;
  cout << " ---- tcmd S= " << opt << " (commander/evaluator test) " << endl;
  try {
    if (opt == "commander") {
      Commander cmd;
      TCmdExecutor cmdex(cmd);
      InputLoop(cmd);
    }
    else if (opt == "cexptst") rc = tst_cexpreval();
    else if (opt == "rpntst")   rc = tst_rpneval();
    else if (opt == "timer")   rc = tst_timer();
    else {
      cout << " tcmd/error: Unknown select option: " << opt << endl;
      rc = 9;
    }
  }
 
  catch (PThrowable & exc) {
    cerr << " Catched Exception " << (string)typeid(exc).name()
         << " - Msg= " << exc.Msg() << endl;
  }
  catch (std::exception & e) {
    cerr << " exception catched : e.what()= " << e.what() << endl;
  }
  catch (...) {
    cerr << " some other exception was caught ! " << endl;
  }

  PrtTim(" End of tcmd ");
  PrtTim("--Fin tcmd ");
  return(rc);
}

/* --Fonction-- */
int  InputLoop(Commander & cmd)
{
  cout << " ====================================================== " << endl;
  cout << " ==============   Test of Commander class  ============ " << endl;
  cout << " ====================================================== " << endl;
  cout << " tcmd/InputLoop() : Type in your commands, \n" 
       << "     end with a blanck line OR <Cntl>D " << endl;
  int line = 0;
  bool fg = true;
  char buff[1024];
  char * ret;
  while (fg) {
    printf("%d-%s ", line+1, cmd.GetCurrentPrompt().c_str());
    fflush(stdout);
    buff[0] = '\0';
    ret = fgets(buff, 1024, stdin);
    buff[1023] = '\0';
    if (ret && ( (buff[0] != '\0') && (buff[0] != '\n') && (buff[0] != '\r')) ) { 
      buff[strlen(buff)-1] = '\0';
      string cline = buff;
      cmd.Interpret(cline);
      line++;
    }
    else fg = false;
  }
  cout << " \n Total " << line << " lines from stdin -> Commander " << endl;
  if (line > 0) return(0);
  else return(1);
}

/* -- Fonction Test de CExpressionEvaluator -- */
int tst_cexpreval()
{
  double res;
  int nok=0;
  int nerr=0;
  int nerrparse=0;
  int num = 0;
  cout << " ====================================================== " << endl;
  cout << " ============   Test of CExpressionEvaluator ========== " << endl;
  cout << " ====================================================== " << endl;
  try {
    try {
      num++;
      CExpressionEvaluator cex("4.e-1");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? " << ( res=4.e-1 ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      } 
      else nok++;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

    try {
      num++;
      CExpressionEvaluator cex("4*3+8");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? 4*3+8 = " << ( res=4*3+8 ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      } 
      else nok++;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

    try {
      num++;
      CExpressionEvaluator cex("cos(0)+2");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? cos(0)+2 = " << ( res=cos(0.)+2 ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      }
      else nok++;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;


    try {
      num++;
      CExpressionEvaluator cex("4+3*8");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? 4+3*8 = " << ( res=4+3*8 ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      }
      else nok++;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;


    try {
      num++;
      CExpressionEvaluator cex("4+3*6*2");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? 4+3*6*2 = " << ( res=4+3*6*2 ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      }
      else nok++;
    }

    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

    try {
      num++;
      CExpressionEvaluator cex("(12+3*6*cos(0))");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? (12+3*6*cos(0))  = " 
	   << ( res=(12+3*6*cos(0.)) ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      }
      else nok++;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

    try {
      num++;    
      CExpressionEvaluator cex("(12+3*6*cos(0))-(5*pow(2,2))");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? (12+3*6*cos(0))-(5*pow(2,2))  = " 
	   << ( res=(12+3*6*cos(0.))-(5*pow(2.,2.)) ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      }
      else nok++;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

    try {
      num++;    
      CExpressionEvaluator cex("sin(Pi/6)+E");
      cout << "CExpr=sin(Pi/6)+E " << cex; 
      cout << " -> cex.Value() = " << cex.Value() << " =? sin(M_PI/6)+M_E  = " 
	   << ( res=sin(M_PI/6)+M_E ) << endl;
      if (fabs(cex.Value()-res) > 1.e-9) {
	cout << " ERREUR CALCUL " << cex << endl;
	nerr++;
      }
      else nok++;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

    // Expression avec erreur de syntaxe 
   cout << " >>>>> Expression avec erreur <<<<<< " << endl;
   try {
      num++;    
      CExpressionEvaluator cex("6**8");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << endl;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

   try {
      num++;    
      CExpressionEvaluator cex("6*(8+4");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << endl;
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;


   try {
      num++;    
      CExpressionEvaluator cex("6*sin(4,)+12");
      cout << "CExpr=" << cex; 
      cout << " -> cex.Value() = " << cex.Value() << endl; 
    }
    catch (CExprException& err) {
      nerrparse++;
      cout << "Exp[" << num << "]  Exception: " << err.Msg() << endl; 
    }
    cout << "  [" << num << "] CExprBase::NbCreate() = " << CExprBase::NbCreate() 
	 << "CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;

  }
  catch (CExprException& err) {
    cout << " Exception: " << err.Msg() << endl; 
  }

  cout << "-------- CExprBase::NbCreate() = " << CExprBase::NbCreate() << " CExprBase::NbDelete()=" <<  CExprBase::NbDelete() << endl;
  cout << "--- NExpr= " << num << " NOk= " <<  nok << " NErr=" << nerr << " NErrParse=" << nerrparse << endl;
  if ( (nok == 8) && (nerr == 0) && (nerrparse == 3) ) return 0;
  else return 99;
}

/* -- Fonction Test de CExpressionEvaluator -- */
int tst_rpneval()
{
  int num = 0;
  cout << " ====================================================== " << endl;
  cout << " ============ Test of RPNExpressionEvaluator ========== " << endl;
  cout << " ====================================================== " << endl;
  try {
    { 
      num++;
      RPNExpressionEvaluator rpn("4 2 print + 3 * ");
      cout << "4 2 + 3 * -> rpn.Value() = " << rpn.Value() << endl;
    }
    {
      num++;
      RPNExpressionEvaluator rpn("1 2 3 4 5 sum");
      cout << "1 2 3 4 5 sum -> rpn.Value() = " << rpn.Value() << endl;
    }
    {
      num++;
      RPNExpressionEvaluator rpn("4 3 pow");
      cout << "4 3 pow -> rpn.Value() = " << rpn.Value() << endl;
    }
  }
  catch (RPNExprException& err) {
    cout << "RPNExp[" << num << "]  Exception: " << err.Msg() << endl; 
  }

  return 0;
}

/* --Fonction-- */
int  tst_timer() 
{
  TIMEF ;
  cout << "**** tcmd.cc : Test class SOPHYA::Timer() **** " << endl;
  Timer tm("tcmd::Timer", false);

  int N = 10000000;
  double * x = new double[N];
  for(int k=0; k<N; k++) x[k] = k*0.0001;
  for(int k=0; k<N; k++) x[k] = sin(x[k]);
  for(int k=0; k<N; k++) x[k] = cos(x[k]);
  tm.Split();
  cout << " Step1: PARTIAL CPU(s)=" << tm.PartialCPUTime() 
       << " Elapsed (s)= " << tm.PartialElapsedTime()
       << " Elapsed (ms)= " << tm.PartialElapsedTimems() << endl;
  cout << " Step1: TOTAL CPU(s)=" << tm.TotalCPUTime() 
       << "  Elapsed (s)= " << tm.TotalElapsedTime() 
       << "  Elapsed (ms)= " << tm.TotalElapsedTimems() << endl;

  for(int k=0; k<N; k++) x[k] *= 8.5; 
  for(int k=0; k<N; k++) x[k] = tan(x[k]);

  tm.Split();
  cout << " Step2: PARTIAL CPU(s)=" << tm.PartialCPUTime() 
       << " Elapsed (s)= " << tm.PartialElapsedTime()
       << " Elapsed (ms)= " << tm.PartialElapsedTimems() << endl;
  cout << " Step2: TOTAL CPU(s)=" << tm.TotalCPUTime() 
       << "  Elapsed (s)= " << tm.TotalElapsedTime() 
       << "  Elapsed (ms)= " << tm.TotalElapsedTimems() << endl;

  for(int k=0; k<N; k++) x[k] = sin(x[k]);
  for(int k=0; k<N; k++) x[k] = cos(x[k]);
  for(int k=0; k<N; k++) x[k] *= 15.5; 
  for(int k=0; k<N; k++) x[k] = sin(x[k]);

  tm.Split();
  cout << " Step3: PARTIAL CPU(s)=" << tm.PartialCPUTime() 
       << " Elapsed (s)= " << tm.PartialElapsedTime()
       << " Elapsed (ms)= " << tm.PartialElapsedTimems() << endl;
  cout << " Step3: TOTAL CPU(s)=" << tm.TotalCPUTime() 
       << "  Elapsed (s)= " << tm.TotalElapsedTime() 
       << "  Elapsed (ms)= " << tm.TotalElapsedTimems() << endl;

  tm.Split("CheckPrintFmt", true);
  cout << " Waiting 70 sec (sleep(70)) ... " << endl; 
  sleep(100);
  tm.Split("CheckPrintFmt-AfterWait", true);
 
  cout << " Doing delete[] x, sleep(5) ... " << endl;  
  delete[] x;
  sleep(5);
}

