/**
 *
 * @file src/trace/Container.hpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Mohamed Faycal Boullit
 * @author Mathieu Faverge
 * @author Kevin Coulomb
 * @author Olivier Lagrasse
 * @author Augustin Degomme
 * @author Clement Vuchener
 *
 * @date 2024-07-17
 */
#ifndef CONTAINER_HPP
#define CONTAINER_HPP

#include "trace/Event.hpp"
#include "trace/Link.hpp"
#include "trace/State.hpp"
#include "trace/StateChange.hpp"
#include "trace/StateType.hpp"
/* -- */
#include "trace/values/Name.hpp"
#include "trace/values/String.hpp"
/* -- */
#include <stack>

/*!
 * \file Container.hpp
 */
template <typename E>
class Node;
template <typename E>
class BinaryTree;
class ContainerType;
class Double;
class Event;
class Interval;
class StateChange;
class Statistic;
class Variable;
class VariableType;

#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 remove_links(LinkType *type)
     * \brief Remove links having as a LinkType type
     * \param type Type of links to remove
     */
    void remove_links(LinkType *type);

    /*!
     * \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)
    //        Q_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
