#ifndef  SERIALIZER_STRUCTS
#define  SERIALIZER_STRUCTS


#include "trace/Serializer.hpp"

#include <limits>
#include <float.h>
#include "trace/Entitys.hpp"
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <trace/Serializer.hpp>


using namespace std;

 // Serialization functions for All Entitys : Links, Events, States, StateChanges and Variables


        using namespace boost::serialization;


    //Entity serialization methods

    /* BOOST_SERIALIZATION_SPLIT_FREE(Entity)//we have 2 functions (load/save) instead of one serialize


    template<class Archive>
    void save(Archive &ar,const Entity& l, const unsigned int )
    {
        int uid=Serializer<Container>::Instance().getUid(l.get_container());
        ar & uid;
        std::map<std::string, Value *>* opt =l.get_extra_fields();
        ar & opt;

    }


        template<class Archive>
    void load(Archive &ar, Entity& l, const unsigned int )
    {

        const Container                *_container;
        std::map<std::string, Value *>* _extra_fields;
        int cont_uid;


        ar & cont_uid;
        _container = Serializer<Container>::Instance().getValue(cont_uid);
        ar & _extra_fields;

        if(_extra_fields==NULL){
            std::map<std::string, Value *> t;
            _extra_fields=&t ; //dirty because this will be discarded in the constructor ...
        }
        new(&l) Entity(_container, *_extra_fields); //sets the value in the object pointed by l
    }

    BOOST_SERIALIZATION_ASSUME_ABSTRACT(Entity);//this type can be inherited by other serialized classes

    */

    //Link serialization methods

    BOOST_SERIALIZATION_SPLIT_FREE(Link)

        template<class Archive>
         void save(Archive & ar, const Link& l, const unsigned int)
    {

        //ar & boost::serialization::base_object<Entity>(l);
        int uid=Serializer<Container>::Instance().getUid(l.get_container());
        ar & uid;
        const std::map<std::string, Value *>* _extra_fields=l.get_extra_fields();
        ar & _extra_fields;
        Date         _start=l.get_start_time();
        ar & _start;
                Date         _end=  l.get_end_time();
        ar & _end;
        uid=Serializer<EntityType>::Instance().getUid(l.get_type());
        ar & uid;
        //const EntityValue * v= l.get_value();
        // printf("value : %p\n", v);
        //ar & v;
        uid=Serializer<EntityValue>::Instance().getUid(l.get_value());
        ar & uid;
        uid=Serializer<Container>::Instance().getUid(l.get_source());
        ar & uid;
        uid=Serializer<Container>::Instance().getUid(l.get_destination());
        ar & uid;

    }

     template<class Archive>
    void load(Archive & ar, Link& l, const unsigned int)
    {
        static std::map<std::string, Value *>* _extra_fields_empty =new std::map<std::string, Value *>();
        const Container                     *_container;
        const std::map<std::string, Value *>* _extra_fields;
        Date         _start, _end;
        const LinkType    *_type;
        const EntityValue *_value;
        const Container   *_source, *_destination;
        /*ar & boost::serialization::base_object<Entity>(l);
        _container=l.get_container(); //TODO : avoid doing that .. do not use Entitys ?
        _extra_fields=l.get_extra_fields();*/
        int cont_uid;
        ar & cont_uid;
        _container = Serializer<Container>::Instance().getValue(cont_uid);
        ar &_extra_fields;


        ar & _start;
        ar & _end;

        int uid;
        ar & uid;
        _type=(const LinkType*)Serializer<EntityType>::Instance().getValue(uid);
       // ar & _value;
        ar & uid;
        _value=(const EntityValue*)Serializer<EntityValue>::Instance().getValue(uid);
        ar & uid;
        _source=Serializer<Container>::Instance().getValue(uid);
        ar & uid;
        _destination=Serializer<Container>::Instance().getValue(uid);
        if(_extra_fields==NULL){
            _extra_fields=_extra_fields_empty ; //dirty because this will be discarded in the constructor ...
        }
        new(&l)Link(_start, _end, const_cast<LinkType*>(_type),const_cast<Container*>(_container), const_cast<Container*>(_source),const_cast<Container*>(_destination), const_cast<EntityValue*>(_value),* const_cast<std::map<std::string, Value *>* >(_extra_fields));
    }



    //State serialization methods


      BOOST_SERIALIZATION_SPLIT_FREE(State)

        template<class Archive>
         void save(Archive & ar, const State& l, const unsigned int)
    {

        //ar & boost::serialization::base_object<Entity>(l);
        int uid=Serializer<Container>::Instance().getUid(l.get_container());
        ar & uid;

        const std::map<std::string, Value *>* _extra_fields=l.get_extra_fields();
        ar & _extra_fields;

        Date d=l.get_start_time();
        ar & d;
        Date d2= l.get_end_time();
        ar & d2;
        uid=Serializer<EntityType>::Instance().getUid(l.get_type());
        ar & uid;
        //const EntityValue * v= l.get_value();
        // printf("value : %p\n", v);
        //ar & v;
        uid=Serializer<EntityValue>::Instance().getUid(l.get_value());
        ar & uid;


    }

     template<class Archive>
    void load(Archive & ar, State& l, const unsigned int)
    {

        static std::map<std::string, Value *>* _extra_fields_empty =new std::map<std::string, Value *>();
        const Container                     *_container;
        const std::map<std::string, Value *>* _extra_fields;
        Date         _start, _end;
        const StateType    *_type;
        const EntityValue *_value;

        /*ar & boost::serialization::base_object<Entity>(l);
        _container=l.get_container(); //TODO : avoid doing that .. do not use Entitys ?
        _extra_fields=l.get_extra_fields();*/
        int cont_uid;
        ar & cont_uid;
        _container = Serializer<Container>::Instance().getValue(cont_uid);
        ar &_extra_fields;


        ar & _start;
        ar & _end;
        int uid;
        ar & uid;
        _type=(const StateType*)Serializer<EntityType>::Instance().getValue(uid);
        //ar & _value;
        ar & uid;
        _value=(const EntityValue*)Serializer<EntityValue>::Instance().getValue(uid);
        if(_extra_fields==NULL){
            _extra_fields=_extra_fields_empty ; //dirty because this will be discarded in the constructor ...
        }
        new(&l)State(_start, _end, const_cast<StateType*>(_type), const_cast<Container*>(_container),const_cast<EntityValue*>(_value),* const_cast<std::map<std::string, Value *>* >(_extra_fields));
    }



    //StateChange serialization methods

    BOOST_SERIALIZATION_SPLIT_FREE(StateChange)

                template<class Archive>
         void save(Archive & ar, const StateChange& l, const unsigned int)
    {
        const State* s= l.get_left_state();
        ar & s;
        const State* s2=l.get_right_state();
        ar & s2;
        Date d=l.get_time();
        ar & d;
    }

     template<class Archive>
    void load(Archive & ar, StateChange& l, const unsigned int)
    {

        Date         _time;
        State* _right;
        State* _left;

       ar & _left;
       ar & _right;
       ar & _time;
        new(&l)StateChange(_time, _left, _right);
    }


        //Variable serialization methods

        BOOST_SERIALIZATION_SPLIT_FREE(Variable)

                template<class Archive>
         void save(Archive & ar, const Variable& l, const unsigned int)
    {
        //ar & boost::serialization::base_object<Entity>(l);
        const std::map<std::string, Value *>* _extra_fields=l.get_extra_fields();
        int uid=Serializer<Container>::Instance().getUid(l.get_container());
        ar & uid;
        ar & _extra_fields;


        const std::list<std::pair<Date, Double> >* d= l.get_values();
        ar & d;
        uid=Serializer<EntityType>::Instance().getUid(l.get_type());
        ar & uid;
    }

     template<class Archive>
    void load(Archive & ar, Variable& l, const unsigned int)
    {
        const Container                     *_container;
        const std::map<std::string, Value *>* _extra_fields;
        std::list<std::pair<Date, Double> > *_values;
        Double _min, _max;
        const VariableType *_type;

        /*ar & boost::serialization::base_object<Entity>(l);
        _container=l.get_container(); //TODO : avoid doing that .. do not use Entitys ?
        _extra_fields=l.get_extra_fields();*/
        int cont_uid;
        ar & cont_uid;
        _container = Serializer<Container>::Instance().getValue(cont_uid);
        ar &_extra_fields;

        ar & _values;

        int uid;
        ar & uid;
        _type=(const VariableType*)Serializer<EntityType>::Instance().getValue(uid);
        new(&l)Variable(const_cast<Container*>(_container), const_cast<VariableType*>(_type));

        std::list<std::pair<Date, Double> >::const_iterator it_end=_values->end();
        for(std::list<std::pair<Date, Double> >::iterator it=_values->begin(); it!=it_end;it++){
            l.add_value((*it).first,(*it).second);//add children
        }
    }

    BOOST_SERIALIZATION_SPLIT_FREE(Event)


     template<class Archive>
        void save(Archive &ar, const Event& l, const unsigned int)
    {
        //ar & boost::serialization::base_object<Entity>(l);
        const std::map<std::string, Value *>* _extra_fields=l.get_extra_fields();
        int uid=Serializer<Container>::Instance().getUid(l.get_container());
        ar & uid;
        ar & _extra_fields;


        Date t=l.get_time();
        ar & t;
        uid=Serializer<EntityType>::Instance().getUid(l.get_type());
        ar & uid;
        //const EntityValue * v= l.get_value();
        // printf("value : %p\n", v);
        //ar & v;
        uid=Serializer<EntityValue>::Instance().getUid(l.get_value());
        ar & uid;
    }
         template<class Archive>
    void load(Archive & ar, Event& l, const unsigned int)
    {
        static std::map<std::string, Value *>* _extra_fields_empty =new std::map<std::string, Value *>();
        const Container                     *_container;
        const std::map<std::string, Value *>* _extra_fields;
        /*ar & boost::serialization::base_object<Entity>(l);
        _container=l.get_container(); //TODO : avoid doing that .. do not use Entitys ?
        _extra_fields=l.get_extra_fields();*/
        int cont_uid;
        ar & cont_uid;
        _container = Serializer<Container>::Instance().getValue(cont_uid);
        ar &_extra_fields;

        Date _time;
        const EventType* _type;
        const EntityValue * _value;
        ar & _time;
        //ar & _type;
        int uid;
        ar & uid;
        _type=(const EventType*)Serializer<EntityType>::Instance().getValue(uid);
        //ar & _value;
        ar & uid;
        _value=(const EntityValue*)Serializer<EntityValue>::Instance().getValue(uid);
        if(_extra_fields==NULL){
            _extra_fields=_extra_fields_empty ; //dirty because this will be discarded in the constructor ...
        }


        new(&l)Event(_time, const_cast<EventType*>(_type), const_cast<Container*>(_container),const_cast<EntityValue*>( _value), * const_cast<std::map<std::string, Value *>* >(_extra_fields));


    }

#endif
