/*
 ** 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 TRACE_HPP
#define TRACE_HPP

// #include <map>
// #include <stack>
// #include <list>
// #include "common/common.hpp"

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

class Interval;
class Palette;
class QDomElement;
class QDomDocument;
class QString;
class Name;
/*!
 *
 * \file Trace.hpp
 * \brief This file contains the datas definition for the storage of the trace
 * \date 30 janvier 09
 *
 */
/*!
 *
 * \class Trace
 * \brief This class contains the trace
 *
 */

class Trace {
private:
    Date                       _max_date;
    std::list<ContainerType *> _root_container_types;
    Container::Vector          _root_containers;
    Container::Vector          _view_root_containers;
    std::map<Name, StateType* >     _state_types;
    std::map<Name, EventType* >     _event_types;
    std::map<Name, LinkType* >      _link_types;
    std::map<Name, VariableType* >  _variable_types;

    /*Palette *_palette;
     Palette * _event_types_palette;
     Palette * _link_types_palette;*/
    /*!
     * \brief Set of the containers to be drawn in the partial drawing function
     */
    std::vector<const Container *> * _selected_container;

    /*!
     * \brief Interval to display (without browsing the other data
     */
    Interval * _interval_constrained;
    /*!
     * \brief zoom level
     */
    double _filter;

    /*!
     * \brief Store the depth of the trace. (number of stacked containers).
     */
    int _depth;

    /*!
     * \brief add all the children of parent to the list
     * \param containers the list where we add the children
     * \param parent the parent container
     */

    void add_containers(Container::Vector &containers, const Container *parent) const ;

public :
    Trace();
    ~Trace();

    /*!
     * \brief Define a container type
     * \param alias Name of the container type
     * \param parent_container_type Type of the parent container
     * \param opt Extra fields
     */
    void define_container_type(Name &alias, ContainerType *parent_container_type, std::map<std::string, Value *> &opt);

    /*!
     * \brief Create a container
     * \param time Date of the event
     * \param alias Name of the container
     * \param type Type of the container
     * \param parent Parent of the container (NULL if the container is root)
     * \param opt Extra fields
     */
    Container* create_container(Date &time, Name &alias, ContainerType *type, Container *parent, std::map<std::string, Value *> &opt);

    /*!
     * \brief Destroy a container
     * \param time Date of the event
     * \param cont Container to destroy
     * \param type Type of the container
     * \param opt Extra fields
     */
    void destroy_container(Date &time, Container *cont, ContainerType *type, std::map<std::string, Value *> &opt);


    /*!
     * \brief Define a type of event
     * \param alias Name of the type
     * \param container_type Type of the container for these events
     * \param opt Extra fields
     */
    void define_event_type(Name &alias, ContainerType *container_type, std::map<std::string, Value *> &opt);


    /*!
     * \brief Define a type of state
     * \param alias Name of the type
     * \param container_type Type of the container for these states
     * \param opt Extra fields
     */
    void define_state_type(Name &alias, ContainerType *container_type, std::map<std::string, Value *> &opt);

    /*!
     * \brief Define a type of variable
     * \param alias Name of the type
     * \param container_type Type of the container for these variables
     * \param opt Extra fields
     */
    void define_variable_type(Name &alias, ContainerType *container_type, std::map<std::string, Value *> &opt);


    /*!
     * \brief Define a type of link
     * \param alias Name of the type
     * \param ancestor Type of the ancestor container
     * \param source Type of the source container
     * \param destination Type of the destination container
     * \param opt Extra fields
     */
    void define_link_type(Name &alias, ContainerType *ancestor, ContainerType *source, ContainerType *destination, std::map<std::string, Value *> &opt);


    /*!
     * \brief Define an entity value
     * \param alias Name of the value
     * \param entity_type Type of the entity
     * \param opt Extra fields
     */
    void define_entity_value(Name &alias, EntityType *entity_type, std::map<std::string, Value *> &opt);


    /*!
     * \brief Set the state of a container
     * \param time Date of the event
     * \param type Type of the state
     * \param container Container whose state is changed
     * \param value Value of the state
     * \param opt Extra fields
     */
    void set_state(Date &time, StateType *type, Container *container, EntityValue *value, std::map<std::string, Value *> &opt);

    /*!
     * \brief Set the state of a container and save the previous one
     * \param time Date of the event
     * \param type Type of the state
     * \param container Container whose state is changed
     * \param value Value of the state
     * \param opt Extra fields
     */
    void push_state(Date &time, StateType *type, Container *container, EntityValue *value, std::map<std::string, Value *> &opt);

    /*!
     * \brief Restore a previously saved state of a container
     * \param time Date of the event
     * \param type Type of the state
     * \param container Container whose state is changed
     * \param opt Extra fields
     */
    void pop_state(Date &time, StateType *type, Container *container, std::map<std::string, Value *> &opt);

    /*!
     * \brief Purge a container from all the stacked states
     * \param time Date of the event
     * \param type Type of the state
     * \param container Container whose state is changed
     * \param opt Extra fields
     */
    void reset_state(Date &time, StateType *type, Container *container, std::map<std::string, Value *> &opt);

    /*!
     * \brief Add a new event to a container
     * \param time Date of the event
     * \param type Type of the event
     * \param container Container of the event
     * \param value Value of the event
     * \param opt Extra fields
     */
    void new_event(Date &time, EventType *type, Container *container, EntityValue *value, std::map<std::string, Value *> &opt);

    /*!
     * \brief Set the value of a variable
     * \param time Date of the new value
     * \param type Type of the variable whose value is changed
     * \param container Container of the variable
     * \param value New value of the variable
     * \param opt Extra fields
     */
    void set_variable(Date &time, VariableType *type, Container *container, Double value, std::map<std::string, Value *> &opt);


    /*!
     * \brief Add a value to a variable
     * \param time Date of the new value
     * \param type Type of the variable whose value is changed
     * \param container Container of the variable
     * \param value Value to add
     * \param opt Extra fields
     */
    void add_variable(Date &time, VariableType *type, Container *container, Double value, std::map<std::string, Value *> &opt);


    /*!
     * \brief Substract a value to a variable
     * \param time Date of the new value
     * \param type Type of the variable whose value is changed
     * \param container Container of the variable
     * \param value Value to substract
     * \param opt Extra fields
     */
    void sub_variable(Date &time, VariableType *type, Container *container, Double value, std::map<std::string, Value *> &opt);


    /*!
     * \brief Start a new link identified by key
     * \param time Date of the event
     * \param type Type of the link
     * \param ancestor Ancestor container
     * \param source Source container
     * \param value Value of the link
     * \param key Key to match the end of the link
     * \param opt Extra fields
     */
    void start_link(Date &time, LinkType *type, Container *ancestor, Container *source, EntityValue *value, String key, std::map<std::string, Value *> &opt);

    /*!
     * \brief End a link identified by key
     * \param time Date of the event
     * \param type Type of the link
     * \param ancestor Ancestor container
     * \param destination Destination container
     * \param value Value of the link
     * \param key Key to match the Start of the link
     * \param opt Extra fields
     */
    void end_link(Date &time, LinkType *type, Container *ancestor, Container *destination, EntityValue *value, String key, std::map<std::string, Value *> &opt);

    /*!
     * \fn finish()
     * \brief Finish to initialize the trace
     */
    void finish();

#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
    /*!
     * \fn dump()
     * \brief Finish  by dumping all ITC in the trace
     */
    void dump(std::string path, std::string filename);
#endif

    /*!
     * \fn get_root_containers() const
     * \brief Get the list of the root containers
     */
    const Container::Vector *get_root_containers() const;

    /*!
     * \fn get_view_root_containers() const
     * \brief Get the list of the root containers to be displayed
     */
    const Container::Vector *get_view_root_containers() const;

    /*!
     * \fn set_root_containers()
     * \brief allows to replace the root containers of the trace, to reorder them
     */
    void set_root_containers( std::list<Container*>& conts);

    /*!
     * methods used to rebuild a trace from serialized data
     */
    void set_container_types (std::list<ContainerType*>& conts) ;
    void set_state_types (std::map<Name, StateType* >& conts) ;
    void set_event_types (std::map<Name, EventType* >& conts);
    void set_link_types (std::map<Name, LinkType* >& conts);
    void set_variable_types (std::map<Name, VariableType* >& conts);

    /*!
     * \fn set_max_date()
     * \brief Function that sets the max of the date
     */
    void set_max_date(Date d);

#ifdef BOOST_SERIALIZE
    void updateTrace(Interval* interval);
    /*!
     * \fn loadTraceInside(Interval* i)
     * \brief Load all the data inside the IntervalOfContainers, bounded by interval i
     */
    void loadTraceInside(Interval* i);

    /*!
     * \fn loadPreview(Interval* i)
     * \brief Load the preview
     */
    void loadPreview();
#endif


    /*!
     * \fn set_root_containers()
     * \brief allows to change the view of containers
     */
    void set_view_root_containers( std::list<Container*>& conts);

    /*!
     * \fn get_all_containers(Container::Vector &list_to_fill) const
     * \brief Get the list of all the containers
     * \param list_to_fill the list to fill
     */
    void get_all_containers(Container::Vector &list_to_fill) const;

    /*!
     * \brief Get all the stateTypes
     */
    const std::map<Name, StateType* > *get_state_types() const;

    /*!
     * \brief Get all the eventTypes
     */
    const std::map<Name, EventType*> *get_event_types() const;

    /*!
     * \brief Get all the eventTypes
     */
    const std::map<Name, LinkType*> *get_link_types() const;

    /*!
     * \fn search_container_type(String name) const
     * \brief Search a container type by his name or alias
     */
    ContainerType *search_container_type(String name) const;

    /*!
     * \fn search_container(String name) const
     * \brief Search a container by his name or alias
     */
    Container *search_container(String name) const;

    /*!
     * \fn search_event_type(String name) const
     * \brief Search a event type by his name or alias
     */
    EventType *search_event_type(String name) const;


    /*!
     * \fn search_state_type(String name) const
     * \brief Search a container by his name or alias
     */
    StateType *search_state_type(String name) const;


    /*!
     * \fn search_variable_type(String name) const
     * \brief Search a variable type by his name or alias
     */
    VariableType *search_variable_type(String name) const;


    /*!
     * \fn search_link_type(String name) const
     * \brief Search a container by his name or alias
     */
    LinkType *search_link_type(String name) const;

    /*!
     * \fn search_entity_type(String name) const
     * \brief Search an entity type by his name or alias
     */
    EntityType *search_entity_type(String name) const;

    /*!
     * \fn search_entity_value(String name,  EntityType *entity_type) const
     * \brief Search an entity value by his name or alias
     */
    EntityValue *search_entity_value(String name,  EntityType *entity_type) const;

    /*!
     * \fn get_max_date()
     * \brief Function that return the max of the date
     */
    Date get_max_date();

    /*!
     * \fn get_depth()
     * \brief Return the depth of the trace. Trace loading MUST be completed!
     */
    int get_depth();

    // Set
    void set_selected_container  (std::vector<const Container *> *);
    void set_interval_constrained(Interval *);
    void set_filter              (double);
    // Get
    std::vector<const Container *> *get_selected_container();
    Interval                       *get_interval_constrained();
    double                          get_filter();

    /*!
     * \fn get_all_variables(std::map<std::string, Variable *> &map_to_fill)
     * \brief Get a map of all the variables.
     * \param map_to_fill The map to fill.
     * A Variable do not have a name so the key is:
     * Container name + " " + VariableType name
     */
    void get_all_variables(std::map<std::string, Variable *> &map_to_fill);

    void get_states_colors(std::map<std::string, Color * > &, Container *parent = NULL);
    void get_events_colors(std::map<std::string, Color * > &nc_map);
    void get_links_colors(std::map<std::string, Color * > &nc_map);

    void get_colors(const std::string type, std::map<std::string, Color * > &nc_map);

    /*!
     * \fn load_config_from_xml(QString filename)
     * \brief load an xml config file into the view_root_containers
     * \param QString filename the xml file
     */
    bool load_config_from_xml(QString filename);

    void load_names_rec(Container *current_container, QDomElement& element);

    std::map<long int,double> update_text_variable_values(double date);

};//end class

void get_state_names_colors_list(std::map<std::string, Color *> &name_map, Node<StateChange> *node);

#endif
