/*
** 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
