#ifndef TEST_H
#define TEST_H

#include <iostream>
#include <sstream>
#include <stdint.h>
#include "Common/include/Message.h"
#include "Common/include/ErrorMorpheo.h"
#include "Common/include/ToString.h"

namespace morpheo {

//-----[ Routine de test ]---------------------------------------

static uint32_t num_test;

inline void test_ko_error (void)
{
  std::string msg = "Test ko : error in test \""+morpheo::toString(num_test)+"\"";
  throw (morpheo::ErrorMorpheo (msg));
}
  
template <class T>
inline void test_ko (char * file, uint32_t line, T exp1, T exp2)
{
  std::cerr << "[" << num_test << "] : Test KO"
       << "\tline " << line                           << std::endl
       << " * Localisation"                           << std::endl
       << "   - File : " << file                      << std::endl
       << "   - Line : " << line                      << std::endl
       << " * Expression is different"                << std::endl
       << "   - exp1 : "+morpheo::toString(exp1)               << std::endl
       << "   - exp2 : "+morpheo::toString(exp2)               << std::endl;

  test_ko_error ();
};

inline void test_ko (char * file, uint32_t line)
{
  std::cerr << "[" << num_test << "] : Test KO"
       << "\tline " << line                           << std::endl
       << " * Localisation"                           << std::endl
       << "   - File : " << file                      << std::endl
       << "   - Line : " << line                      << std::endl;
  
  test_ko_error ();
};

inline void test_ok ()
{
  msg (_("[%d] : Test OK\n"), num_test);

  num_test ++;
};

inline void test_ok (char * file, uint32_t line)
{
  msg (_("[%d] : Test OK\n"), num_test);
  msg (_("\tline %d\n"), line);

  num_test ++;
};

template <class T>
inline void test_ok (char * file, uint32_t line, T exp)
{
  msg (_("[%d] : Test OK\n"), num_test);
  msg (_("\tline %d\n"), line);
  msg (_("\tvalue %s\n"), (morpheo::toString(exp)).c_str());

  num_test ++;
}

template <class T>
inline void test(char * file, uint32_t line, T exp1, T exp2)
{
  if (exp1 != exp2)
    test_ko <T> (file,line,exp1,exp2);
  else
    test_ok <T> (file,line,exp1);
};

#define TEST(type,exp1,exp2)            do {morpheo::test<type> (__FILE__,__LINE__,exp1,exp2);} while(0)
#define TEST_STR(type,exp1,exp2,str...) do {fprintf(stdout,str); fprintf(stdout,"\n"); morpheo::test<type> (__FILE__,__LINE__,exp1,exp2);} while(0)
#define TEST_OK(str...)                 do {fprintf(stdout,str); fprintf(stdout,"\n"); morpheo::test_ok(__FILE__,__LINE__);} while(0)
#define TEST_KO(str...)                 do {fprintf(stdout,str); fprintf(stdout,"\n"); morpheo::test_ko(__FILE__,__LINE__);} while(0)


#define LABEL(str...)							\
  {									\
    msg (_("{%d} "),static_cast<uint32_t>(sc_simulation_time()));	\
    msg (str);								\
    msg (_("\n"));							\
  } while(0)


#ifndef CYCLE_MAX
# error "CYCLE_MAX must be defined";
#endif

#define SC_START(cycle_offset)						\
  do									\
    {									\
      /*cout << "SC_START (begin)" << endl;*/				\
      									\
      uint32_t cycle_current = static_cast<uint32_t>(sc_simulation_time()); \
      if (cycle_offset != 0)						\
	{								\
	  cout << "##########[ cycle "<< cycle_current+cycle_offset << " ] (" << __LINE__ << ")" << endl; \
	}								\
      									\
      if (cycle_current > CYCLE_MAX)					\
	{								\
	  TEST_KO("Maximal cycles Reached");				\
	}								\
      									\
      sc_start(cycle_offset);						\
      									\
      /*cout << "SC_START (end  )" << endl;*/				\
    } while(0)



};
#endif
