#include <time.h>

#include <relapp.h>
#include <urldefid.h>

///////////////////////////////////////////////////////////

class TTab_application : public TRelation_application
{
  TMask* _msk;
  TRelation* _rel;
  
protected:
  virtual TMask* get_mask(int mode);
  virtual TRelation* get_relation() const;
  virtual bool changing_mask(int mode);
  virtual bool user_create();
  virtual bool user_destroy();

public:
  TTab_application();
  virtual ~TTab_application();
};

// @cmember Costruttore
TTab_application::TTab_application() 
                : _msk(NULL), _rel(NULL) 
{ }

// @cmember Distruttore
TTab_application::~TTab_application() 
{ }

// @cmember Indica se la futura <mf TTab_application::get_mask> ritornera' una maschera diversa
//        dalla corrente.
bool TTab_application::changing_mask(int mode) 
{ return FALSE; }

// @cmember Richiede la maschera da usare
TMask* TTab_application::get_mask(int mode) 
{ 
  CHECK(_msk, "Null mask");
  return _msk; 
}

// @cmember Ritorna la relazione da modificare
TRelation* TTab_application::get_relation() const 
{ 
  CHECK(_rel, "Null relation");
  return _rel; 
}


bool TTab_application::user_create()
{
  if (argc() < 3) 
    return FALSE;
  
  TString16 tabname = argv(2);
  tabname.upper();
  _rel = new TRelation(tabname);

  TString16 t(tabname);
  if (t[0] == '%') t.ltrim(1);
  TString16 m; m << "BATB" << t;
  _msk = new TMask(m) ;
  
  TString80 tit = _msk->get_caption();
  set_title(tit);
  
  return TRUE;
}

bool TTab_application::user_destroy() 
{
  if (_msk) delete _msk;
  if (_rel) delete _rel;
  return TRUE;
}



///////////////////////////////////////////////////////////
// Test Relapp
///////////////////////////////////////////////////////////

class TTestrel_application : public TRelation_application
{
  const char* _maskname;
  const char* _num;

  TRelation* _rel;
  TMask* _msk;

protected:
  virtual bool user_create();
  virtual bool user_destroy();
  virtual TMask* get_mask(int) { return _msk; }
  virtual bool changing_mask(int) { return FALSE;}
  virtual TRelation* get_relation() const { return _rel; }
  virtual int read(TMask& m) { m.autoload(*_rel); return NOERR; }
  virtual int write(const TMask&) { return NOERR; }
  virtual int rewrite(const TMask&) { return NOERR; }

public:
  TTestrel_application(const char* name, const char* num);
};

TTestrel_application::TTestrel_application(const char* name, const char* num)
: _maskname(name), _num(num),
  _msk(NULL), _rel(NULL)
{}


bool TTestrel_application::user_create()
{
  const int id = atoi(_num);
  if (id > 0) _rel = new TRelation(id);
  else _rel = new TRelation(_num);

  _msk = new TMask(_maskname);

  return TRUE;
}

bool TTestrel_application::user_destroy()
{
  delete _msk;
  delete _rel;
  return TRUE;
} 

///////////////////////////////////////////////////////////
// Testmask
///////////////////////////////////////////////////////////

class TTest_application : public TApplication
{
  TFilename _maskname;

protected:
  bool create() { dispatch_e_menu(BAR_ITEM(1)); return TRUE; }
  bool destroy() { return TRUE; }
  bool menu(MENU_TAG);

public:
  TTest_application(const char* name) : _maskname(name) {}
};

bool TTest_application::menu(MENU_TAG)
{ 
  TMask m(_maskname);
  KEY k = m.run();
  if (k == K_QUIT) stop_run();

  return k != K_QUIT;
}

///////////////////////////////////////////////////////////

class TBenchmark_application : public TApplication
{          
  clock_t _timer_start;
  
protected:
  virtual bool create();
  virtual bool destroy();
  virtual bool menu(MENU_TAG);
  
  void initializing();
  void start_test(const char* msg);
  void update_bar(long rec);
  void stop_test();
  
  void test_relation_scan();
  void test_cursor_scan();
  void test_file_scan();
  void test_file_random();

public:
  TBenchmark_application() { } 
  virtual ~TBenchmark_application() { }
};

bool TBenchmark_application::create()
{                               
  dispatch_e_menu(BAR_ITEM(1));
  return TRUE;
}

bool TBenchmark_application::destroy()
{                               
  return TRUE;
}


bool TBenchmark_application::menu(MENU_TAG mt)
{
  if (mt == BAR_ITEM(1)) 
  {
    TString test = argv(1); test.upper();
    const bool test_all = test.find('*') >= 0;
    
    if (test_all || test.find('F') >= 0)
      test_file_scan();
  
    if (test_all || test.find('R') >= 0)
      test_relation_scan();
      
    if (test_all || test.find('C') >= 0)
      test_cursor_scan();

    if (test_all || test.find('T') >= 0)
      test_file_random();
  }
  return TRUE;  
} 

void TBenchmark_application::initializing()
{
  xvt_statbar_set("Initializing...");
  do_events();
}

void TBenchmark_application::start_test(const char* text)
{
  xvt_statbar_set(text);
  do_events();          
  
  clock_t t;
  _timer_start = clock();
  do
  { 
    t = clock(); 
  } while (t == _timer_start);
  _timer_start = t;
}

void TBenchmark_application::stop_test()
{
  const clock_t t = clock() - _timer_start; 
  const double s = (double)t / CLOCKS_PER_SEC;
  TString80 msg;
  msg.format("Time to complete: %.1lf s", s);
  message_box(msg);
}

void TBenchmark_application::update_bar(long rec)
{   
  if ((rec & 0x7F) == 0)
  {
    const double sec = double(clock() - _timer_start) / CLOCKS_PER_SEC;
    if (sec > 0.0)
    {
      TString80 msg;
      msg.format("%ld records at %ld rec/sec", rec, long(rec / sec));
      xvt_statbar_set(msg);
      do_events();
    }  
  }
}

void TBenchmark_application::test_file_scan()
{ 
  int found = 0;

  initializing();
  
  TLocalisamfile comuni(LF_COMUNI);
  
  start_test("Scansione file COMUNI di Reggio Emilia");
  

  comuni.first();
  for (TRecnotype rec = 0; !comuni.eof(); rec++)
  {
    if (comuni.get("PROVCOM") == "RE")
      found++;
    comuni.next();
    update_bar(rec);
  }  
  
  stop_test();  
}


void TBenchmark_application::test_relation_scan()
{ 
  int found = 0;

  initializing();
  
  TRelation comuni(LF_COMUNI);
  start_test("Scansione relazione COMUNI");
  
  comuni.first();
  for (TRecnotype rec = 0; !comuni.eof(); rec++)
  {
    if (comuni.curr().get("PROVCOM") == "RE")
      found++;
    comuni.next();
    update_bar(rec);
  }  
  
  stop_test();
}

void TBenchmark_application::test_cursor_scan()
{ 
  int found = 0;
  initializing();
  
  TRelation comuni(LF_COMUNI);
  TCursor cur(&comuni);
  
  start_test("Scansione cursore COMUNI");
        
  TRecnotype tot = cur.items();      
  cur = 0L;
  for (TRecnotype c = 0; c < tot; c++)
  {
    if (comuni.curr().get("PROVCOM") == "RE")
      found++;
    ++cur;
    update_bar(c);
  }  
  
  stop_test();
}

void TBenchmark_application::test_file_random()
{ 
  initializing();
  
  TLocalisamfile comuni(LF_COMUNI);
  
  start_test("Lettura randome del file COMUNI");
                 
  TRectype& rec = comuni.curr();
  char code[8];
  long found, notfound;
  
  for (long n = 0; n < 1000; n++)
  {
    const char l = 'A' + rand() % 26;
    const int c = rand() % 100;
    sprintf(code, "%c%03d", l, c);
    rec.zero();
    rec.put("COM", code);
    if (comuni.read() == NOERR)
      found++;                
    else
      notfound++;  
    update_bar(n);
  }  
  
  stop_test();  
}



///////////////////////////////////////////////////////////

int main(int argc, char** argv)
{
  TApplication::check_parameters(argc, argv);
  
  if (argc > 1 && *argv[1] == '-')
  {
    TBenchmark_application bma;
    bma.run(argc, argv, "Benchmark");
    return 0;
  }
  
  if (argc < 3)
  { 
    TFilename n = argv[1];
    if (n.not_empty())
    {
      TTest_application a(n);
      n = n.name(); n.insert("Test Mask ", 0);
      a.run(argc, argv, n);
    }  
  }
  else
  {
    if (isdigit(argv[2][0]))
    {
      TTestrel_application a(argv[1], argv[2]);
      a.run(argc, argv, "Test Relation Application");
    }
    else
    {                                                
      TTab_application a;
      a.run(argc, argv, "Test Table Application");    
    }  
  }

  return 0;
}