/*
 ** 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 developpers 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 <vector>
#include <map>
#include "Color.hpp"
#include "Date.hpp"
#include "Double.hpp"
#include "Hex.hpp"
#include "Integer.hpp"
#include "Name.hpp"
#include "String.hpp"
#include "Value.hpp"

/*!
 *
 * \file Trace.hpp
 * \author  NOISETTE
 * \brief Bouchon
 *
 *
 *
 */

typedef std::string Container ;
typedef std::string ContainerType ;
typedef std::string EntityType ;
typedef std::string StateType;
typedef std::string EntityValue;
typedef std::string EventType;
typedef std::string VariableType;
typedef std::string LinkType;


class Trace{

private:
    mutable std::vector<std::string*> to_freed;
    void free_str();

public :

    Trace();
    ~Trace();
    std::string to_string(std::map<std::string, Value *> extra_fields);
    /*!
     *
     *\fn define_container_type()
     *\brief This function is to define a container type
     *
     *\param String : the type of his parent container
     *\param Name : an object that can contain a name, an alias or both
     *
     */
    void define_container_type(Name &alias, ContainerType *container_type_parent, std::map<std::string, Value *> extra_fields);

    /*!
     *
     *\fn create_container()
     *\brief This function is to create a container
     *
     *
     *\param Date : When the container is created
     *\param Name : an object that can contain a name, an alias or both
     *\param String : the type of the container
     *\param String : the parent of the container
     *
     */
    void create_container(Date time, Name alias, ContainerType *type, Container *parent, std::map<std::string, Value *> extra_fields);

    /*!
     *
     *\fn destroy_container()
     *\brief This function is to destroy a container
     *
     *\param Date : When the container is destroyed
     *\param Name : an object that can contain a name, an alias or both
     *\param Sring : the type of the container
     *
     */
    void destroy_container(Date time, Container *cont, ContainerType *type, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn define_event_type()
     *\brief This function is to define a type of event
     *
     *\param Name : an object that can contain a name, an alias or both
     *\param String : the type of the container
     *
     */
    void define_event_type(Name alias, ContainerType *container_type, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn define_state_type()
     *\brief This function is to define a type of state
     *
     *\param Name : an object that can contain a name, an alias or both
     *\param String : the type of the container
     *
     *
     */
    void define_state_type(Name alias, ContainerType *container_type, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn define_variable_type()
     *\brief This function is to define a type of variable
     *
     *\param Name : an object that can contain a name, an alias or both
     *\param String : the type of the container
     *
     */
    void define_variable_type(Name alias, ContainerType *container_type, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn define_link_type()
     *\brief This function is to define a type of link
     *
     *\param Name : an object that can contain a name, an alias or both
     *\param String : the type of the container that is the common ancestor of both container
     *\param String : the type of the container where the link starts
     *\param String : the type of the container where the link goes
     *
     */
    void define_link_type(Name alias, ContainerType *ancestor, ContainerType *source, ContainerType *destination, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn define_entity_value()
     *\brief This function is to define_entity_value
     *
     *\param Name : an object that can contain a name, an alias or both
     *\param String : the type of the entity
     *
     */
    void define_entity_value(Name alias, EntityType *entity_type, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn set_state()
     *\brief This function is to set a state
     *
     *\param Date : Moment when it changes of state
     *\param String : the type of the entity
     *\param String : the container
     *\param String : the new value of the state
     *
     */
    void set_state(Date time, StateType *type, Container *container, EntityValue *value, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn push_state()
     *\brief This function is to push a state on the stack
     *
     *\param Date : Moment when the state is pushed
     *\param String : the type of the entity
     *\param String : the container
     *\param String : the new value of the state
     *
     */
    void push_state(Date time, StateType *type, Container *container, EntityValue *value, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn pop_state()
     *\brief This function is to pop a state from the stack
     *
     *\param Date : Moment when the state is popped
     *\param String : the type of the entity
     *\param String : the container
     *
     */
    void pop_state(Date time, StateType *type, Container *container, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn new_event()
     *\brief This function is to create a new event
     *
     *\param Date : When the new event arrives
     *\param String : the type of the entity
     *\param String : the container
     *\param String : the value of the event
     *
     */
    void new_event(Date time, EventType *type, Container *container, EntityValue *value, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn set_variable()
     *\brief This function is to set a value to the variable
     *
     *\param Date : When the variable is set
     *\param String : the type of the entity
     *\param String : the container
     *\param double : the value of the variable
     *
     */
    void set_variable(Date time, VariableType *type, Container *container, Double value, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn add_variable()
     *\brief This function is to add a new variable
     *
     *\param Date : When th variable is incremented
     *\param String : the type of the entity
     *\param String : the container
     *\param double : the value of the variable
     *
     */
    void add_variable(Date time, VariableType *type, Container *container, Double value, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn sub_variable()
     *\brief This function is to substract a value to the variable
     *
     *\param Date : When the variable is decremented
     *\param String : the type of the entity
     *\param String : the container
     *\param double : the value of the variable
     *
     */
    void sub_variable(Date time, VariableType *type, Container *container, Double value, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn start_link()
     *\brief This function is to start a link
     *
     *\param Date : When the link starts
     *\param String : the type of the entity
     *\param String : the container
     *\param String : the source of the link
     *\param String : the value of the variable
     *
     */
    void start_link(Date &time, LinkType *type, Container *ancestor, Container *source, EntityValue *value, String key, std::map<std::string, Value *> extra_fields);


    /*!
     *
     *\fn end_link()
     *\brief This function is to end a link
     *
     *\param Date : When the link ends
     *\param String : the type of the entity
     *\param String : the container
     *\param String : the destination of the link
     *\param String : the value of the variable
     *
     */
    void end_link(Date &time, LinkType *type, Container *ancestor, Container *destination, EntityValue *value, String key, std::map<std::string, Value *> extra_fields);


    /*!
     *
     * \fn get_root_container
     * \brief returns the list of the root container
     *
     */


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

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

    /*!
     *
     * \fn search_event_type
     * \brief search a event type by his name or alias
     *
     */
    Container *search_event_type(String name) ;


    /*!
     *
     * \fn search_state_type
     * \brief search a container by his name or alias
     *
     */
    Container *search_state_type(String name) ;


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


    /*!
     *
     * \fn search_link_type
     * \brief search a container by his name or alias
     *
     */
    LinkType *search_link_type(String name);     /*!
                                                  *
                                                  * \fn search_entity_value
                                                  * \brief search a container by his name or alias
                                                  *
                                                  */
    EntityValue *search_entity_value(String name, EntityType *entity_type) const;
    EntityType *search_entity_type(String name) const;

    void finish();

};//end class

#endif
