#ifndef XML_OBJECT_POINTER_SPEC_H
#define XML_OBJECT_POINTER_SPEC_H


template<typename XMLIZED>

struct xmlObject<XMLIZED*> : public xmlWrapper<XMLIZED*>
{

  //an object factory to register different derived types for the object.
  xmlFactory<XMLIZED> * derivedFactory;

  //a "fake" (not wrapping anything) xmlObject<XMLIZED>, if the pointer is used as a simple 'container' over its base class
  xmlObject<XMLIZED> myHandler;

  //constructors and destructors:
  xmlObject(XMLIZED* & obj , std::string name = "" );
  xmlObject( std::string name = "" );
  virtual ~xmlObject();

  //overwriting some sub-routines from class xmlObject_base :
  virtual void save_Element (xmlpp::Element* the_element);
  virtual list<xmlpp::Element*> get_load_List (xmlpp::Node* father_node);
  virtual void load_Element (xmlpp::Element* the_element);

  //Copy the 'other-than-wrapped-object' properties of an xmlObject<XMLIZED*> to another.
  //Useful when dealing with containers, or pointers, over class XMLIZED*
  void copy_Handler(const xmlObject<XMLIZED*> & origin);

  //'un'-specialization of the function:
  static const type_info & pointer_typeid ( XMLIZED* *obj )
  {
    return typeid(obj);
  }

private : //non copyable
  xmlObject(const xmlObject<XMLIZED*> & yo){}
}
;




// *******************  AND HERE COMES THE CORRESPONDING TEMPLATE CODE ! *****************
// ***************************************************************************************



template<class XMLIZED>
xmlObject<XMLIZED*>::xmlObject(XMLIZED* & obj , std::string name ) : xmlWrapper<XMLIZED*>(obj,name)
{
  derivedFactory=new xmlFactory<XMLIZED>();
}

template<class XMLIZED>
xmlObject<XMLIZED*>::xmlObject(std::string name ) : xmlWrapper<XMLIZED*>(name) //no wrapped object...
{
  derivedFactory=new xmlFactory<XMLIZED>();
}

template<class XMLIZED>
xmlObject<XMLIZED*>::~xmlObject()
{
  xmlFactory<XMLIZED>::remove_occurence(derivedFactory);
}



template<class XMLIZED>
void xmlObject<XMLIZED*>::save_Element( xmlpp::Element* the_element )

{

  //ENTERING_NODE(xmlObject<XMLIZED*>::save_Element, the_element)

  // Just in case other childSpaces , or parameters, have been attached at this node (but... why should one do that??)
  xmlObject_base::save_Element(the_element);

  if(this->wrapped==0)
  {
    cerr<<"ERROR in function xmlPointer::save_Element(), at node<"<<the_element->get_name()<<">. This xmlPointer does not wrap any real pointer, which should never happen! Exiting."<<endl;
    exit(0);
  }

  if( *(this->wrapped) )

  {

    string saveName;

    //Does *(this->wrapped) already have an associated xmlObject, with a NAME ?
    xmlObject_base * tmp = xmlFC::find_xmlObject( **(this->wrapped) );
    //If yes, better use THAT name... it's gotta be good :-)
    if(tmp != 0)
      saveName = tmp->xmlName;
    else //use a default name
      //that's the tough line requiring a reflexive object factory...
      saveName = derivedFactory->GetId( *(this->wrapped) );

    //Even if **(this->wrapped) was already wrapped, we prefer to create a new wrapper xmlObject, just for saving.
    xmlObject<XMLIZED> * new_child= xmlFC::create_xmlObject( *(this->wrapped) , saveName );
    new_child -> copy_Handler( myHandler );

    add_toDelete(new_child);
    new_child->save_XML(the_element);

  }
}


//We must rewrite the two loading sub-routines, because of the very special case where the pointer name is ""


template<class XMLIZED>
list<xmlpp::Element*> xmlObject<XMLIZED*>::get_load_List (xmlpp::Node* father_node)
{
  //ENTERING(get_load_List_POINTER_VERSION)
  list<xmlpp::Element*> res;

  if( this->xmlName !="") 	//return the list of elements that bear the pointer's name
  {
    //cerr<<"pointer has a name: "<<this->xmlName<<endl;
    res= get_Element_children(father_node, this->xmlName );
  }

  else			//return the list of elements that bear SPECIALIZED names for pointed objects.
  {
    //cerr<<"pointer has null name."<<endl;
    res=get_Element_children (father_node);
    uint res_size=res.size();
    for(uint i=0; i<res_size ; ++i)
    {
      if( derivedFactory->isRegistered( res.front()->get_name() )  )
      {
        res.push_back (res.front() );
        //cerr<<"but factory found a registered name, as being "<<res.front()->get_name()<<endl;
      }
      res.pop_front();
    }
  }
  return res;
}



template<class XMLIZED>
void xmlObject<XMLIZED*>::load_Element(xmlpp::Element* the_element)
{
  //ENTERING_NODE(xmlObject<XMLIZED*>::load_Element, the_element)

  // Just in case other childSpaces , or parameters, have been attached at this node (but... why should one do that??)
  xmlObject_base::load_Element(the_element);


  //********** First step : two different ways of finding the xmlpp::Element * that will be loaded !

  list<xmlpp::Element *> find_child;

  if( this->xmlName != "")	//then, the_element is the pointer node. Check if it has ONE good specialisation name.
  {
    find_child=get_Element_children(the_element);
    for(uint i=0; i<find_child.size() ; ++i)
    {
      if( !  derivedFactory->isRegistered( find_child.front()->get_name() )  )
        find_child.pop_front();
    }

    if(find_child.size()>1)
    {
      cerr<<"WARNING in function xmlObject<XMLIZED*>::load_Element : node <"<<the_element->get_name()<<"> leads to more than one possible element whose name has been registered for the initialization of the pointer. First element is taken into account."<<endl;
    }
    while(find_child.size()>1)
      find_child.pop_back();

    if( find_child.size() == 0 ) return;	//The pointer has a node, but no correct specialization under it.
  }

  else  	//the_element is already the specialized object node, as found by function get_load_List.
    find_child.push_back(the_element);


  //*********** Second step : creating the object and loading it from xml:

  string loadName=find_child.front()->get_name();

  if(this->wrapped==0)
  {
    cerr<<"ERROR in function xmlPointer::load_relevant_Element(), at node<"<<loadName<<">. This xmlPointer does not wrap any real pointer, which should never happen! Exiting."<<endl;
    exit(0);
  }

  if( *(this->wrapped) )
  {
    cerr<<"WARNING in function xmlPointer::load_relevant_Element(), at node<"<<loadName<<">. You are asking to load an already initialized pointer. Old pointed object is detroyed, and a new object is created according to the xml specifications."<<endl;
    delete *(this->wrapped);
    *(this->wrapped)=0;
  }

  *(this->wrapped) = derivedFactory->Create(loadName);	//So... we are sure it exists!...

  xmlObject<XMLIZED> * new_child = xmlFC::create_xmlObject( *(this->wrapped) , loadName );
  new_child -> copy_Handler( myHandler );

  this->add_toDelete(new_child);
  
  new_child->load_Element(find_child.front() );
}



//The copy_Handler function in this case:

template<class XMLIZED>
void xmlObject<XMLIZED*>::copy_Handler(const xmlObject<XMLIZED*> & origin)
{
  xmlFactory<XMLIZED>::remove_occurence(derivedFactory);
  xmlFactory<XMLIZED>::assign(derivedFactory , origin.derivedFactory);
  myHandler.copy_Handler( origin.myHandler );
  myHandler.xmlName = origin.myHandler.xmlName;
}




// *******************  AND HERE COME THE SPECIALIZATIONS FOR FUNCTION Register IN THE POINTER CASE ********
// *********************************************************************************************************


//*************
// (1)  in the general case, when order > 1 , just passing the registration of derivedCLASS to my handler !
//*************


template < uint order , typename XMLIZED , typename derivedCLASS >
struct Register_obj <order , XMLIZED* , derivedCLASS >
{

  static bool total_registration (list<string> registerNames , xmlObject<XMLIZED*> * xmlobj)
  {
    if( registerNames.size() != order )
      cerr<<"ERROR in function Register_obj <"<<order<<" , XMLIZED * , derivedCLASS >::total_registration (list<string> registerNames , xmlObject<XMLIZED*> * xmlobj) : the list registerNames must have the same size as the value of 'order' "<<endl;


    //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <"<<order<<" , XMLIZED* , derivedCLASS >::total_registration is registering NAME:"<<endl;
    //cerr<<registerNames.front()<<endl;

    //auto-registration of the type of the handler (that is, XMLIZED) :
    Register_obj <1 , XMLIZED* , XMLIZED >::last_step_registration ( registerNames.front() , xmlobj );

    //passing the registration of type <derivedCLASS> to the xmlObject<XMLIZED> myHandler of xmlobj:
    registerNames.pop_front();
    return Register_obj <order-1 , XMLIZED , derivedCLASS>::total_registration ( registerNames , &( xmlobj->myHandler ) );
  }

  static bool last_step_registration ( std::string registerName , xmlObject<XMLIZED*> * xmlobj)
  {

    //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <"<<order<<" , XMLIZED* , derivedCLASS >::last_step_registration is registering NAME:"<<endl;
    //cerr<<registerName<<endl;

    //only passing the registration of type <derivedCLASS> to the xmlObject<XMLIZED> myHandler of xmlobj:
    return Register_obj <order-1 , XMLIZED , derivedCLASS>::last_step_registration ( registerName , &( xmlobj->myHandler ) );
  }

};



//*************
// (2)   For order 1, it is OUR derivedFactory that is concerned with the type derivedCLASS :
//*************


template < typename XMLIZED , typename derivedCLASS >
struct Register_obj <1 , XMLIZED* , derivedCLASS >
{

  static bool total_registration (list<string> registerNames , xmlObject<XMLIZED*> * xmlobj)
  {
    if( registerNames.size() != 1 )
      cerr<<"ERROR in function Register_obj <1 , XMLIZED * , derivedCLASS >::total_registration (list<string> registerNames , xmlObject<XMLIZED*> * xmlobj) : the list registerNames must have the same size as the value of 'order' "<<endl;


    //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <1 , XMLIZED* , derivedCLASS >::total_registration is registering NAME:"<<endl;
    //cerr<<registerNames.front()<<endl;

    return xmlobj->derivedFactory->template Register<derivedCLASS> ( registerNames.front() );
  }

  static bool last_step_registration ( std::string registerName , xmlObject<XMLIZED*> * xmlobj)
  {

    //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <1 , XMLIZED* , derivedCLASS >::last_step_registration is registering NAME:"<<endl;
    //cerr<<registerName<<endl;

    return xmlobj->derivedFactory->template Register<derivedCLASS> ( registerName );
  }

};


#endif
