/*
 * $Id: Instance_fromXMLLight.cpp 109 2009-02-16 20:28:31Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Configuration/include/Instance.h"
#include "Common/include/FromString.h"
#include <fstream>

namespace morpheo {
namespace behavioural {
namespace configuration {

  using namespace XMLUtils;

#undef  FUNCTION
#define FUNCTION "Instance::fromXMLLight"
  void Instance::fromXMLLight (XML_t * xml,
                               attribute_t         id,
                               list_parameters_t * list_parameters,
                               list_links_t      * list_links,
                               list_components_t * list_components)
  {

    XMLLightVector<XML_t> vect = xml->getNodes(); 

    for (uint32_t i=0; i<vect.size(); ++i)
      {
        XML_t * child = vect[i];

        std::string child_name = child->getName();

//         log_printf(TRACE,Configuration,FUNCTION,"  * child_name : %s",child_name.c_str());

        //--------------------------------------------
        // Child : Parameter
        //--------------------------------------------
        if (child_name == "parameter")
          {
            // Is a parameter
            testSingleton  (child,true);        
            
            attributes_t attributes = child->getAttributes();
            attribute_t  value_name = getAttribute(child,attributes,"name" );
            attribute_t  value      = getAttribute(child,attributes,"value");

//             log_printf(TRACE,Configuration,FUNCTION,"    * parameter \"%s\" = %s",value_name.c_str(), value.c_str());
            
            testAttributesEmpty(child,attributes);

            // Test the parameter :
            //   * name is correct
            //   * value is correct
            test (value_name, value);
            
            // Insert in array
            Parameter_affectation * param = new Parameter_affectation(value_name, // type
                                                                      value);
            
            // insert parameter
            (*list_parameters)[param->_name] = param;
          }
        //--------------------------------------------
        // Child : Link
        //--------------------------------------------
        else
        if (child_name == "link")
          {
            // Is a parameter
            testSingleton  (child,true);        
            
            attributes_t attributes = child->getAttributes();
            attribute_t  value_name = getAttribute(child,attributes,"name");

//             log_printf(TRACE,Configuration,FUNCTION,"    * link  \"%s\"",value_name.c_str());
            
            // Test, must have src or dest (or twice)
            bool have_src  = child->containsAttribute("src" );
            bool have_dest = child->containsAttribute("dest");
            if (not have_src  and
                not have_dest)
              throw ERRORMORPHEO(FUNCTION,toString(_("Syntax error, node \"link\" must have one or twince of this attributes : src, dest\n")));
            
            attribute_t  value_src  = (have_src )?getAttribute(child,attributes,"src" ):id;
            attribute_t  value_dest = (have_dest)?getAttribute(child,attributes,"dest"):id;


            testAttributesEmpty(child,attributes);
            
            // Test the link :
            //   * name is correct
            //   * if not have_src , test if src  is correct
            //   * if not have_dest, test if dest is correct
            test (value_name,
                  xml->getName(),
                  not have_src,
                  not have_dest);

            // Create a new link
            {
              Link_affectation * link = new Link_affectation(value_name, // type
                                                             value_src,
                                                             value_dest);
              
              // Test if this id is previously used
              if (((*list_links)[value_name]).find(value_src) != ((*list_links)[value_name]).end())
                throw ERRORMORPHEO(FUNCTION,toString(_("A Link \"%s\" with the source \"%s\" is previously declared.\n"),value_name.c_str(),value_src.c_str()));
              
              ((*list_links)[value_name])[value_src] = link;
            }
          }
        //--------------------------------------------
        // Child : Timing
        //--------------------------------------------
        else
        if (child_name == "timing")
          {
//             log_printf(TRACE,Configuration,FUNCTION,"    * timing");

            // Notation :
            //     <timing type="5" operation="8" latence="2"  delay="1" />
            // 
            // is equivalent at :
            //     <type id="5" >
            //       <operation id="8" >
            //         <parameter  name="delay"   value="1" />
            //         <parameter  name="latence" value="2" />
            //       </operation>
            //     </type>

            // Is a parameter
            testSingleton  (child,true);        
            
            attributes_t attributes      = child->getAttributes();
            attribute_t  value_type      = getAttribute(child,attributes,"type");
            bool         have_operation  = (child->containsAttribute("operation"));
            attribute_t  value_operation ;
            attribute_t  value_latence   = (child->containsAttribute("latence"  ))?getAttribute(child,attributes,"latence"  ):"1";
            attribute_t  value_delay     = (child->containsAttribute("delay"    ))?getAttribute(child,attributes,"delay"    ):"1";

            {
              // Find component "type", if don't exist : create
              if (((*list_components)["type"]).find(value_type) == ((*list_components)["type"]).end())
                {
                  // Create instance
                  Instance_component * param = new Instance_component("type", // type
                                                                      value_type);
                  ((*list_components)["type"])[value_type] = param;
                }

              list_components_t * list_type = ((*list_components)["type"])[value_type]->_list_components;

              // Find component "operation", if exist : error, else create

              bool         stop            = false;
              Toperation_t operation       = 0;
              attribute_t  value_operation = (have_operation)?getAttribute(child,attributes,"operation"):toString(operation);

              while (not stop)
                {
                  if (((*list_type)["operation"]).find(value_operation) != ((*list_type)["operation"]).end())
                    throw ERRORMORPHEO(FUNCTION,toString(_("A Component \"%s\" with id \"%s\" is previously declared.\n"),"operation",value_operation.c_str()));
                  else
                    {
                      // Create instance
                      Instance_component * param = new Instance_component("operation", // type
                                                                          value_operation);
                      ((*list_type)["operation"])[value_operation] = param;
                    }

                  list_parameters_t * list_operation = ((*list_type)["operation"])[value_operation]->_list_parameters;
                  
                  // insert parameter "latence" and "delay"
                  Parameter_affectation * param_latence = new Parameter_affectation("latence",
                                                                                    value_latence);
                  Parameter_affectation * param_delay   = new Parameter_affectation("delay",
                                                                                    value_delay);            
                  
                  (*list_operation)["latence"] = param_latence;
                  (*list_operation)["delay"  ] = param_delay  ;

                  operation ++;
                  value_operation = toString(operation);
                  stop = have_operation or (operation == MAX_OPERATION);
                };
              
            }

            testAttributesEmpty(child,attributes);
          }
        //--------------------------------------------
        // Child : Other (component)
        //--------------------------------------------
        else
          {
//             log_printf(TRACE,Configuration,FUNCTION,"    * component");

            testSingleton  (child,false);        
            
            attributes_t attributes = child->getAttributes();
            attribute_t  value_ids  = getAttribute(child,attributes,"id");
            attribute_t  value_type = child->getName();

            testAttributesEmpty(child,attributes);

            // Test if counter is an parameters
            std::string name_counter = "nb_"+value_type;
            
            {
              if (list_parameters->find(name_counter) == list_parameters->end())
                {
                  // Insert in array
                  Parameter_affectation * param = new Parameter_affectation(name_counter, // type
                                                                            "0");
                  // insert parameter
                  (*list_parameters)[name_counter] = param;
                }
            }
            
            size_t index_begin = 0;
            while (index_begin != std::string::npos)
              {
                size_t index_end = value_ids.find_first_of(",",index_begin+1);
                
                size_t      index_min = (index_begin==0)?index_begin:(index_begin+1);
                size_t      index_max = index_end-index_min;
                attribute_t value_id  = value_ids.substr(index_min, index_max);

//                 log_printf(TRACE,Configuration,FUNCTION,"    * component \"%s\" - %s",value_type.c_str(), value_id.c_str());

                index_begin = index_end;

                // Create a new component
                {
                  Instance_component * param = new Instance_component(value_type, // type
                                                                      value_id);
              
//                log_printf(TRACE,Configuration,FUNCTION,"%s.%s",value_type.c_str(),value_id.c_str());
//                log_printf(TRACE,Configuration,FUNCTION,"  * %d",((*list_components)[value_type]).size());
              
                  // Test if this id is previously used
                  if (((*list_components)[value_type]).find(value_id) != ((*list_components)[value_type]).end())
                    throw ERRORMORPHEO(FUNCTION,toString(_("A Component \"%s\" with id \"%s\" is previously declared.\n"),value_type.c_str(),value_id.c_str()));
                  
                  ((*list_components)[value_type])[value_id] = param;
                }

                // Increase occurence counter
                {
                  (*list_parameters)[name_counter]->_value = toString(fromString<uint32_t>((*list_parameters)[name_counter]->_value)+1);
                }
                
                // Recursive function
                fromXMLLight (child,
                              ((id=="")?value_id:(id+"."+value_id)), // construction of identificator
                              ((*list_components)[value_type])[value_id]->_list_parameters,
//                            ((*list_components)[value_type])[value_id]->_list_links,
                              list_links,
                              ((*list_components)[value_type])[value_id]->_list_components);
              }
          }
      }
  };

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