/**
 *
 * @file src/trace/IntervalOfContainer.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 INTERVALOFCONTAINER_HPP
#define INTERVALOFCONTAINER_HPP

#define N_EVENTS_PER_INTERVAL 10000
#include <iostream>
#include <string>
#include <map>
#include <list>
#include <vector>
#include <stack>
#include <algorithm>
#ifdef BOOST_SERIALIZE
#include <boost/serialization/split_member.hpp>
#endif
#include "stdio.h"

#include "trace/values/Values.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"

#include "trace/Serializer_values.hpp"
#include "trace/Serializer_structs.hpp"
typedef struct IntervalOfContainer
{

    // Defines if the interval is loaded into memory or stored inside a file (yes=in memory, no=out of core)
    bool _loaded;
    // Time Interval
    Date _beginning;
    Date _end;
    // Statechanges in this ITC
    StateChange *_statechanges;
    // number of StateChanges in this ITC
    int _n_statechanges;
    // States in this ITC
    State *_states;
    // number of States in this ITC
    int _n_states;

    // aggregated value of each one of the values in the chunk. For preview purpose
    std::map<EntityValue *, double> *_states_values_map;

    // Events in this ITC
    Event *_events;
    // number of Events in this ITC
    int _n_events;

    // Links in this ITC
    Link *_links;
    // number of Links in this ITC
    int _n_links;

    // variables in this ITC
    Variable *_variables;
    // number of variables in this ITC
    int _n_variables;

public:
    /*!
     * \brief Constructor
     */
    IntervalOfContainer();

    /*!
     * \brief Destructor
     */
    ~IntervalOfContainer();

    /*!
     * \fn get_beginning() const
     * \brief Get the beginning Date of the ITC
     */
    Date get_beginning();

    /*!
     * \fn get_end() const
     * \brief Get the end date of the ITC
     */
    Date get_end();

    /*!
     * \fn add_state
     * \brief add a State to the ITC
     * \param start Starting Date of the State
     * \param end Ending Date of the State
     * \param type StateType
     * \param value value of the State
     * \param container Container containing this State
     * \param opt Extra fields
     * \returns a pointer to the State
     */
    State *add_state(Date start, Date end, StateType *type, EntityValue *value, Container *container, std::map<std::string, Value *> opt);

    /*!
     * \fn add_state(Date , State*, State* )
     * \brief add a StateChange to the ITC
     * \param time Date of the StateChange
     * \param left left State
     * \param right right State
     * \return a boolean, true if the StateChange has been successfully added, false if the IntervalOfContainer is full and need to be changed
     */
    bool add_statechange(Date time, State *left, State *right);

    /*!
     * \fn add_event
     * \brief add an Event to the ITC
     * \param time Date of the Event
     * \param type EventType
     * \param value value of the Event
     * \param container Container containing this Event
     * \param opt Extra fields
     */
    void add_event(Date time, EventType *type, Container *cont, EntityValue *value, std::map<std::string, Value *> opt);

    /*!
     * \fn set_variable
     * \brief add a variable to the ITC
     * \param container Container containing this Event
     * \param v VariableType
     */
    void set_variable(Container *container, VariableType *v);

    /*!
     * \fn set_variables
     * \brief add a set of variables to the ITC
     * \param the map of variables to add
     */
    void set_variables(std::map<VariableType *, Variable *> *);

    /*!
     * \fn add_link
     * \brief add a Link to the ITC
     * \param start Starting Date of the Link
     * \param end Ending Date of the Link
     * \param container Container containing this Link
     * \param source source Container
     * \param destination destination Container
     * \param value value of the Event
     * \param opt Extra fields
     */
    bool add_link(Date start, Date end, LinkType *type, Container *container, Container *source, Container *destination, EntityValue *value, std::map<std::string, Value *> opt);

    /*!
     * \fn is_loaded
     * \brief returns the loaded state of the ITC
     */
    bool is_loaded() { return _loaded; }

    /*!
     * \fn get_states_values_map
     * \brief returns the aggregated value of each one of the States in the chunk. For preview purposes.
     */
    std::map<EntityValue *, double> *get_states_values_map();

#ifdef BOOST_SERIALIZE
    /*!
     * \fn unload()
     * \brief unload data from memory without deleting the element and sets its loaded value to false
     */
    void unload();

    /*!
     * \fn dump_on_disk()
     * \brief dump data from the ITC on disk
     * \param filename The file containig the ITC
     * \return true if no error is encountered
     */
    bool dump_on_disk(const char *filename);

    /*!
     * \fn retrieve()
     * \brief retrieve data from a file to the mail memory
     * \param filename The file containig the ITC
     * \return true if no error is encountered
     */
    bool retrieve(const char *filename);

    /*!
     * \fn save()
     * \brief boost serialization function for an ITC
     */
    template <class Archive>
    void save(Archive &ar, const unsigned int) const {

        ar.register_type(static_cast<StateType *>(NULL));
        ar.register_type(static_cast<EventType *>(NULL));
        ar.register_type(static_cast<VariableType *>(NULL));
        ar.register_type(static_cast<LinkType *>(NULL));
        ar.register_type(static_cast<ContainerType *>(NULL));

        ar.register_type(static_cast<EntityValue *>(NULL));
        ar.register_type(static_cast<Color *>(NULL));
        ar.register_type(static_cast<Date *>(NULL));
        ar.register_type(static_cast<Double *>(NULL));
        ar.register_type(static_cast<Hex *>(NULL));
        ar.register_type(static_cast<Integer *>(NULL));
        ar.register_type(static_cast<Name *>(NULL));
        ar.register_type(static_cast<String *>(NULL));

        ar &_beginning;
        // printf("beginning %lf\n", _beginning.get_value());
        ar &_end;
        // printf("end %lf\n", _end.get_value());
        ar &_n_statechanges;
        // printf("_n_statechanges %d\n", _n_statechanges);
        ar &_n_states;
        // printf("_n_states %d\n", _n_states);
        if (_n_statechanges != 0) {
            // for(int i=0; i< _n_statechanges; i++){
            // printf("ceci est un état %d %lf %p\n",i, (_statechanges[i])._time.get_value(), this);
            //	ar & _statechanges[i];

            //	}

            int i = 0;
            QT_TRY {
                for (i = 0; i < _n_states; i++) {
                    ar &_states[i];
                }
            }
            QT_CATCH(...) {
                printf("_states failure ! %d\n", i);
            }

            QT_TRY {
                for (i = 0; i < _n_statechanges; i++) {
                    ar &_statechanges[i];
                }
            }
            QT_CATCH(...) {
                printf("_statechanges failure ! %d\n", i);
            }
            // delete[] _statechanges;
        }
        // printf("states %p\n", this);
        ar &_n_links;
        // printf("_n_links %p\n", this);
        if (_n_links != 0) {
            int i = 0;
            QT_TRY {
                for (i = 0; i < _n_links; i++)
                    ar &_links[i];
            }
            QT_CATCH(...) {
                printf("_links failure ! %d\n", i);
            }

            //  delete _links;
        }
        // printf("links %p\n", this);
        ar &_n_events;
        // printf("_n_events %p\n", this);
        if (_n_events != 0) {
            int i = 0;
            QT_TRY {
                for (i = 0; i < _n_events; i++)
                    ar &_events[i];
            }
            QT_CATCH(...) {
                printf("_events failure ! %d\n", i);
            }
            // for(int i=0; i< _n_events; i++)
            // ar & _events[i];
            // delete _events;
        }
        // printf("events %p\n", this);
        ar &_n_variables;
        // printf("_n_variables %p\n", this);
        if (_n_variables != 0) {
            // printf("saving %d vars from %lf %lf\n", _n_variables, _beginning.get_value(), _end.get_value());
            // for(int i=0; i< _n_variables; i++)
            // ar & _variables[i];
            int i = 0;
            QT_TRY {
                for (i = 0; i < _n_variables; i++)
                    ar &_variables[i];
            }
            QT_CATCH(...) {
                printf("_variables failure ! %d\n", i);
            }
            // delete _events;
        }
        // printf("variables %p\n", this);
    }

    /*!
     * \fn load()
     * \brief boost serialization function for an ITC
     */
    template <class Archive>
    void load(Archive &ar, const unsigned int) {
        ar.register_type(static_cast<StateType *>(NULL));
        ar.register_type(static_cast<EventType *>(NULL));
        ar.register_type(static_cast<VariableType *>(NULL));
        ar.register_type(static_cast<LinkType *>(NULL));
        ar.register_type(static_cast<ContainerType *>(NULL));

        ar.register_type(static_cast<EntityValue *>(NULL));
        ar.register_type(static_cast<Color *>(NULL));
        ar.register_type(static_cast<Date *>(NULL));
        ar.register_type(static_cast<Double *>(NULL));
        ar.register_type(static_cast<Hex *>(NULL));
        ar.register_type(static_cast<Integer *>(NULL));
        ar.register_type(static_cast<Name *>(NULL));
        ar.register_type(static_cast<String *>(NULL));

        ar &_beginning;
        // printf("beg : %lf \n",_beginning.get_value());
        ar &_end;
        // printf("end : %lf \n",_end.get_value());
        ar &_n_statechanges;
        // printf("_n_statechanges : %d \n",_n_statechanges);
        ar &_n_states;
        // printf("_n_states : %d \n",_n_states);

        QT_TRY {
            if (_n_statechanges != 0) {

                int i = 0;
                _states = (State *)malloc(_n_states * sizeof(State));

                for (i = 0; i < _n_states; i++) {

                    ar &_states[i];
                    // printf("i: %d, _name : %s\n", i, _states[i].get_type()->get_name().to_string().c_str());
                }

                // printf("n_links : %d\n", _n_links);
                _statechanges = (StateChange *)malloc(_n_statechanges * sizeof(StateChange));
                for (i = 0; i < _n_statechanges; i++)
                    ar &_statechanges[i];
            }
        }
        QT_CATCH(...) {
            printf("_states failure !\n");
        }

        ar &_n_links;
        if (_n_links != 0) {
            // printf("n_links : %d\n", _n_links);
            _links = (Link *)malloc(_n_links * sizeof(Link));
            for (int i = 0; i < _n_links; i++)
                ar &_links[i];
        }
        ar &_n_events;
        if (_n_events != 0) {
            // printf("n_events : %d\n", _n_events);
            _events = (Event *)malloc(_n_events * sizeof(Event));
            for (int i = 0; i < _n_events; i++)
                ar &_events[i];
        }
        ar &_n_variables;
        if (_n_variables != 0) {
            // printf("loading %d vars from %lf %lf\n", _n_variables, _beginning.get_value(), _end.get_value());
            // printf("n_events : %d\n", _n_events);
            _variables = (Variable *)malloc(_n_variables * sizeof(Variable));
            for (int i = 0; i < _n_variables; i++) {
                ar &_variables[i];
                // printf("loading %lf %lf %d\n",_variables[i]._min.get_value(), _variables[i]._max.get_value(),_variables[i]._values->size() );
            }
        }
    }
    BOOST_SERIALIZATION_SPLIT_MEMBER()
#endif

} IntervalOfContainer;

#endif
