/**
 *
 * @file src/trace/Serializer_container.hpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Augustin Degomme
 * @author Thibault Soucarre
 *
 * @date 2024-07-17
 */
#ifndef SERIALIZER_CONTAINER
#define SERIALIZER_CONTAINER

#include "trace/IntervalOfContainer.hpp"

#include <limits>
#include <float.h>
#include "trace/Entitys.hpp"
#include "trace/Container.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>

#include "trace/Serializer_values.hpp"
#include "trace/Serializer_types.hpp"
#include "trace/Serializer_structs.hpp"

// Container serialization methods
BOOST_SERIALIZATION_SPLIT_FREE(::Container)

template <class Archive>
void save(Archive &ar, const ::Container &l, const unsigned int) {
    Name _name = l.get_name();
    ar &_name;
    Date _creation_time = l.get_creation_time();
    ar &_creation_time;
    Date _destruction_time = l.get_destruction_time();
    ar &_destruction_time;
    int type_uid = Serializer<ContainerType>::Instance().getUid(l.get_type());
    ar &type_uid;
    const Container *_parent = l.get_parent();
    ar &_parent;

    int _uid = Serializer<::Container>::Instance().getUid(&l);
    ar &_uid;
    // size of the _intervalsOfContainer array;
    int i = l.get_intervalsOfContainer()->size();
    // printf("nb itc dans %s : %d\n", _name.to_string().c_str(), i);
    ar &i;
    // start and stop time of each one of the itc
    std::list<IntervalOfContainer *>::const_iterator it_end1 = l.get_intervalsOfContainer()->end();
    for (std::list<IntervalOfContainer *>::const_iterator it = l.get_intervalsOfContainer()->begin();
         it != it_end1;
         it++) {
        Date d = (*it)->get_beginning();
        ar &d;
        Date d2 = (*it)->get_end();
        ar &d2;
        // printf("on sauve %lf et %lf de %s\n", d.get_value(), d2.get_value(), _name.to_string().c_str());
        std::map<EntityValue *, double> *t = (*it)->get_states_values_map();
        ar &t;
    }

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

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

    Name _name;
    Date _creation_time;
    Date _destruction_time;
    const ContainerType *_type;
    Container *_parent;
    ::Container::Vector *_children;

    std::map<std::string, Value *> *_extra_fields;

    std::list<IntervalOfContainer *> _intervalsOfContainer;
    ar &_name;
    ar &_creation_time;
    ar &_destruction_time;
    int type_uid;
    ar &type_uid;
    _type = Serializer<ContainerType>::Instance().getValue(type_uid);
    ar &_parent;
    int _uid;
    ar &_uid;
    Serializer<Container>::Instance().setUid(_uid, &l);
    int itc_size = 0;
    ar &itc_size;
    if (itc_size != 0) {
        // start and stop time of each one of the it
        for (int i = 0; i < itc_size; i++) {
            IntervalOfContainer *itc = new IntervalOfContainer();
            itc->_loaded = 0;
            ar & itc->_beginning;
            ar & itc->_end;
            ar & itc->_states_values_map;

            if (itc->_beginning < Info::Entity::x_min)
                Info::Entity::x_min = itc->_beginning.get_value();
            if (itc->_end > Info::Entity::x_max)
                Info::Entity::x_max = itc->_end.get_value();
            _intervalsOfContainer.push_back(itc);
        }
    }

    ar &_extra_fields;
    new (&l) Container(_name, _creation_time, const_cast<ContainerType *>(_type), _parent, *_extra_fields);
    l.set_intervalsOfContainer(&_intervalsOfContainer);

    ar &_children;
    ::Container::VectorIt it = _children->begin();
    ::Container::VectorIt it_end = _children->end();
    for (; it != it_end; it++) {
        l.add_child(*it);
    }
}

#endif
