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

#include "Behavioural/include/Component.h"

namespace morpheo              {
namespace behavioural          {

#undef  FUNCTION
#define FUNCTION "Component::port_map"
  void Component::port_map (string component_src ,
			    string port_src      ,
			    string component_dest,
			    string port_dest     )
  {
    log_printf(FUNC,Behavioural,FUNCTION,"Begin");

    string name_entity = _entity->get_name();

    // First entity 
    Entity * entity_dest = find_entity(component_dest);

    if (entity_dest == NULL)
      throw (ErrorMorpheo ("<Component::port_map> in component \""+name_entity+"\", port map with unknow component \""+component_dest+"\"."));

    Signal * signal_dest = entity_dest->find_signal (port_dest);

    if (signal_dest == NULL)
      throw (ErrorMorpheo ("<Component::port_map> in component \""+name_entity+"\", port map with component \""+component_dest+"\" and a unknow signal \""+port_dest+"\"."));

    // Second entity
    Entity * entity_src = find_entity(component_src);

    if (entity_src == NULL)
      throw (ErrorMorpheo ("<Component::port_map> in component \""+name_entity+"\", port map with unknow component \""+component_src+"\"."));

    Signal * signal_src = entity_src->find_signal (port_src);

    if (signal_src == NULL)
      throw (ErrorMorpheo ("<Component::port_map> in component \""+name_entity+"\", port map with component \""+component_src+"\" and a unknow signal \""+port_src+"\"."));

    // If all is ok, mapping
    log_printf(TRACE,Behavioural,FUNCTION, "Signal \"%s.%s\"\tlink with \"%s.%s\""
	       ,entity_src ->get_name().c_str()
	       ,signal_src ->get_name().c_str()
	       ,entity_dest->get_name().c_str()
	       ,signal_dest->get_name().c_str());

    // need an internal signal ?
    bool src_is_port  = entity_src  == _entity;
    bool dest_is_port = entity_dest == _entity;

    if (src_is_port == true)
      throw (ErrorMorpheo ("<Component::port_map> src can't be an interface's port of the top level."));
    
    // 2 cases : 
    //  a) dest is a top level port -> direct connection
    //  b) dest is a component port -> need internal signal
    if (dest_is_port == false)
      {
	// 1) find productor of signal
	//        
	// Interface      Component
	//    |	         |	   
	//  ----> (IN)     --X-> (IN) 
	//    |	         |	   
	//  <-X-- (OUT)    <---- (OUT)
	//    |              |        
	
	Signal * signal_productor;
	Entity * entity_productor;

	bool     src_is_productor = (signal_src->get_direction() == OUT);

	if (src_is_productor == true)
	  {
	    signal_productor = signal_src;
	    entity_productor = entity_src;
	  }
	else
	  {
	    signal_productor = signal_dest;
	    entity_productor = entity_dest;
	  }

	signal_dest= signal_internal (entity_productor, signal_productor);
	signal_dest->set_size_max(signal_src->get_size());

	dest_is_port = false;
      }
    
    try
      {
	signal_src->link(signal_dest,
			 dest_is_port);
      }
    catch (morpheo::ErrorMorpheo & error)
      {
	throw (ErrorMorpheo ("<Component::port_map> Error in mapping between "+entity_src ->get_name()+"."+signal_src ->get_name()+" and "+entity_dest->get_name()+"."+signal_dest->get_name()+" :\n"+error.what ()));
      }
    //catch (...)
    //  {
    //  }

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


  void Component::port_map (string component_src ,
			    string port_src      )
  {
    log_printf(FUNC,Behavioural,FUNCTION,"Begin");
    
    Entity * entity_src = find_entity(component_src);
    
    if (entity_src == NULL)
      throw (ErrorMorpheo ("<Component::port_map> in component \""+_entity->get_name()+"\", port map with unknow component \""+component_src+"\"."));
    
    Signal * signal_src = entity_src->find_signal (port_src);
    
    if (signal_src == NULL)
      throw (ErrorMorpheo ("<Component::port_map> in component \""+_entity->get_name()+"\", port map with component \""+component_src+"\" and a unknow signal \""+port_src+"\"."));
    
    // need an internal signal ?
    
    if (entity_src == _entity)
      throw (ErrorMorpheo ("<Component::port_map> src can't be an interface's port of the top level."));
    
    if (signal_src->get_direction() != OUT)
      throw (ErrorMorpheo ("<Component::port_map> the direction of the signal '"+signal_src->get_name()+"' must be OUT."));

    Signal * signal_dest;

    signal_dest= signal_internal (entity_src, signal_src);
    signal_dest->set_size_max(signal_src->get_size());
    
    try
      {
	signal_src->link(signal_dest,
			 false);
      }
    catch (morpheo::ErrorMorpheo & error)
      {
	throw (ErrorMorpheo ("<Component::port_map> Error in mapping "+entity_src ->get_name()+"."+signal_src ->get_name()+" :\n"+error.what ()));
      }
    //catch (...)
    //  {
    //  }

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

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

