#ifndef SAMPLE_XML_CLASSES_H
#define SAMPLE_XML_CLASSES_H

#include<xml_parameters.h>
#include<math.h>


//******************************** Here are the 'people' classes **************************
//*****************************************************************************************


class Person : virtual public xmlClass
{
  //parameters:
  int age;
  string name;

protected:
  //other variables...
  string presentationPhrase;
  //...and the possibility to initialize them from the set of parameters:
  virtual void make_presentationPhrase()
  {
    ostringstream ost;
    ost<<"Hi, my name is "<<name<<" and I am "<<age<<" years old.";
    presentationPhrase = ost.str();
  }

public:
  Person()
  {
    age=0;
    name="";
    presentationPhrase="";
  }
  virtual ~Person(){}

  void say_Hi(void)
  {
    if(presentationPhrase=="") make_presentationPhrase();
    cout<<presentationPhrase<<endl;
  }


  //**********************************************
  //This is the ' XML_IZE ' part you have to add:
  const type_info & get_pointer_typeid ()
  {
    return typeid ( this ) ;
  }

  void xml_ize()
  {
    xmlClass::add_param(age,"age");
    xmlClass::add_param(name,"name");
  }

  //**********************************************


  void generate()
  {
    age=(int)floor((double)rand()/RAND_MAX*100);
    name="";
    int nLetters=1+(int)floor((double)rand()/RAND_MAX*10);
    for(int i=0;i<nLetters;++i)
    {
      name.push_back((char)(97+floor((double)rand()/RAND_MAX*26))); //lettre au hasard entre a et z
    }
  }

};

class NiceGuy: public Person
{
protected:
  void make_presentationPhrase()
  {
    Person::make_presentationPhrase();
    presentationPhrase+=" How are you? Care for "+to_offer+"? ";
  }

public:
  string to_offer;

  NiceGuy() : Person()
  {
    to_offer="";
  }
  ~NiceGuy(){}


  //**********************************************
  //This is the ' XML_IZE ' part you have to add:
  //const type_info & get_pointer_typeid ()
  //{
  //   return typeid ( this ) ;
  //}

  //void xml_ize()

  //or you can just write:
  XML_IZE_MACRO
  {
    Person::xml_ize();
    xmlClass::add_param(to_offer,"what-I-offer");
  }
  //**********************************************


};


class RudeGuy: public Person
{
protected:

  virtual void make_presentationPhrase()
  {
    Person::make_presentationPhrase();
    presentationPhrase+=" Now, why don't you "+insult+"? ";
  }

public:
  string insult;

  RudeGuy() : Person()
  {
    insult="";
  }

  //**********************************************
  //This is the ' XML_IZE ' part you have to add:
  XML_IZE_MACRO
  {
    Person::xml_ize();
    xmlClass::add_param(insult,"my-insult");
  }
  //**********************************************


  ~RudeGuy(){}}
;



//******************************** Here are the 'animal' classes **************************
//*****************************************************************************************


struct Animal : virtual public xmlClass
{
  string yell;
  Animal() : yell("") {}
  virtual ~Animal(){}
  void say_Hi() {cout<<yell<<endl;}

};

struct Dog : public Animal
{
  Dog() {}

  //**********************************************
  //This is the ' XML_IZE ' part you have to add:
  XML_IZE_MACRO
  {
    xmlClass::add_param(yell,"bark");
  }
  //**********************************************

  ~Dog(){}}
;

struct Cat : public Animal
{
  Cat() {}

  //**********************************************
  //This is the ' XML_IZE ' part you have to add:
  XML_IZE_MACRO
  {
    xmlClass::add_param(yell,"mew");
  }
  //**********************************************

  ~Cat(){}}
;



//******************************** And here is the bus ! **************************
//*********************************************************************************



struct Bus : virtual public xmlClass
{

  int capacity;
  NiceGuy myself; //Of course!!!

  Person *driver;
  vector<Person*> people;

  //and well... there can be, sometimes, an animal trailer, or not!
  vector<Animal*> *animal_trailer;

public:
  Bus()
  {
    capacity=4;
    //Make sure that all uninitialized pointers loadable from XML are explicitely set to 0 ! Otherwise, probable segfault.
    driver=0;
    animal_trailer=0;
  }


  //**********************************************
  //This is the ' XML_IZE ' part you have to add:
  //just for change, here, we dont use the macro ;-)

  const type_info & get_pointer_typeid ()
  {
    return typeid ( this ) ;
  }

  void xml_ize()
  {
    xmlClass::add_param(capacity,"capacity");

    xmlClass::add_child(myself, "me");

    xmlClass::add_child(driver, "driver");
    xmlRegister<1,NiceGuy>(driver,"polite");
    xmlRegister<1,RudeGuy>(driver,"unpolite");

    xmlClass::add_child(people, "people");
    xmlRegister<2,Person>(people, xml_names("","shy-guy") );
    xmlRegister<2,NiceGuy>(people,"nice-guy");
    xmlRegister<2,RudeGuy>(people,"rude-guy");

    xmlClass::add_child(animal_trailer, "");
    xmlRegister<3,Dog>( animal_trailer,xml_names("animal-trailer","","dog") );
    xmlRegister<3,Cat>( animal_trailer, "cat" );
  }
  //**********************************************

  ~Bus(){}

  void everybody_say_Hi(void)
  {
    cout<<"-myself : "<<endl;
    myself.say_Hi();
    if(driver)
    {
      cout<<"-driver : "<<endl;
      driver->say_Hi();
    }
    for(uint i=0;i<people.size();++i)
    {
      cout<<"-passenger number "<<i+1<<" : "<<endl;
      people[i]->say_Hi();
    }
    if(driver)
      if((int)(1+people.size()) > capacity)
        cout<<"-driver : "<<endl<<"There are too many of you. Rude guys, get off!!!"<<endl;


    int count=0;
    if(animal_trailer)
      for(uint i=0;i<animal_trailer->size();++i)
      {
        cout<<"-animal number "<<++count<<" : "<<endl;
        (*animal_trailer)[i]->say_Hi();
      }


  }

  void empty()
  {
    if(driver) delete driver;
    for(uint i=0;i<people.size(); ++i)
      if(people[i]) delete people[i];
    people=vector<Person*>();
    //We keep the animals if they exist... whatever!
  }

  void generate()
  {
    empty();

    myself.generate();

    if((double)rand()/RAND_MAX<0.5)
    {
      driver = new RudeGuy();
      driver->generate();
      dynamic_cast<RudeGuy*>(driver)->insult="pay me your ticket, you little swine";
    }
    else driver=0;

    int nPeople=(int)floor((double)rand()/RAND_MAX*6);
    for(int i=0;i<nPeople;++i)
    {
      double rnd=(double)rand()/RAND_MAX;
      if(rnd<0.33)
        people.push_back(new Person());
      else if(rnd<0.66)
        people.push_back(new NiceGuy());
      else
        people.push_back(new RudeGuy());
      people[i]->generate();
    }
  }

};

#endif



