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

/*!
 * \file Container.hpp
 */
template <typename E> class Node;
template <typename E> class BinaryTree;
class Statistic;
class Interval;
#ifdef USE_ITC
struct IntervalOfContainer;
#endif
/*!
 * \class Container
 * \brief Contains others containers or entities
 */

class Container {

    friend class State;

public:
    typedef std::list<Container *>                 Vector;
    typedef std::list<Container *>::const_iterator VectorIt;

private:
    Name                      _name;
    Date                      _creation_time;
    Date                      _destruction_time;
    ContainerType            *_type;
    Container                *_parent;
    Vector                    _children;
    Vector                    _view_children;
    unsigned int              _n_states;
    StateChange::Vector       _states;
    StateChange::Tree        *_state_tree;
    unsigned int              _n_events;
#ifdef USE_ITC
    Event**		      _events;
#else
    Event::Vector             _events;
#endif
    Event::Tree              *_event_tree;
    Link::Vector              _links;
    unsigned int              _n_variables;
    std::map<VariableType *, Variable *> _variables;
    std::map<std::string, Value *>       _extra_fields;
    int                       _depth;/* The container depth within the datastructure. The _depth of seed is equal to 0 */

#ifdef USE_ITC
    std::list<IntervalOfContainer* >     _intervalsOfContainer;
#endif
    /*
     * Temporary stores states before complete definition
     */
    struct current_state_t {
        Date                           start;
        StateType                     *type {nullptr};
        EntityValue                   *value {nullptr};
        std::map<std::string, Value *> opt;

        current_state_t(Date t, StateType *st, EntityValue *val,
                        std::map<std::string, Value *> o)
            : start(std::move(t)), type(st), value(val), opt(std::move(o)) {}

        current_state_t()
            : start(0) {}
    };
    std::stack<current_state_t> _current_states;

    /*
     * Temporary stores links before complete definition
     */
    struct current_link_t {
        Date         start;
        LinkType    *type {nullptr};
        Container   *source {nullptr};
        EntityValue *value {nullptr};
        std::map<std::string, Value *> opt;

        current_link_t(Date st, LinkType *ty, Container *src, EntityValue *val,
                       std::map<std::string, Value *> o)
            : start(std::move(st)), type(ty), source(src), value(val), opt(std::move(o)) {}

        current_link_t()
            : start(0) {}
    };

    //stores unfinished sent messages
    std::map<String, std::list<current_link_t>, String::less_than> _current_sent_links;
    //stores unfinished received messages
    std::map<String, std::list<current_link_t>, String::less_than> _current_received_links;

    void add_current_state(const Date &end);

public:
    /*!
     * \fn Container(Name name, Date creation_time, ContainerType *type, Container *parent, std::map<std::string, Value *> &opt)
     * \brief Constructor of Container
     * \param name Name of the container
     * \param creation_time Date when the container was created
     * \param type Type of the container
     * \param parent Parent container (NULL if the container is root)
     * \param opt Optional fields
     */
    Container(Name name, Date creation_time, ContainerType *type, Container *parent, std::map<std::string, Value *> &opt);

    /*!
     * \fn ~Container()
     * \brief Destructor of Container
     */
    ~Container();

    /*!
     * \fn add_child(Container *)
     * \brief Add a child to the container
     * \param child new child container
     */
    void add_child(Container *child);

    /*!
     * \fn set_state(const Date &time, StateType *type, EntityValue *value, std::map<std::string, Value *> &opt)
     * \brief Set the current state of the container
     * \param time Date of the event
     * \param type Type of the state
     * \param value Value of the state
     * \param opt Optional options of the state
     */
    void set_state(const Date &time, StateType *type, EntityValue *value, std::map<std::string, Value *> &opt);

    /*!
     * \fn push_state(const Date &time, StateType *type, EntityValue *value, std::map<std::string, Value *> &opt)
     * \brief Set the current state of the container and save the previous state
     * \param time Date of the event
     * \param type Type of the state
     * \param value Value of the state
     * \param opt Optional options of the state
     */
    void push_state(const Date &time, StateType *type, EntityValue *value, std::map<std::string, Value *> &opt);

    /*!
     * \fn pop_state(const Date &time)
     * \brief Restore a previous state
     * \param time Date of the event
     */
    void pop_state(const Date &time);

    /*!
     * \fn reset_state(const Date &time)
     * \brief Purge a container from all the stacked states
     * \param time Date of the event
     */
    void reset_state(const Date &time);

    /*!
     * \fn new_event(const Date &time, EventType *type, EntityValue *value, std::map<std::string, Value *> &opt)
     * \brief Add a new event
     * \param time Date of the event
     * \param type Type of the event
     * \param value Value of the event
     * \param opt Optional options of the state
     */
    void new_event(const Date &time, EventType *type, EntityValue *value, std::map<std::string, Value *> &opt);

    /*!
     * \fn start_link(const Date &time, LinkType *type, Container *source, EntityValue *value, const String &key, std::map<std::string, Value *> &opt)
     * \brief Start a new link identified by key
     * \param time Date of the start of the link
     * \param type Type of the link
     * \param source Container from where the link is sent
     * \param value Value of the link
     * \param key String that identifies the link to match its end
     * \param opt Optional options of the state
     */
    void start_link(const Date &time, LinkType *type, Container *source, EntityValue *value, const String &key, std::map<std::string, Value *> &opt);

    /*!
     * \fn end_link(const Date &time, Container *destination, const String &key, std::map<std::string, Value *> &opt)
     * \brief End a link identified by key
     * \param time Date of the end of the link
     * \param destination Container to where the link is sent
     * \param key String that identifies the link to match its beginning
     * \param opt Optional options of the state
     */
    void end_link(const Date &time, Container *destination, const String &key, std::map<std::string, Value *> &opt);

    /*!
     * \fn set_variable(const Date &time, VariableType *type, const Double &value)
     * \brief Set a new value of a variable
     * \param time Date of the event
     * \param type Type of the variable
     * \param value New value of the variable
     */
    void set_variable(const Date &time, VariableType *type, const Double &value);

    /*!
     * \fn add_variable(const Date &time, VariableType *type, const Double &value)
     * \brief Add a value to the current value of a variable
     * \param time Date of the event
     * \param type Type of the variable
     * \param value Value to add
     */
    void add_variable(const Date &time, VariableType *type, const Double &value);

    /*!
     * \fn sub_variable(const Date &time, VariableType *type, const Double &value)
     * \brief Substract a value to the current value of a variable
     * \param time Date of the event
     * \param type Type of the variable
     * \param value Value to substract
     */
    void sub_variable(const Date &time, VariableType *type, const Double &value);

    /*!
     * \fn get_name() const
     * \brief Get the name and the alias of the container
     */
    Name get_Name() const;

    std::string get_name()  const;
    std::string get_alias() const;

    /*!
     * \fn get_parent() const
     * \brief Get the parent container
     */
    const Container *get_parent() const;

    /*!
     * \fn get_type() const
     * \brief Get the type of the container
     */
    const ContainerType *get_type() const;

    /*!
     * \fn get_children() const
     * \brief Get the list of the child containers
     */
    const Vector *get_children() const;

    /*!
     * \fn clear_children() const
     * \brief Clear the list of the child containers, to allow reordering
     */
    void clear_children();

    /*!
     * \fn add_view_child(Container* child) const
     * \brief Add a children to the view
     */
    void add_view_child(Container *child);

    /*!
     * \fn get_view_children() const
     * \brief Get the list of the child containers to display
     */
    const Vector *get_view_children() const;

    /*!
     * \fn clear_view_children() const
     * \brief Clear the list of the child containers to display
     */
    void clear_view_children();
    /*!
     * \fn get_creation_time() const
     * \brief Get the time when the container was created
     */
    Date get_creation_time() const;

    /*!
     * \fn get_destruction_time() const
     * \brief Get the time when the container was destroyed
     */
    Date get_destruction_time() const;

    /*!
     * \fn get_states() const
     * \brief Get the state list
     */
    StateChange::Tree *get_states() const;// MODIF -> enleve * du template/ du const

    /*!
     * \fn get_events() const
     * \brief Get the event list
     */
    Event::Tree *get_events() const;

    /*!
     * \fn get_links() const
     * \brief Get the link list
     */
    const Link::Vector *get_links() const;

    /*!
     * \fn get_variables() const
     * \brief Get the variables
     */
    const std::map<VariableType *, Variable *> *get_variables() const;

    /*!
     * \fn get_extra_fields() const
     * \brief Get the extra fields
     */
    const std::map<std::string, Value *> *get_extra_fields() const;

    /*!
     * \fn get_state_number() const
     * \brief Get the number of states
     */
    unsigned int get_state_number() const;

    /*!
     * \fn get_variable_number() const
     * \brief Get the number of variables
     */
    unsigned int get_variable_number() const;

    /*!
     * \fn get_event_number() const
     * \brief Return the number of events
     */
    unsigned int get_event_number() const;

#ifdef USE_ITC

    /*!
     * \fn get_intervalsOfContainer() const
     * \brief Return the list of intervalOfContainers
     */
    const std::list<IntervalOfContainer* >* get_intervalsOfContainer() const;

    /*!
     * \fn set_intervalsOfContainer() const
     * \brief Allows to restore a list of Itc
     */
    void set_intervalsOfContainer(std::list<IntervalOfContainer* >* itc) ;
#ifdef BOOST_SERIALIZE
    /*!
     * \fn dump(std::string path, std::filename) const
     * \brief Dump all IntervalOfContainers to disk
     */
    void dump(std::string path, std::string filename,const Date &time);

    /*!
     * \fn dump_last_itc() const
     * \brief Dumps the last finished IntervalOfContainer to disk
     */
    void dump_last_itc();

    void loadItcInside(Interval* splitInterval);

    void loadPreview();

#endif


#endif

    /*!
     * \fn destroy(const Date &time)
     * \brief Sets the destruction time of the container
     * \param time Destruction tim
     */
    void destroy(const Date &time);

    /*!
     * \fn finish(const Date &time)
     * \brief Finish to initialize the container (flush temporary states)
     * \param time Time to set destruction time if it was not destroy
     */
    void finish(const Date &time);

    /*!
     * \fn fill_stat(Statistic * stat, Interval I)
     * \brief Fill the stat element with the corresponding data to be displayed
     */
    void fill_stat(Statistic * stat, Interval I);

    /*!
     * \fn get_depth()
     * \brief Return the depth of the current container.
     */
    int get_depth();
    //#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
    //       signals:
    //
    //     void dump_on_disk(IntervalOfContainer*,const  char*);
    //     void build_finish();

    //#endif
};

/*!
 * \fn browse_stat_state(Node<StateChange> * node, Statistic * stat, Interval I, Node<StateChange> ** prev)
 * \brief Recursive function that browses the tree
 * \param node : The node that is currently added
 * \param stat : The Statistic class that is filled
 * \param I : The interval we want the data in
 * \param prev : To save the previous state before the interval to be able to count it in the statistic
 */
void browse_stat_state(Node<StateChange> * node, Statistic * stats, Interval I, Node<StateChange> ** prev);
/*!
 * \fn browse_stat_link(const Container * cont, Statistic * S, Interval I)
 * \brief Fill the stat element with the corresponding data to be displayed
 */
void browse_stat_link(const Container * cont, Statistic * S, Interval I);


#endif
