/*
 ** 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
 **
 */
#include <iostream>
#include <string>
#include <map>
#include <list>
#include <set>
#include <vector>
#include <sstream>
#include <stack>
#include <algorithm>
#include <cassert>

/* -- */
#include "interface/Interface.hpp"
/* -- */
#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 <QtXml>


#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;


Trace::Trace(): _max_date(0.0) {
    _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 (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 (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 (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 (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 (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 (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 (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 (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,
                  const String &key, map<string, Value *> &opt)
{
    EntityValue *EV = search_entity_value( type->get_alias(), type );
    assert(EV);

    if (ancestor && type && source)
        ancestor->start_link(time, type, source, EV, 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 (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;
}

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

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;
}

bool  Trace::load_config_from_xml(const QString &filename){
    QDomDocument doc( "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() != "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() == "rootNode" )
            {
                string n(e.attribute( "name", "" ).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() == "Node" )
            {
                string n(e.attribute( "name", "" ).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(double 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;
}
