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

#include "Behavioural/include/Component.h"

namespace morpheo              {
namespace behavioural          {

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

//     log_printf(INFO,Behavioural,FUNCTION,"Map %s.%s with %s.%s",
// 	       component_src.c_str(),
// 	       port_src.c_str(),
// 	       component_dest.c_str(),
// 	       port_dest.c_str());

    std::string name_entity = _entity->get_name();

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

    if (entity_dest == NULL)
      throw (ERRORMORPHEO (FUNCTION,"In component \""+name_entity+"\", try map \""+component_src+"."+port_src+"\" with \""+component_dest+"."+port_dest+"\" but the component \""+component_dest+"\" is unknow.\n"));

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

    if (signal_dest == NULL)
      throw (ERRORMORPHEO (FUNCTION,"In component \""+name_entity+"\",try map \""+component_src+"."+port_src+"\" with \""+component_dest+"."+port_dest+"\" but the component \""+component_dest+"\" have not the signal \""+port_dest+"\".\n"));

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

    if (entity_src == NULL)
      throw (ERRORMORPHEO (FUNCTION,"In component \""+name_entity+"\", try map \""+component_src+"."+port_src+"\" with \""+component_dest+"."+port_dest+"\" but the component \""+component_src+"\" is unknow.\n"));

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

    if (signal_src == NULL)
      throw (ERRORMORPHEO (FUNCTION,"In component \""+name_entity+"\", try map \""+component_src+"."+port_src+"\" with \""+component_dest+"."+port_dest+"\" but the component \""+component_src+"\" have not the signal \""+port_src+"\".\n"));

    // 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 (FUNCTION,"In component \""+name_entity+"\", try map \""+component_src+"."+port_src+"\" with \""+component_dest+"."+port_dest+"\" but the component \""+component_src+" is the Top_level, and we can't be use interface's port of the top level as a source.\n"));
    
    // 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;
	Signal * signal_consumer ;
	Entity * entity_consumer ;

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

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

	// Create internal signal
	signal_dest= signal_internal (entity_productor,
                                      signal_productor,
                                      entity_consumer ,
                                      signal_consumer );
	signal_dest->set_size_max(signal_src->get_size());
      }
    
    try
      {
	signal_src->link(signal_dest,
			 dest_is_port);
      }
    catch (morpheo::ErrorMorpheo & error)
      {
      throw (ERRORMORPHEO (FUNCTION,"In component \""+name_entity+"\", try map \""+component_src+"."+port_src+"\" with \""+component_dest+"."+port_dest+"\" but "+error.what ()));
      }
    //catch (...)
    //  {
    //  }

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

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