#ifndef morpheo_behavioural_Interface_h
#define morpheo_behavioural_Interface_h

/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#ifdef SYSTEMC
#include "systemc.h"
#endif

#include <stdint.h>
#include <iostream>
#include <list>
#include "Behavioural/include/Signal.h"
#include "Behavioural/include/Direction.h"
#include "Behavioural/include/Localisation.h"
#ifdef VHDL
#include "Behavioural/include/Vhdl.h"
#endif
#include "Common/include/ChangeCase.h"
#include "Common/include/ToString.h"
#include "Common/include/ErrorMorpheo.h"
#include "Common/include/Debug.h"
#include "Behavioural/include/Usage.h"

namespace morpheo              {
namespace behavioural          {

  class Interface
  {
    // -----[ fields ]----------------------------------------------------
  protected : const std::string          _name         ;
#ifdef POSITION
  protected : const direction_t     _direction    ;
  protected : const localisation_t  _localisation ;
#endif
  protected : const Tusage_t        _usage;

#ifdef POSITION
  protected :       std::string          _comment      ;
#endif

  protected : std::list<Signal *>      * _list_signal  ;

#ifdef POSITION
  protected :       bool            _is_map       ;
  protected :       void          * _entity_map   ; // Entity -> erreur cyclique
  protected :       void          * _interface_map; // pour être homogène avec _entity_map
#endif

#ifdef VHDL_TESTBENCH
  private   : uint32_t              _nb_cycle     ;
#endif
    
    // -----[ methods ]---------------------------------------------------
  public    :                       Interface            (std::string         name        
#ifdef POSITION
							  ,direction_t    direction   
							  ,localisation_t localisation
#endif
							  ,Tusage_t       usage=USE_ALL
							  );

  public    :                       Interface            (const Interface    & interface);
  public    :                       ~Interface           ();

  public    : std::string                get_name             ();

#ifdef POSITION
  public    : void                  set_comment          (std::string comment);
  protected : std::string                get_comment          (void          );
#endif

  protected : std::string                signal_name          (std::string      name_interface,
							  std::string      name_signal   ,
							  direction_t direction     );

  public    : Signal *              find_signal          (std::string name);
  public    : bool                  find_signal          (Signal * signal);

  protected : std::string                get_signal           (void);
  public    : Signal *              set_signal           (std::string          name     ,
							  direction_t     direction,
							  uint32_t        size     ,
							  presence_port_t presence_port = PORT_VHDL_YES_TESTBENCH_YES);
  public    : std::list<Signal *>      * get_signal_list      (void);

#ifdef SYSTEMC
  public    : sc_in_clk *           set_signal_clk       (std::string          name     ,
							  uint32_t        size     ,
							  presence_port_t presence_port=CLOCK_VHDL_YES)
    {
      log_printf(FUNC,Behavioural,"set_signal_clk","Begin");

      if ((presence_port != CLOCK_VHDL_YES) and
	  (presence_port != CLOCK_VHDL_NO ))
	throw ErrorMorpheo ("Signal \""+name+"\" is a clock, bad presence_port.");

      Signal    * sig  = set_signal (name, IN , size, presence_port);
      sc_in_clk * port;

      if (_usage & USE_SYSTEMC)
	{
	  port = new sc_in_clk (sig->_name.c_str());
	  sig->alloc<bool> (static_cast<void *>(port));
	}
      else
	{
	  port = NULL;
	}

      log_printf(FUNC,Behavioural,"set_signal_clk","End");

      return port;
    };

  public    : template <typename T>
              sc_in <T> *           set_signal_in       (std::string          name     ,
							 uint32_t        size     ,
							 presence_port_t presence_port=PORT_VHDL_YES_TESTBENCH_YES)
    {
      log_printf(FUNC,Behavioural,"set_signal_in","Begin");

      if ((presence_port == CLOCK_VHDL_YES) or 
	  (presence_port == CLOCK_VHDL_NO ))
	throw ErrorMorpheo ("Signal \""+name+"\" is not a clock, bad presence_port.");

      Signal    * sig  = set_signal (name, IN , size, presence_port);
      sc_in <T> * port;

      if (_usage & USE_SYSTEMC)
	{
	  port = new sc_in <T> (sig->_name.c_str());
	  sig->alloc<T> (static_cast<void *>(port));
	}
      else
	{
	  port = NULL;
	}

      log_printf(FUNC,Behavioural,"set_signal_in","End");

      return port;
    };

  public    : template <typename T>
              sc_out <T> *          set_signal_out      (std::string          name     ,
							 uint32_t        size     ,
							 presence_port_t presence_port=PORT_VHDL_YES_TESTBENCH_YES)
    {
      log_printf(FUNC,Behavioural,"set_signal_out","Begin");

      if ((presence_port == CLOCK_VHDL_YES) or 
	  (presence_port == CLOCK_VHDL_NO ))
	throw ErrorMorpheo ("Signal \""+name+"\" is not a clock, bad presence_port.");

      Signal * sig = set_signal (name, OUT , size, presence_port);
      sc_out <T> * port;

      if (_usage & USE_SYSTEMC)
	{
	  port = new sc_out <T> (sig->_name.c_str());
	  sig->alloc<T> (static_cast<void *>(port));
	}
      else
	{
	  port = NULL;
	}

      log_printf(FUNC,Behavioural,"set_signal_out","End");

      return port;
    };

  public    : template <typename T>
              sc_signal <T> *       set_signal_internal (std::string   name,
							 uint32_t size)
    {
      log_printf(FUNC,Behavioural,"set_signal_internal","Begin");

      Signal * sig = set_signal (name, INTERNAL , size, PORT_VHDL_NO_TESTBENCH_NO);
      sc_signal <T> * port;

      if (_usage & USE_SYSTEMC)
	{
	  port = new sc_signal <T> (sig->_name.c_str());
	  sig->alloc<T> (static_cast<void *>(port));
	}
      else
	{
	  port = NULL;
	}

      log_printf(FUNC,Behavioural,"set_signal_internal","End");

      return port;
    };

#endif

#ifdef VHDL
  public    : void                  set_port             (Vhdl * & vhdl);
#  ifdef VHDL_TESTBENCH
  public    : void                  set_signal           (Vhdl * & vhdl);
  public    : void                  get_signal           (std::list<std::string> * & list_signal);
#  endif
#endif
#ifdef VHDL_TESTBENCH
  public    : uint32_t              get_cycle            (void);
  public    : Signal *              get_clock            (void);
  public    : Signal *              get_reset            (void);

  public    : void                  testbench            (void);
  public    : void                  testbench_cycle      (void);
  public    : void                  testbench_body       (Vhdl           * & vhdl          ,
							  std::string             counter_name  ,
							  std::string             reset_name    );
  public    : std::string                testbench_test       (Vhdl           * & vhdl        ,
							  std::string             counter_name,
							  std::string             reset_name);
  public    : std::string                testbench_test_ok    (Vhdl           * & vhdl        );
  protected : std::string                testbench_test_name   (Vhdl           * & vhdl);
  protected : std::string                testbench_test_ok_name(Vhdl           * & vhdl);
  protected : std::string                testbench_test_transaction_name(Vhdl           * & vhdl);
#endif

  public    : bool                  test_map             (uint32_t depth, bool top_level);

#ifdef POSITION
  public    : void                  interface_map        (void * entity,
							  void * interface);
  public    : XML                   toXML                (void);
  public    : XML                   toXML_mapping        (void);
#endif
  public    : friend std::ostream&       operator<<           (std::ostream& output_stream,
							       morpheo::behavioural::Interface & x);

  };

}; // end namespace behavioural          
}; // end namespace morpheo              

#endif
