/*
 * $Id: Signal_link.cpp 113 2009-04-14 18:39:12Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/include/Signal.h"


namespace morpheo              {
namespace behavioural          {

#undef  FUNCTION
#define FUNCTION "Signal::link"
  void Signal::link (Signal * signal_dest,
		     bool     signal_dest_is_port)
  {
    // signal_dest_is_port == 1 when the signal dest is in a top level interface. (else, signal_dest is type "INTERNAL")
    
    log_printf(FUNC,Behavioural,FUNCTION,"Begin");

    Signal * signal_src = this;

    // Test
    if (signal_src ->_is_allocate == false)
      throw (ERRORMORPHEO (FUNCTION,"Signal \""+_name+"\", can't map with signal \""+        get_name()+"\", because the first signal is not already allocate."));
    if (signal_dest->_is_allocate == false)
      throw (ERRORMORPHEO (FUNCTION,"Signal \""+_name+"\", can't map with signal \""+signal_dest->get_name()+"\", because the second signal is not already allocate."));

    // List of all case
    //
    //            src         dest
    // COMPONENT {IN } ----- {SIG} SIGNAL
    // COMPONENT {OUT} ----- {SIG} SIGNAL
    //
    // COMPONENT {IN } ----- {IN } PORT
    // COMPONENT {OUT} ----- {OUT} PORT

    // list valid case
    if (not (    signal_dest_is_port and (((signal_src->_direction == IN ) and (signal_dest->_direction == IN      )) or
					  ((signal_src->_direction == OUT) and (signal_dest->_direction == OUT     )))) and
	not (not signal_dest_is_port and (((signal_src->_direction == IN ) and (signal_dest->_direction == INTERNAL)) or
					  ((signal_src->_direction == OUT) and (signal_dest->_direction == INTERNAL)))))
      throw (ERRORMORPHEO (FUNCTION,"Signal \""+_name+"\" can't been linked with signal \""+signal_dest->get_name()+"\" : illegal direction ("+toString(signal_src->_direction)+" with "+toString(signal_dest->_direction)+")."));


    // Multi consumer is authorized , no to multi producer!
    bool source_have_multi_consumer      = (signal_src ->_connect_to_signal != NULL);
//     bool destination_have_multi_producer = (signal_dest->_connect_from_signal != NULL) and (signal_dest_is_port == false);
//     if (destination_have_multi_producer)
// //       throw (ERRORMORPHEO (FUNCTION,"Signal \""+_name+"\" can't been linked with signal \""+signal_dest->get_name()+"\" : destination have multi producer."));
//       log_printf(INFO,Behavioural,FUNCTION,"Signal \"%s\" can't been linked with signal \"%s\" : destination have multi producer.",_name.c_str(),signal_dest->get_name().c_str());

    // update info source
    signal_src ->_connect_to_signal       = signal_dest;
    signal_src ->_is_map_as_component_src = true;

    // update info destination
    if (signal_dest_is_port == true)
      signal_dest->_is_map_as_toplevel_dest = true; // because toplevel port can't be a source
    else
      // signal_dest is a internal signal
      if (signal_src->_direction == OUT)
	signal_dest->_is_map_as_component_dest = true;
      else
	signal_dest->_is_map_as_component_src  = true;
    
    // an internal signal and port can't be a source. 
    // also, to fill the connect_to_signal's field 
    if (signal_dest->_direction == INTERNAL)
      if (signal_src->_direction == OUT)
	signal_dest->_connect_from_signal = signal_src;
      else
	signal_dest->_connect_to_signal   = signal_src;
    else
      signal_dest->_connect_from_signal   = signal_src;
    
    // vhdl_testbench : to read an output producte by a internal component
    // TODO : ŕ vérifier !!!!!!!!!!!!
    if ((signal_dest_is_port == true) and 
	(signal_src ->_direction == OUT))
      signal_dest->_sc_signal_map = signal_src ->_sc_signal_map;

    // A signal can be connect once
    if (not source_have_multi_consumer)
      connect (signal_dest);

    log_printf(FUNC,Behavioural,FUNCTION,"End");
  };

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