/*
** This file is part of the ViTE project.
**
** This software is governed by the CeCILL-A license under French law
** and abiding by the rules of distribution of free software. You can
** use, modify and/or redistribute the software under the terms of the
** CeCILL-A license as circulated by CEA, CNRS and INRIA at the following
** URL: "http://www.cecill.info".
**
** As a counterpart to the access to the source code and rights to copy,
** modify and redistribute granted by the license, users are provided
** only with a limited warranty and the software's author, the holder of
** the economic rights, and the successive licensors have only limited
** liability.
**
** In this respect, the user's attention is drawn to the risks associated
** with loading, using, modifying and/or developing or reproducing the
** software by the user in light of its specific status of free software,
** that may mean that it is complicated to manipulate, and that also
** therefore means that it is reserved for developers and experienced
** professionals having in-depth computer knowledge. Users are therefore
** encouraged to load and test the software's suitability as regards
** their requirements in conditions enabling the security of their
** systems and/or data to be ensured and, more generally, to use and
** operate it in the same conditions as regards security.
**
** The fact that you are presently reading this means that you have had
** knowledge of the CeCILL-A license and that you accept its terms.
**
**
** ViTE developers are (for version 0.* to 1.0):
**
**        - COULOMB Kevin
**        - FAVERGE Mathieu
**        - JAZEIX Johnny
**        - LAGRASSE Olivier
**        - MARCOUEILLE Jule
**        - NOISETTE Pascal
**        - REDONDY Arthur
**        - VUCHENER Clément
**
*/

#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
