/**
 *
 * @file src/trace/Trace.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Mathieu Faverge
 * @author Thibault Soucarre
 * @author Kevin Coulomb
 * @author Philippe Swartvagher
 * @author Olivier Lagrasse
 * @author Augustin Degomme
 * @author Clement Vuchener
 *
 * @date 2024-07-17
 */
#include <iostream>
#include <string>
#include <map>
#include <list>
#include <set>
#include <vector>
#include <sstream>
#include <stack>
#include <algorithm>
#include <cassert>

/* -- */
#include "common/Message.hpp"
#include "common/Session.hpp"
#include "common/Palette.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/tree/Interval.hpp"
#include "trace/tree/Node.hpp"
#include "trace/tree/BinaryTree.hpp"
#include "trace/EntityValue.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp" /* Dirty, should be remove */
#include "common/Message.hpp"
/* -- */
#include "trace/tree/Interval.hpp"
/* -- */

#include <QDomDocument>
#include <QFile>
#include <QIODevice>

#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
#include <fstream>
#include <boost/serialization/base_object.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include "boost/serialization/map.hpp"

#include "trace/Serializer.hpp"

#include "trace/Serializer_values.hpp"
#include "trace/Serializer_types.hpp"
#include "trace/Serializer_structs.hpp"
#include "trace/Serializer_container.hpp"

#include "trace/SerializerDispatcher.hpp"
#endif
using namespace std;

bool Trace::_sub_trace_to_load = false;
Date Trace::_begin_trace;
Date Trace::_end_trace;

Trace::Trace(const std::string &filename) :
    _max_date(0.0), _filename(filename) {
    _selected_container = nullptr;
    _filter = 0;
    _interval_constrained = nullptr;
    _depth = 0;

    _state_values = nullptr;
    _event_values = nullptr;
    _link_values = nullptr;
    _vars_values = nullptr;
}

template <class T>
void MyDelete(T *ptr) {
    delete ptr;
}

Trace::~Trace() {
    if (_interval_constrained != nullptr) {
        delete _interval_constrained;
        _interval_constrained = nullptr;
    }

    // Delete containers
    for_each(_root_containers.begin(),
             _root_containers.end(),
             MyDelete<Container>);
    _root_containers.clear();
    _root_containers.resize(0);

    // Delete container types
    while (!_root_container_types.empty()) {
        delete _root_container_types.front();
        _root_container_types.pop_front();
    }

    //     Delete state types
    for (auto &_state_type: _state_types)
        delete _state_type.second;

    // Delete event types
    for (auto &_event_type: _event_types)
        delete _event_type.second;

    // Delete link types
    for (auto &_link_type: _link_types)
        delete _link_type.second;

    // Delete variable types
    for (auto &_variable_type: _variable_types)
        delete _variable_type.second;

    _state_types.clear();
    _event_types.clear();
    _link_types.clear();
    _variable_types.clear();
}

static void delete_opt(map<string, Value *> &opt) {
    for (auto &i: opt) {
        delete i.second;
    }
}

void Trace::define_container_type(Name &name, ContainerType *parent, map<string, Value *> &opt) {
    ContainerType *type = new ContainerType(name, parent);
    if (parent)
        parent->add_child(type);
    else
        _root_container_types.push_back(type);
#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
    Serializer<ContainerType>::Instance().setUid(type);
#endif
    // Delete unused extra fields
    delete_opt(opt);
}

Container *Trace::create_container(Date &time,
                                   Name &name,
                                   ContainerType *type,
                                   Container *parent,
                                   map<string, Value *> &opt) {
    if (!type) {
        vite_error("Trace::get_container : Type undefined");
        return nullptr;
    }

    Container *cont = new Container(name, time, type, parent, opt);
    if (parent) {
        parent->add_child(cont);
    }
    else {
        _root_containers.push_back(cont);
    }

    /* Update the trace depth */
    if (cont->get_depth() > _depth) {
        _depth = cont->get_depth();
        Info::Trace::depth = _depth; /* Dirty method. Should be remove */
    }

    if (time > _max_date)
        _max_date = time;

#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
    Serializer<Container>::Instance().setUid(cont);
#endif

    return cont;
}

void Trace::destroy_container(Date &time,
                              Container *cont,
                              ContainerType *type,
                              map<string, Value *> &opt) {
    if (cont && type)
        cont->destroy(time);

    if (time > _max_date)
        _max_date = time;

    delete_opt(opt);
}

void Trace::define_event_type(Name &name, ContainerType *container_type, map<string, Value *> &opt) {
    EventType *et = new EventType(name, container_type, opt);
    _event_types.insert(pair<std::string, EventType *>(name.get_alias(), et));

#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
    Serializer<EntityType>::Instance().setUid(et);
#endif
}

void Trace::define_state_type(Name &name, ContainerType *container_type, map<string, Value *> &opt) {
    StateType *st = new StateType(name, container_type, opt);
    _state_types.insert(pair<std::string, StateType *>(name.get_alias(), st));

#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
    Serializer<EntityType>::Instance().setUid(st);
#endif
}

void Trace::define_variable_type(Name &name, ContainerType *container_type, map<string, Value *> &opt) {
    if (container_type) {
        VariableType *vt = new VariableType(name, container_type, opt);
        _variable_types.insert(pair<std::string, VariableType *>(name.get_alias(), vt));

#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
        Serializer<EntityType>::Instance().setUid(vt);
#endif
    }
    else {
        std::cerr << "define_variable_type: No container_type defined !!!" << std::endl;
    }
}

void Trace::define_link_type(Name &name,
                             ContainerType *ancestor,
                             ContainerType *source,
                             ContainerType *destination,
                             map<string, Value *> &opt) {
    if (source && destination) {
        LinkType *lt = new LinkType(name, ancestor, source, destination, opt);
        _link_types.insert(pair<std::string, LinkType *>(name.get_alias(), lt));
#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
        Serializer<EntityType>::Instance().setUid(lt);
#endif
    }
    else {
        if (!source)
            std::cerr << "define_link_type: source container is undefined !!!" << std::endl;

        if (!destination)
            std::cerr << "define_link_type: destination container is undefined !!!" << std::endl;
    }
}

void Trace::define_entity_value(Name &name, EntityType *entity_type, map<string, Value *> &opt) {
    if (entity_type && (entity_type->get_class() == _EntityClass_State)) {
        entity_type->add_value(new EntityValue(name, entity_type, opt));
    }
    else {
        if (!entity_type) {
            std::cerr << "define_entity_value: EntityType is undefined !!!" << std::endl;
        }
        else {
            std::cerr << "define_entity_value: EntityType class is " << entity_type->get_class()
                      << " instead of " << _EntityClass_State << " !!!" << std::endl;
        }
    }
}

void Trace::set_state(Date &time, StateType *type, Container *container, EntityValue *value, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type)
        container->set_state(time, type, value, opt);

    if (time > _max_date)
        _max_date = time;
}

void Trace::push_state(Date &time, StateType *type, Container *container, EntityValue *value, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type)
        container->push_state(time, type, value, opt);

    if (time > _max_date)
        _max_date = time;
}

void Trace::pop_state(Date &time, StateType *type, Container *container, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type)
        container->pop_state(time);

    if (time > _max_date)
        _max_date = time;

    // Delete unused extra fields
    delete_opt(opt);
}

void Trace::reset_state(Date &time, StateType *type, Container *container, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type)
        container->reset_state(time);

    if (time > _max_date)
        _max_date = time;

    // Delete unused extra fields
    delete_opt(opt);
}

void Trace::new_event(Date &time, EventType *type, Container *container, const String &value, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type) {
        EntityValue *EV = search_entity_value(value.to_string(), type, true);
        assert(EV);
        container->new_event(time, type, EV, opt);
    }

    if (time > _max_date)
        _max_date = time;
}

void Trace::set_variable(Date &time, VariableType *type, Container *container, const Double &value, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type)
        container->set_variable(time, type, value);

    if (time > _max_date)
        _max_date = time;

    // Delete unused extra fields
    delete_opt(opt);
}

void Trace::add_variable(Date &time, VariableType *type, Container *container, const Double &value, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type)
        container->add_variable(time, type, value);

    if (time > _max_date)
        _max_date = time;

    // Delete unused extra fields
    delete_opt(opt);
}

void Trace::sub_variable(Date &time, VariableType *type, Container *container, const Double &value, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (container && type)
        container->sub_variable(time, type, value);

    if (time > _max_date)
        _max_date = time;

    // Delete unused extra fields
    delete_opt(opt);
}

void Trace::start_link(Date &time, LinkType *type,
                       Container *ancestor, Container *source,
                       EntityValue *value,
                       const String &key, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (ancestor && type && source) {
        if (value == NULL) {
            // If we come from an other parser than Pajé
            value = search_entity_value(type->get_alias(), type);
        }

        ancestor->start_link(time, type, source, value, key, opt);

        if (time > _max_date)
            _max_date = time;
    }
}

void Trace::end_link(Date &time, LinkType *type,
                     Container *ancestor, Container *destination,
                     const String &key, map<string, Value *> &opt) {
    if (!is_in_loaded_interval(time))
        return;

    if (ancestor && type && destination)
        ancestor->end_link(time, destination, key, opt);

    if (time > _max_date)
        _max_date = time;
}

void Trace::finish() {
    stack<Container *> containers;

    const Container::Vector *root_containers = &_view_root_containers;
    if (root_containers->empty())
        root_containers = &_root_containers;

    Container::VectorIt i = root_containers->begin();
    Container::VectorIt const &end = root_containers->end();

    for (; i != end; i++)
        containers.push(*i);

    while (!containers.empty()) {
        Container *c = containers.top();
        containers.pop();
        c->finish(_max_date);

        {
            const Container::Vector *children = c->get_view_children();
            if (children->empty())
                children = c->get_children();

            for (const auto &child: *children)
                containers.push(child);
        }
    }
}

#if defined(USE_ITC) && defined(BOOST_SERIALIZE)

void Trace::updateTrace(Interval *interval) {
    if (Info::Splitter::load_splitted == true) {
        if (Info::Splitter::preview == false) {
            loadTraceInside(interval);
            finish();
        }
        else {
            loadPreview();
        }
    }
}

void Trace::loadTraceInside(Interval *interval) {
    SerializerDispatcher::Instance().init();
    stack<Container *> containers;
    const Container::Vector *root_containers = &_view_root_containers;
    if (root_containers->empty())
        root_containers = &_root_containers;

    Container::VectorIt i = root_containers->begin();
    Container::VectorIt const &end = root_containers->end();

    for (; i != end; i++)
        containers.push(*i);

    while (!containers.empty()) {
        Container *c = containers.top();
        c->loadItcInside(interval);
        containers.pop();
        {
            const Container::Vector *children = c->get_view_children();
            if (children->empty())
                children = c->get_children();

            Container::VectorIt it = children->begin();
            Container::VectorIt const &it_end = children->end();

            for (; it != it_end; it++)
                containers.push(*it);
        }
    }

    // wait for loading to finish
    SerializerDispatcher::Instance().kill_all_threads();
}

void Trace::loadPreview() {
    stack<Container *> containers;
    const Container::Vector *root_containers = &_view_root_containers;
    if (root_containers->empty())
        root_containers = &_root_containers;

    Container::VectorIt i = root_containers->begin();
    Container::VectorIt const &end = root_containers->end();

    for (; i != end; i++)
        containers.push(*i);

    while (!containers.empty()) {
        Container *c = containers.top();
        c->loadPreview();
        containers.pop();
        {
            const Container::Vector *children = c->get_view_children();
            if (children->empty())
                children = c->get_children();

            Container::VectorIt it = children->begin();
            Container::VectorIt const &it_end = children->end();

            for (; it != it_end; it++)
                containers.push(*it);
        }
    }
}

void Trace::dump(std::string path, std::string filename) {
    // dump intervalOfContainer for each container
    stack<Container *> containers;
    Container::VectorIt i = _root_containers.begin();
    Container::VectorIt const &end = _root_containers.end();

    for (; i != end; i++)
        containers.push(*i);

    while (!containers.empty()) {
        Container *c = containers.top();
        c->dump(path, filename, _max_date);
        containers.pop();
        {
            std::list<Container *>::const_iterator it = c->get_children()->begin();
            std::list<Container *>::const_iterator it_end = c->get_children()->end();

            for (; it != it_end; ++it) {
                containers.push(*it);
            }
        }
    }
    // dump containers

    std::string file;
    file += path + "/" + filename + "/" + filename + ".vite";
    //  i   = _root_containers.begin();
    std::ofstream ofs(file.c_str(), std::ios::out);
    boost::archive::text_oarchive oa(ofs);

    oa.register_type(static_cast<StateType *>(NULL));
    oa.register_type(static_cast<EventType *>(NULL));
    oa.register_type(static_cast<VariableType *>(NULL));
    oa.register_type(static_cast<LinkType *>(NULL));
    oa.register_type(static_cast<ContainerType *>(NULL));
    oa.register_type(static_cast<Container *>(NULL));
    oa.register_type(static_cast<Color *>(NULL));
    oa.register_type(static_cast<Date *>(NULL));
    oa.register_type(static_cast<Double *>(NULL));
    oa.register_type(static_cast<Hex *>(NULL));
    oa.register_type(static_cast<Integer *>(NULL));
    oa.register_type(static_cast<Name *>(NULL));
    oa.register_type(static_cast<String *>(NULL));
    oa << _root_container_types;
    oa << _root_containers;
    oa << _state_types;
    oa << _event_types;
    oa << _link_types;
    oa << _variable_types;
    oa << _max_date;

    // we finished to dump all the trace, we can now cleanly kill the serialization threads
    SerializerDispatcher::Instance().kill_all_threads();
}
#endif

const Container::Vector *
Trace::get_root_containers() const {
    return &_root_containers;
}

void Trace::set_root_containers(Container::Vector &conts) {
    _root_containers = conts;

    /* Update the trace depth, a bit dirty, but we need to fetch the maximum */
    stack<Container *> containers;

    const Container::Vector *root_containers = &_root_containers;

    for (const auto &child: *root_containers)
        containers.push(child);

    while (!containers.empty()) {
        Container *c = containers.top();
        containers.pop();
        if (c->get_depth() > _depth) {
            _depth = c->get_depth();
            Info::Trace::depth = _depth; /* Dirty method. Should be remove */
        }

        {
            const Container::Vector *children = c->get_children();

            for (const auto &child: *children)
                containers.push(child);
        }
    }
}

void Trace::set_state_types(std::map<std::string, StateType *> &conts) {
    _state_types = conts;
}
void Trace::set_event_types(std::map<std::string, EventType *> &conts) {
    _event_types = conts;
}
void Trace::set_link_types(std::map<std::string, LinkType *> &conts) {
    _link_types = conts;
}
void Trace::set_variable_types(std::map<std::string, VariableType *> &conts) {
    _variable_types = conts;
}

void Trace::set_container_types(std::list<ContainerType *> &conts) {
    _root_container_types = conts;
}

void Trace::set_max_date(Date d) {
    _max_date = std::move(d);
}

const Container::Vector *Trace::get_view_root_containers() const {
    return &_view_root_containers;
}

void Trace::set_view_root_containers(Container::Vector &conts) {
    _view_root_containers = conts;
}

void Trace::get_all_containers(Container::Vector &list_to_fill) const {
    for (const auto &child: _root_containers) {
        list_to_fill.push_back(child);
        // Recursivity to add the children names
        add_containers(list_to_fill, child);
    }
}

void Trace::add_containers(Container::Vector &containers, const Container *parent) const {
    const Container::Vector *children = parent->get_children();

    for (const auto &child: *children) {
        // We create the node and we do the recursivity
        containers.push_back(child);
        add_containers(containers, child);
    }
}

const map<std::string, StateType *> *Trace::get_state_types() const {
    return &_state_types;
}

const map<std::string, EventType *> *Trace::get_event_types() const {
    return &_event_types;
}

const map<std::string, LinkType *> *Trace::get_link_types() const {
    return &_link_types;
}

template <class T>
static T *search_tree(string name, T *el) { // Before : String name
    if (el->get_Name() == name)
        return el;
    else {
        T *r;
        typename list<T *>::const_iterator it_end = el->get_children()->end();
        for (typename list<T *>::const_iterator it = el->get_children()->begin();
             it != it_end;
             ++it) {
            r = search_tree<T>(name, *it);
            if (r)
                return r;
        }
    }
    return nullptr;
}

ContainerType *Trace::search_container_type(const String &name) const {
    ContainerType *r;

    const string &std_name = name.to_string();
    if (std_name == "0")
        return nullptr;

    const list<ContainerType *>::const_iterator &it_end = _root_container_types.end();
    for (list<ContainerType *>::const_iterator it = _root_container_types.begin();
         it != it_end;
         ++it) {
        r = search_tree<ContainerType>(std_name, *it);
        if (r)
            return r;
    }

    return nullptr;
}

Container *Trace::search_container(const String &name) const {
    Container *r;

    const string &std_name = name.to_string();
    if (std_name == "0")
        return nullptr;

    Container::VectorIt it = _root_containers.begin();
    Container::VectorIt const &end = _root_containers.end();
    for (; it != end; ++it) {
        r = search_tree<Container>(std_name, *it);
        if (r)
            return r;
    }

    return nullptr;
}

EventType *Trace::search_event_type(const String &name) const {
    std::map<std::string, EventType *>::const_iterator it = _event_types.find(name.to_string());
    if (it != _event_types.end()) {
        return ((it->second));
    }

    return nullptr;
}

StateType *Trace::search_state_type(const String &name) const {
    std::map<std::string, StateType *>::const_iterator it = _state_types.find(name.to_string());
    if (it != _state_types.end())
        return ((it->second));
    return nullptr;
}

VariableType *Trace::search_variable_type(const String &name) const {
    std::map<std::string, VariableType *>::const_iterator it = _variable_types.find(name.to_string());
    if (it != _variable_types.end())
        return ((it->second));
    return nullptr;
}

LinkType *Trace::search_link_type(const String &name) const {
    std::map<std::string, LinkType *>::const_iterator it = _link_types.find(name.to_string());
    if (it != _link_types.end())
        return ((it->second));
    return nullptr;
}

EntityType *Trace::search_entity_type(const String &name) const {

    // Search the State Type
    std::map<std::string, StateType *>::const_iterator it = _state_types.find(name.to_string());
    if (it != _state_types.end())
        return ((it->second));

    // Search the Link Type
    std::map<std::string, LinkType *>::const_iterator it2 = _link_types.find(name.to_string());
    if (it2 != _link_types.end())
        return (((*it2).second));

    // Search the Entity Type
    std::map<std::string, EventType *>::const_iterator it3 = _event_types.find(name.to_string());
    if (it3 != _event_types.end())
        return (((*it3).second));

    return nullptr;
}

EntityValue *
Trace::search_entity_value(const std::string &alias,
                           EntityType *entity_type) const {
    if (!entity_type) {
        return nullptr;
    }

    map<std::string, EntityValue *>::const_iterator it = entity_type->get_values()->find(alias);
    if (it != entity_type->get_values()->end()) {
        return (it->second);
    }

    std::cerr << "Trace::search_entity_value: EntityValue with alias " << alias << " not found !!!" << std::endl;
    assert(0);
    return nullptr;
}

EntityValue *
Trace::search_entity_value(const Name &alias_name,
                           EntityType *entity_type,
                           bool create) const {
    if (!entity_type) {
        return nullptr;
    }

    map<std::string, EntityValue *>::const_iterator it = entity_type->get_values()->find(alias_name.get_alias());
    if (it != entity_type->get_values()->end()) {
        return (it->second);
    }

    if (create) {
        EntityValue *value = new EntityValue(alias_name, entity_type, map<string, Value *>());
        entity_type->add_value(value);
        return value;
    }
    else {
        std::cerr << "Trace::search_entity_value: EntityValue with Name " << alias_name << " not found !!!" << std::endl;
        return nullptr;
    }
}

Date Trace::get_max_date() {
    return _max_date;
}

int Trace::get_depth() {
    return _depth;
}

void Trace::set_selected_container(vector<const Container *> *c) {
    _selected_container = c;
}

void Trace::set_interval_constrained(Interval *i) {
    if (_interval_constrained != nullptr) {
        delete _interval_constrained;
    }
    _interval_constrained = i;
}

vector<const Container *> *Trace::get_selected_container() {
    return _selected_container;
}

Interval *Trace::get_interval_constrained() {
    return _interval_constrained;
}

void Trace::set_filter(double f) {
    _filter = f;
}

double Trace::get_filter() {
    return _filter;
}

void Trace::get_all_variables(map<string, Variable *> &map_to_fill) {
    Container::Vector all_containers;
    get_all_containers(all_containers);

    Container::VectorIt const &end = all_containers.end();
    Container::VectorIt it = all_containers.begin();
    for (; it != end; it++) {
        const map<VariableType *, Variable *> *variables = (*it)->get_variables();
        // We store each variable
        for (const auto &variable: *variables) {
            string name = (*it)->get_Name().to_string() + " " + variable.first->get_Name().to_string();
            map_to_fill[name] = variable.second;
        }
    }
}

std::map<std::string, EntityValue *> *
Trace::get_all_entityvalues(EntityClass_t type) {
    const std::map<std::string, EntityValue *> *ev_map;
    std::map<std::string, EntityValue *>::const_iterator it2;

    switch (type) {
    case _EntityClass_State: {
        if (_state_values == nullptr) {
            _state_values = new std::map<std::string, EntityValue *>();
            std::map<std::string, StateType *>::const_iterator it;
            for (it = _state_types.begin();
                 it != _state_types.end(); ++it) {
                ev_map = (it->second)->get_values();
                _state_values->insert(ev_map->begin(), ev_map->end());
            }
        }
        return _state_values;
    } break;
    case _EntityClass_Link: {
        if (_link_values == nullptr) {
            _link_values = new std::map<std::string, EntityValue *>();
            std::map<std::string, LinkType *>::const_iterator it;
            for (it = _link_types.begin();
                 it != _link_types.end(); ++it) {
                ev_map = (it->second)->get_values();
                _link_values->insert(ev_map->begin(), ev_map->end());
            }
        }
        return _link_values;
    } break;
    case _EntityClass_Event: {
        if (_event_values == nullptr) {
            _event_values = new std::map<std::string, EntityValue *>();
            std::map<std::string, EventType *>::const_iterator it;
            for (it = _event_types.begin();
                 it != _event_types.end(); ++it) {
                ev_map = (it->second)->get_values();
                _event_values->insert(ev_map->begin(), ev_map->end());
            }
        }
        return _event_values;
    } break;
    case _EntityClass_Variable: {
        if (_vars_values == nullptr) {
            _vars_values = new std::map<std::string, EntityValue *>();
            std::map<std::string, VariableType *>::const_iterator it;
            for (it = _variable_types.begin();
                 it != _variable_types.end(); ++it) {
                ev_map = (it->second)->get_values();
                _vars_values->insert(ev_map->begin(), ev_map->end());
            }
        }
        return _vars_values;
    } break;
    default:
        std::cerr << "get_all_entityvalues: Unknown type" << std::endl;
    }
    return nullptr;
}

std::map<std::string, EntityValue *> *
Trace::get_all_entityvalues(const string &type) {
    if (type == "palette") {
        return get_all_entityvalues(_EntityClass_State);
    }
    else if (type == "event_types") {
        return get_all_entityvalues(_EntityClass_Event);
    }
    else if (type == "link_types") {
        return get_all_entityvalues(_EntityClass_Link);
    }

    assert(0);
    return nullptr;
}

const std::string &Trace::get_filename() const {
    return _filename;
}

bool Trace::load_config_from_xml(const QString &filename) {
    QDomDocument doc(QStringLiteral("Subset"));
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly)) {
        *Message::get_instance() << "File opening fail" << Message::ende;
        return false;
    }

    if (!doc.setContent(&file)) {
        file.close();
        *Message::get_instance() << "File is not a valid xml file" << Message::ende;
        return false;
    }
    file.close();

    QDomElement root = doc.documentElement();
    if (root.tagName() != QStringLiteral("nodes")) {
        *Message::get_instance() << "File is not a valid xml file" << Message::ende;
        return false;
    }

    // go through all the top elements of the trace to construct a representation
    QDomNode n = root.firstChild();
    _view_root_containers.clear();
    while (!n.isNull()) {
        QDomElement e = n.toElement();
        if (!e.isNull()) {
            if (e.tagName() == QStringLiteral("rootNode")) {
                string n(e.attribute(QStringLiteral("name"), QString()).toStdString());
                Container::VectorIt it = _root_containers.begin();
                for (;
                     it != _root_containers.end();
                     it++) {
                    if ((*it)->get_Name().to_string() == n) { // we found the root container corresponding
                        // QTreeWidgetItem *current_node = new QTreeWidgetItem((QTreeWidgetItem *)0, QStringList(QString::fromStdString(n)));
                        // current_node->setFlags(flg);
                        // current_node->setData(0,Qt::UserRole,qVariantFromValue(*it));//store the pointer to the container in the Data field
                        //  current_node->setCheckState(0,Qt::Checked);
                        // items.append(current_node);
                        _view_root_containers.push_back(*it);
                        // Recursivity to add the children names
                        load_names_rec((*it), e);
                        break;
                    }
                }

                if (it == _root_containers.end())
                    *Message::get_instance() << "Root node was not found, check if it exists. Continuing ..." << Message::ende;
            }
            else
                *Message::get_instance() << "wrong node was found when parsing for rootNode, check xml construction. Continuing ..." << Message::ende;
        }

        n = n.nextSibling();
    }

    // _nodes_displayed->insertTopLevelItems(0, items);

    // _nodes_displayed->expandAll();
    return true;
}

void Trace::load_names_rec(Container *current_container, QDomElement &element) {

    // we need to loop on both the xml childs and the container's child to make them correspond
    const Container::Vector *children = current_container->get_children();
    current_container->clear_view_children();
    QDomNode n = element.firstChild();
    while (!n.isNull()) {
        QDomElement e = n.toElement();
        if (!e.isNull()) {
            if (e.tagName() == QStringLiteral("Node")) {
                string n(e.attribute(QStringLiteral("name"), QString()).toStdString());
                Container::VectorIt it = children->begin();
                for (;
                     it != children->end();
                     it++) {
                    // We create the node and we do the recursivity

                    if ((*it)->get_Name().to_string() == n) {
                        // we found the good Container
                        //  QTreeWidgetItem *node = new QTreeWidgetItem(current_node, QStringList(QString::fromStdString(n)));

                        // node->setFlags(flg);
                        //  node->setData(0,Qt::UserRole, qVariantFromValue(*it));//store the pointer to the container in the Data field
                        //  node->setCheckState(0,Qt::Checked);
                        // printf("we found a sub element %s\n", n.c_str());
                        current_container->add_view_child((*it));
                        load_names_rec((*it), e);
                        break;
                    }
                }
                if (it == children->end())
                    *Message::get_instance() << "node " << n << " was not found, check if it exists. Continuing ..." << Message::ende;
            }
            else
                *Message::get_instance() << "wrong node was found when parsing for Node, check xml construction. Continuing ..." << Message::ende;
        }

        n = n.nextSibling();
    }
}

std::map<long int, double> Trace::update_text_variable_values(const Times &date) {
    std::map<long int, double> values;

    stack<Container *> containers;

    const Container::Vector *root_containers = &_view_root_containers;
    if (root_containers->empty())
        root_containers = &_root_containers;

    const Variable *var;
    for (const auto &root_container: *root_containers)
        containers.push(root_container);

    while (!containers.empty()) {
        Container *c = containers.top();
        containers.pop();
        if (c->get_variable_number() > 0) {
            const std::map<VariableType *, Variable *> *variable_map = c->get_variables();

            for (const auto &i: *variable_map) {

                var = i.second;

                values[(long int)var] = var->get_value_at(date);
                // draw_object->draw_text_value((long int)var,var->get_value_at(date), position);
            }
        }

        {
            const Container::Vector *children = c->get_view_children();
            if (children->empty())
                children = c->get_children();

            for (const auto &child: *children)
                containers.push(child);
        }
    }
    return values;
}
