#include <xml_object_base.h>


xmlObject_base::xmlObject_base() : fatherSpace(0) ,  wrapped_noType(0) , isLoaded(false) {}

xmlObject_base::xmlObject_base(string name):  xmlName(name) , fatherSpace(0) , wrapped_noType(0) , isLoaded(false) {}


//Must destroy created xmlObjects, and also all parameter registeries...

xmlObject_base::~xmlObject_base()
{
  for(TypeMap::iterator it = my_paramHandlers.begin() ; it!=my_paramHandlers.end() ; ++it)
    delete (*it).second;
  delete_recursive();
}



void xmlObject_base::add_childSpace( xmlObject_base * newChild )
{
  childSpace.push_back(newChild);
  toDelete.push_back(newChild);
}

void xmlObject_base::add_toDelete( xmlObject_base * newObj )
{
  toDelete.push_back(newObj);
}

void xmlObject_base::delete_recursive()
{
  while (toDelete.size())
  {
    delete toDelete[0];
    toDelete.erase ( toDelete.begin() );
  }
}

//Non-virtual saving/loading functions :


void xmlObject_base::save_XML(xmlpp::Node* father_node)
{
  //ENTERING_NODE(xmlObject_base::save_XML, father_node)
  xmlpp::Element* saveHere=make_child_Element(father_node );
  save_Element(saveHere);
}


void xmlObject_base::load_XML(xmlpp::Node* father_node)
{
  //ENTERING_NODE(xmlObject_base::load_XML, father_node)
  if(isLoaded)
  {
    cerr<<"WARNING in function xmlObject_base::load_XML(): You were trying to load the object <"<<xmlName<<"> for the second time. First loaded version will be kept."<<endl;
    return;
  }

  list<xmlpp::Element*> relevEl = get_load_List (father_node );

  if(relevEl.size()>1)
    cerr<<"WARNING in function xmlObject_base::load_XML: node <"<<father_node->get_name()<<"> has more than one child element called <"<<xmlName<<">. Only the first node will be taken into account."<<endl;
  while(relevEl.size()>1)
    relevEl.pop_back();

  if( relevEl.size() )	this->load_Element(relevEl.front() );

  isLoaded=true;
}


//The sub-routines (three of whom are virtual functions)


xmlpp::Element* xmlObject_base::make_child_Element (xmlpp::Node* father_node)
{
  xmlpp::Node* saveHere=father_node;
  if( xmlName !="") saveHere=father_node->add_child( xmlName );
  xmlpp::Element* res = dynamic_cast<xmlpp::Element*>(saveHere);
  if(!res)
  {
    cerr<<"ERROR in make_child_Element: node <"<<father_node->get_name()<<"> is not an xmlpp::Element, as it should be to be able to continue the saving procedure."<<endl;
    exit(0);
  }
  return res;
}



void xmlObject_base::save_Element(xmlpp::Element* the_element)
{
  //ENTERING_NODE(xmlObject_base::save_Element, the_element)
  //Saving all registered parameters
  for(TypeMap::iterator it = my_paramHandlers.begin() ; it!=my_paramHandlers.end() ; ++it)
    (*it).second->save_Attributes(the_element);

  //Saving all children xmlObject_base:
  for(uint i=0;i<childSpace.size();++i)
    childSpace[i]->save_XML(the_element);
}



list<xmlpp::Element*> xmlObject_base::get_load_List (xmlpp::Node* father_node)
{
  //ENTERING(get_load_List_REGULAR_VERSION)
  list<xmlpp::Element*> res;
  if( xmlName !="") res= get_Element_children(father_node, xmlName );
  else
  {
    xmlpp::Element* father = dynamic_cast<xmlpp::Element*>(father_node);
    if(!father)
    {
      cerr<<"ERROR in get_load_List: node <"<<father_node->get_name()<<"> is not an xmlpp::Element, as it should be to be able to continue the loading procedure, since it has a child element with name \"\", that must be saved from node <"<<father_node->get_name()<<"> itself."<<endl;
      exit(0);
    }
    res.push_back(father);
  }
  return res;
}



void xmlObject_base::load_Element(xmlpp::Element* the_element)
{
  //ENTERING_NODE(xmlObject_base::load_Element, the_element)
  list<xmlpp::Attribute*> childrenAttr=the_element->get_attributes();
 	 
  //cout<<"size of attribute list : "<<childrenAttr.size()<<endl;
  //cout<<"size of my_paramHandlers : "<<my_paramHandlers.size()<<endl;
  //Loading all registered parameters
  for(TypeMap::iterator it = my_paramHandlers.begin() ; it!=my_paramHandlers.end() ; ++it)
    (*it).second->load_Attributes(childrenAttr);

  
  //Warning if there are useless remaining attributes. Warning works only if the object has a non-null name.
  if ( (childrenAttr.size()!=0) && (xmlName != "") )
  {
    cerr<<"WARNING in xmlObject_base::load_Element() at node  <"<<the_element->get_name()<<">. You are using the following USELESS attributes:"<<endl;
    for( list<xmlpp::Attribute*>::iterator ut = childrenAttr.begin(); ut != childrenAttr.end() ; ut++ )
      cerr<<(*ut)->get_name()<<"=\""<<(*ut)->get_value()<<"\""<<endl;

    cerr<<"This probably means that you have spelling errors in your XML file, or that your XML file is not up-to-date with the programs!!"<<endl;
  }

  //Recursively loading children xmlObject_base objects
  for(uint i=0;i<childSpace.size();++i)
    childSpace[i]->load_XML(the_element);

  //EXITING(xmlObject_base::load_Element)
}

//for practical reasons (not build a .o file with just ONE function), we prefer to put this one HERE:

void xmlParam::delete_structure()
{
  for(uint i=0;i<xmlObject_base::static_toDelete.size();++i)
    delete xmlObject_base::static_toDelete[i];
}


//...and of course the static variables initialisation:

vector<xmlObject_base*> xmlObject_base::static_toDelete = vector<xmlObject_base*>();

std::map< void * , xmlObject_base *> xmlObject_base::reverseMap = std::map< void * , xmlObject_base *>();

