#ifndef XML_OBJECT_CONTAINER_SPEC_H
#define XML_OBJECT_CONTAINER_SPEC_H


/* To avoid that this specialization be applied by the compiler whenever it
 * encounters a template class (not necessarily a container!!), all this code
 * is defined in a 'fake' object xmlObject_CV  (standing for Container Version).
 * Then, the corresponding xmlObject are explicitly specialized for 
 * vector<XMLIZED>, list<XMLIZED> and deque<XMLIZED> */


// Note: With new version of gcc, the specialization must be explicitly made
// mentionning the ALLOCATOR used. Otherwise the specialization is NOT applied.


// (Part I) - The 'intermediate' object xmlObject_CV ...
// *****************************************************

template <typename whatever> struct xmlObject_CV {};

// ...and its only useful specialization :

template<typename XMLIZED, typename ALLOC, template <typename XMLIZED, typename ALLOC> class Cont>
struct xmlObject_CV < Cont<XMLIZED, ALLOC> > : public xmlWrapper< Cont<XMLIZED, ALLOC> > {
    
    //a "fake" xmlObject to keep trace of the common parameters shared by all elements of the container.
    xmlObject<XMLIZED> myHandler;
    
    //constructors and destructors:
    xmlObject_CV( Cont<XMLIZED, ALLOC> & obj , std::string name="" );
    xmlObject_CV( std::string name="" );
    
    //overwriting some sub-routines from class xmlObject_base :
    virtual void save_Element(xmlpp::Element* the_element);
    virtual void load_Element(xmlpp::Element* the_element);
    
    //Copy the 'other-than-wrapped-object' properties of an xmlObject< Cont<XMLIZED,ALLOC> > to another.
    //Useful when dealing with containers, or pointers, over class Cont<XMLIZED,ALLOC>
    void copy_Handler(const xmlObject_CV< Cont<XMLIZED, ALLOC> > & origin);
    
    //'un'-specialization of the function:
    static const type_info & pointer_typeid( Cont<XMLIZED, ALLOC> *obj ) {
        return typeid(obj);
    }
    
private : //non copyable
    xmlObject_CV(const xmlObject_CV< Cont<XMLIZED, ALLOC> > & yo){}
};



// (Part II) Defining the 'real' xmlObjects, for vectors, lists and deques
// ***********************************************************************

// Only need to declare the constructors again.


template < typename XMLIZED_ >
struct xmlObject < vector<XMLIZED_, std::allocator<XMLIZED_> > > :
public xmlObject_CV < vector<XMLIZED_, std::allocator<XMLIZED_> > > {
    
    xmlObject( vector<XMLIZED_, std::allocator<XMLIZED_> > & obj , std::string name="" ) :
    xmlObject_CV < vector<XMLIZED_, std::allocator<XMLIZED_> > > (obj, name)
    {}
    
    xmlObject( std::string name="" ) :
    xmlObject_CV < vector<XMLIZED_, std::allocator<XMLIZED_> > > (name)
    {}
};

template < typename XMLIZED_ >
struct xmlObject < list<XMLIZED_ , std::allocator<XMLIZED_> > > :
public xmlObject_CV < list<XMLIZED_ > > {
    xmlObject( list<XMLIZED_, std::allocator<XMLIZED_> > & obj , std::string name="" ) :
    xmlObject_CV < list<XMLIZED_, std::allocator<XMLIZED_> > > (obj, name)
    {}
    
    xmlObject( std::string name="" ) :
    xmlObject_CV < list<XMLIZED_, std::allocator<XMLIZED_> > > (name)
    {}
};

template < typename XMLIZED_ >
struct xmlObject < deque<XMLIZED_, std::allocator<XMLIZED_> > > :
public xmlObject_CV < deque<XMLIZED_, std::allocator<XMLIZED_> > > {
    xmlObject( deque<XMLIZED_, std::allocator<XMLIZED_> > & obj , std::string name="" ) :
    xmlObject_CV < deque<XMLIZED_, std::allocator<XMLIZED_> > > (obj, name)
    {}
    
    xmlObject( std::string name="" ) :
    xmlObject_CV < deque<XMLIZED_, std::allocator<XMLIZED_> > > (name)
    {}
};



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

//Constructors

template<typename XMLIZED, typename ALLOC, template <typename XMLIZED, typename ALLOC> class Cont>
xmlObject_CV < Cont<XMLIZED,ALLOC> >::xmlObject_CV( Cont<XMLIZED,ALLOC> & obj , std::string name ) : xmlWrapper< Cont<XMLIZED,ALLOC> >(obj, name)
{}

template<typename XMLIZED, typename ALLOC, template <typename XMLIZED, typename ALLOC> class Cont>
xmlObject_CV < Cont<XMLIZED,ALLOC> >::xmlObject_CV( std::string name ) : xmlWrapper< Cont<XMLIZED,ALLOC> > (name)
{}



template<typename XMLIZED, typename ALLOC, template <typename XMLIZED, typename ALLOC> class Cont>
void xmlObject_CV< Cont<XMLIZED,ALLOC> >::save_Element(xmlpp::Element* the_element) {
    
    //ENTERING_NODE(xmlContainer::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);
    
    for (typename Cont<XMLIZED,ALLOC>::iterator arf=this->wrapped->begin() ; arf!=this->wrapped->end() ;arf++) {
        //cerr<<"CONTAINER "<<typeid(*this).name()<<" : HERE IS MY NUMBER OF CHILDREN: "<<this->childSpace.size()<<endl;
        //cerr<<"AND HERE IS THE NAME OF MY HANDLER: "<<myHandler.xmlName<<endl<<endl;
        
        xmlObject<XMLIZED> * new_child= xmlFC::create_xmlObject( &(*arf) , myHandler.xmlName );
        this->add_toDelete(new_child);
        
        new_child->copy_Handler(myHandler);
        new_child->save_XML(the_element);
    }
}


template<typename XMLIZED, typename ALLOC, template <typename XMLIZED, typename ALLOC> class Cont>
void xmlObject_CV< Cont<XMLIZED,ALLOC> >::load_Element(xmlpp::Element* the_element) {
    //ENTERING_NODE(xmlContainer::load_Element, the_element)
    
    
    //First step: 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);
    
    
    //Second step : creating the contained elements , and loading them from xml (from the LIST, this time !)
    
    //cerr<<"Here is the name of MY HANDLER: "<<myHandler.xmlName<<endl;
    list<xmlpp::Element *> find_contained = myHandler.get_load_List( the_element );
    
    //cerr<<"Here is the container list: "<<endl;
    //xml_print_list(find_contained);
    
    while( find_contained.size() ) {
        this->wrapped->push_back( XMLIZED() );	//the container...
        xmlObject<XMLIZED> * handler_for_new_element = xmlFC::create_xmlObject( &( this->wrapped->back() ) , myHandler.xmlName );
        
        //cout<<"CREATED AN XML HANDLER OF TYPE: "<<typeid(*handler_for_new_element).name()<<endl;
        
        this->add_toDelete(handler_for_new_element);
        handler_for_new_element->copy_Handler(myHandler);
        handler_for_new_element->xmlName = myHandler.xmlName;
        
        handler_for_new_element->load_Element( find_contained.front() ) ;
        find_contained.pop_front();
        
        
    }
    
    //EXITING(xmlContainer::load_Element)
}


template<typename XMLIZED, typename ALLOC, template <typename XMLIZED, typename ALLOC> class Cont>
void xmlObject_CV< Cont<XMLIZED,ALLOC> >::copy_Handler(const xmlObject_CV< Cont<XMLIZED,ALLOC> > & origin) {
    myHandler.copy_Handler( origin.myHandler );
    myHandler.xmlName = origin.myHandler.xmlName;
}



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


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


template < uint order , typename XMLIZED , typename ALLOC, typename derivedCLASS, template<typename XMLIZED, typename ALLOC> class Cont >
struct Register_obj <order , Cont<XMLIZED,ALLOC> , derivedCLASS > {
    
    static bool total_registration(list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) {
        if( registerNames.size() != order )
            cerr<<"ERROR in function Register_obj <"<<order<<" , Cont<XMLIZED,ALLOC> , derivedCLASS >::total_registration (list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) : the list registerNames must have the same size as the value of 'order' "<<endl;
        
        
        //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <"<<order<<" , Cont<XMLIZED,ALLOC> , XMLIZED >::total_registration is registering NAME:"<<endl;
        //cerr<<registerNames.front()<<endl;
        
        //auto-registration of the type of the handler (that is, XMLIZED) :
        Register_obj <1 , Cont<XMLIZED,ALLOC> , 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_CV< Cont<XMLIZED,ALLOC> > * xmlobj) {
        
        //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <"<<order<<" , Cont<XMLIZED,ALLOC> , XMLIZED >::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, we can only give a registration name to the contained objects, of type XMLIZED.
//	Thus, if derivedCLASS != XMLIZED , the code produces an execution error !
//*************


template < typename XMLIZED, typename ALLOC, typename derivedCLASS, template<typename XMLIZED, typename ALLOC> class Cont >
struct Register_obj <1 , Cont<XMLIZED,ALLOC> , derivedCLASS > {
    
    static bool total_registration(list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) {
        cerr<<"ERROR in function Register_obj <1 , Cont<XMLIZED,ALLOC> , derivedCLASS >::total_registration (list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) :  At order 1, the container is only registrable over type derivedCLASS = XMLIZED , our chosen convention to register the NAME of the contained objects."<<endl;
        return false;
    }
    
    static bool last_step_registration( std::string registerName , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) {
        cerr<<"ERROR in function Register_obj <1 , Cont<XMLIZED,ALLOC> , derivedCLASS >::last_step_registration (list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) :  At order 1, the container is only registrable over type derivedCLASS = XMLIZED , our chosen convention to register the NAME of the contained objects."<<endl;
        return false;
    }
    
};

//EXCEPT for the case derivedCLASS == XMLIZED : REGISTER THE NAME OF THE CONTAINED XMLIZED OBJECTS.

template < typename XMLIZED, typename ALLOC, template<typename XMLIZED, typename ALLOC> class Cont >
struct Register_obj <1 , Cont<XMLIZED,ALLOC> , XMLIZED > {
    
    static bool total_registration(list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) {
        if( registerNames.size() != 1 )
            cerr<<"ERROR in function Register_obj <1 , Cont<XMLIZED,ALLOC> , XMLIZED >::total_registration (list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) : the list registerNames must have the same size as the order of the macro (that is, 1) !"<<endl;
        
        
        if(xmlobj->myHandler.xmlName !="") {
            cerr<<"ERROR in function Register_obj <1 , Cont<XMLIZED,ALLOC> , XMLIZED >::total_registration (list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) : the name for the contained object has already been registered once ! Ancient registration name is kept."<<endl;
            return false;
        }
        
        //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <1 , Cont<XMLIZED,ALLOC> , XMLIZED >::total_registration is registering NAME:"<<endl;
        //cerr<<registerNames.front()<<endl;
        
        xmlobj->myHandler.xmlName = registerNames.front();
        return true;
        
    }
    
    static bool last_step_registration( std::string registerName , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) {
        
        if(xmlobj->myHandler.xmlName !="") {
            cerr<<"ERROR in function Register_obj <1 , Cont<XMLIZED,ALLOC> , XMLIZED >::total_registration (list<string> registerNames , xmlObject_CV< Cont<XMLIZED,ALLOC> > * xmlobj) : the name for the contained object has already been registered once ! Ancient registration name is kept."<<endl;
            return false;
        }
        
        //cerr<<"YOOOOOOOOOOOOOO ! function Register_obj <1 , Cont<XMLIZED,ALLOC> , XMLIZED >::last_step_registration is registering NAME:"<<endl;
        //cerr<<registerName<<endl;
        
        xmlobj->myHandler.xmlName = registerName;
        return true;
        
    }
    
};


#endif
