/*
 ** 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
 **
 */
/**
 *  @file ParserDefinitionOTF2.cpp
 *
 *  @author François Trahay
 *  @author Lagrasse Olivier
 *  @author Johnny Jazeix
 *  @author Mathieu Faverge
 *
 */
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <cassert>
/* -- */
#include <otf2/otf2.h>
/* -- */
#include "common/common.hpp"
#include "common/Errors.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "parser/OTF2Parser/ParserDefinitionOTF2.hpp"
/* -- */
using namespace std;

map<OTF2_SystemTreeNodeRef, OTF2_SystemTreeNode* > ParserDefinitionOTF2::_system_tree_node;
map<OTF2_LocationGroupRef,  OTF2_LocationGroup* >  ParserDefinitionOTF2::_location_group;
map<OTF2_LocationRef,       OTF2_Location* >       ParserDefinitionOTF2::_location;

map<OTF2_MetricMemberRef, OTF2_MetricMember > ParserDefinitionOTF2::_metric_member;
map<OTF2_MetricRef,       OTF2_MetricClass >  ParserDefinitionOTF2::_metric_class;

map<uint32_t, OTF2_Function > ParserDefinitionOTF2::_functions;

map<uint32_t, const char * >  ParserDefinitionOTF2::_strings;

map<OTF2_GroupRef, OTF2_Group*> ParserDefinitionOTF2::_groups;
map<OTF2_CommRef, OTF2_Comm*>   ParserDefinitionOTF2::_comms;

vector<Color *>               ParserDefinitionOTF2::_default_colors;

uint64_t                      ParserDefinitionOTF2::_ticks_per_second = 1;
double                        ParserDefinitionOTF2::_first_timestamp = -1;

ParserDefinitionOTF2::ParserDefinitionOTF2(OTF2_Reader *reader) {

    _global_def_reader = OTF2_Reader_GetGlobalDefReader(reader);
    _global_def_callbacks = OTF2_GlobalDefReaderCallbacks_New();

    // Create the colors
    _default_colors.push_back(new Color(1, 0, 0)); // Red
    _default_colors.push_back(new Color(0, 1, 0)); // Green
    _default_colors.push_back(new Color(0, 0, 1)); // Blue
    _default_colors.push_back(new Color(1, 1, 0)); // Yellow
    _default_colors.push_back(new Color(0, 1, 1)); // Cyan
    _default_colors.push_back(new Color(1, 0, 1)); // Magenta
    _default_colors.push_back(new Color(1, 0.5, 0)); // Orange
    _default_colors.push_back(new Color(0.5, 0, 0.5)); // Purple
    _default_colors.push_back(new Color(1, 0, 0.5)); // Orange
    _default_colors.push_back(new Color(0, 0.5, 1)); // Clear blue

}

ParserDefinitionOTF2::~ParserDefinitionOTF2() {

    OTF2_GlobalDefReaderCallbacks_Delete(_global_def_callbacks);

    // Free the memory used by the colors
    for(int i = 0 ; i < NB_COLORS ; ++ i) {
        delete _default_colors[i];
        _default_colors[i] = NULL;
    }
    _default_colors.clear();

    _strings.clear();

    ParserDefinitionOTF2::_location.erase(ParserDefinitionOTF2::_location.begin(),
                                          ParserDefinitionOTF2::_location.end());
    ParserDefinitionOTF2::_location_group.erase(ParserDefinitionOTF2::_location_group.begin(),
                                                ParserDefinitionOTF2::_location_group.end());
    ParserDefinitionOTF2::_system_tree_node.erase(ParserDefinitionOTF2::_system_tree_node.begin(),
                                                  ParserDefinitionOTF2::_system_tree_node.end());
    ParserDefinitionOTF2::_functions.erase(ParserDefinitionOTF2::_functions.begin(),
                                           ParserDefinitionOTF2::_functions.end());
    ParserDefinitionOTF2::_groups.erase(ParserDefinitionOTF2::_groups.begin(),
                                        ParserDefinitionOTF2::_groups.end());
    ParserDefinitionOTF2::_comms.erase(ParserDefinitionOTF2::_comms.begin(),
                                      ParserDefinitionOTF2::_comms.end());
}

void ParserDefinitionOTF2::set_handlers(Trace *t) {

    OTF2_GlobalDefReaderCallbacks_SetSystemTreeNodeCallback ( _global_def_callbacks, &handler_DefSystemTreeNode  );
    OTF2_GlobalDefReaderCallbacks_SetLocationCallback       ( _global_def_callbacks, &handler_DefLocation        );
    OTF2_GlobalDefReaderCallbacks_SetLocationGroupCallback  ( _global_def_callbacks,  handler_DefLocationGroup   );
    OTF2_GlobalDefReaderCallbacks_SetStringCallback         ( _global_def_callbacks, &handler_DefString          );
    OTF2_GlobalDefReaderCallbacks_SetClockPropertiesCallback( _global_def_callbacks, &handler_DefTimerResolution );
    OTF2_GlobalDefReaderCallbacks_SetRegionCallback         ( _global_def_callbacks, &handler_DefState           );
    // SetGroupCallback to get containerType, stateType... ?
    OTF2_GlobalDefReaderCallbacks_SetGroupCallback          ( _global_def_callbacks, &handler_DefGroup );
    OTF2_GlobalDefReaderCallbacks_SetCommCallback          ( _global_def_callbacks, &handler_DefComm );

    OTF2_GlobalDefReaderCallbacks_SetMetricMemberCallback       (_global_def_callbacks, &handler_DefMetricMember       );
    OTF2_GlobalDefReaderCallbacks_SetMetricClassCallback        (_global_def_callbacks, &handler_DefMetricClass        );
    OTF2_GlobalDefReaderCallbacks_SetMetricInstanceCallback     (_global_def_callbacks, &handler_DefMetricInstance     );
    OTF2_GlobalDefReaderCallbacks_SetMetricClassRecorderCallback(_global_def_callbacks, &handler_DefMetricClassRecorder);

    (void)t;
}

/*
 * All the definition handlers
 */

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefTimerResolution(void *, uint64_t timer_resolution, uint64_t /*global_offset*/, uint64_t /*trace_length*/)
{
    ParserDefinitionOTF2::_ticks_per_second = timer_resolution;
    return OTF2_CALLBACK_SUCCESS;
}

double ParserDefinitionOTF2::get_timestamp(OTF2_TimeStamp ts) {
    if(_first_timestamp<0) {
        _first_timestamp=(double)ts/(double)ParserDefinitionOTF2::get_ticks_per_second();
    }
    return (double)ts/(double)ParserDefinitionOTF2::get_ticks_per_second()-_first_timestamp;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefString(void */*userData  */,
                                                          OTF2_StringRef id,
                                                          const char *value)
{
    _strings[id] = value;
    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefSystemTreeNode(void *               /*userData  */,
                                                                  OTF2_SystemTreeNodeRef tree_node_id,
                                                                  OTF2_StringRef         name_id,
                                                                  OTF2_StringRef         /*class_id*/,
                                                                  OTF2_SystemTreeNodeRef parent_node_id) {
    OTF2_SystemTreeNode* temp = new OTF2_SystemTreeNode();
    temp->_node_id = tree_node_id;
    temp->_name_id = name_id;
    temp->_parent  = parent_node_id;
    generate_string_id(temp);

    struct OTF2_SystemTreeNode *tree_node = ParserDefinitionOTF2::get_system_tree_node_by_id(parent_node_id);
    if( tree_node != NULL ) {
        tree_node->_child_nodes[tree_node_id] = temp;
    }
    _system_tree_node[tree_node_id] = temp;

#if defined(OTF2_DEBUG)
    cout<<"DefSystemTreeNode(node_id="<<tree_node_id<<", name="<<temp->_id_string<<", parent=";
    if( tree_node ) {
        cout << tree_node->_id_string;
    }
    else {
        cout << "(none)";
    }
    cout<<"\n";
#endif

    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefLocationGroup(void */*userdata*/,
                                                                 OTF2_LocationGroupRef location_group_identifier,
                                                                 OTF2_StringRef name,
                                                                 OTF2_LocationGroupType /*type*/,
                                                                 OTF2_SystemTreeNodeRef system_tree_parent) {
    OTF2_LocationGroup *temp = new OTF2_LocationGroup();
    temp->_group_id = location_group_identifier;
    temp->_name_id = name;
    temp->_node_id=system_tree_parent;
    generate_string_id(temp);

    struct OTF2_SystemTreeNode *tree_node = ParserDefinitionOTF2::get_system_tree_node_by_id(system_tree_parent);
    if(tree_node != NULL) {
        tree_node->_location_group[location_group_identifier] = temp;
    }
    _location_group[location_group_identifier] = temp;

#if defined(OTF2_DEBUG)
    cout<<"DefLocationGroup(group_id="<<location_group_identifier<<", name="<<temp->_id_string<<", parent=";
    if(tree_node)
        cout<<tree_node->_id_string;
    else
        cout<<"(none)";
    cout<<"\n";
#endif  // defined(OTF2_DEBUG)
    return OTF2_CALLBACK_SUCCESS;
}


OTF2_CallbackCode ParserDefinitionOTF2::handler_DefLocation(void *                userData,
                                                            OTF2_LocationRef      locationIdentifier,
                                                            OTF2_StringRef        name_id,
                                                            OTF2_LocationType     /*location_type*/,
                                                            uint64_t              numberOfEvents,
                                                            OTF2_LocationGroupRef locationGroup)
{
    OTF2_Reader* reader = (OTF2_Reader *) userData;
    OTF2_EvtReader* evt_reader = OTF2_Reader_GetEvtReader(reader, locationIdentifier);
    OTF2_DefReader* def_reader = OTF2_Reader_GetDefReader(reader, locationIdentifier);
    uint64_t definitions_read = 0;
    OTF2_Reader_ReadAllLocalDefinitions(reader, def_reader, &definitions_read);

    OTF2_Location* temp= new OTF2_Location();
    temp->_location_id=locationIdentifier;
    temp->_name_id = name_id;
    temp->_group_id=locationGroup;
    temp->_number_of_events=numberOfEvents;
    generate_string_id(temp);

    struct OTF2_LocationGroup *location_group = ParserDefinitionOTF2::get_location_group_by_id(locationGroup);
    if(location_group != NULL) {
        location_group->_location[locationIdentifier] = temp;
    }
    _location[locationIdentifier] = temp;

#if defined(OTF2_DEBUG)
    cout<<"DefLocation(id="<<locationIdentifier<<", name="<<temp->_id_string<<", parent=";
    if(location_group)
        cout<<location_group->_id_string;
    else
        cout<<"(none)";
    cout<<"\n";
#endif  // defined(OTF2_DEBUG)

    (void)evt_reader;
    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefState(void */*userData*/,
                                                         OTF2_RegionRef self,
                                                         OTF2_StringRef name,
                                                         OTF2_StringRef canonicalName,
                                                         OTF2_StringRef description,
                                                         OTF2_RegionRole regionRole,
                                                         OTF2_Paradigm paradigm,
                                                         OTF2_RegionFlag regionFlags,
                                                         OTF2_StringRef sourceFile,
                                                         uint32_t beginLineNumber,
                                                         uint32_t endLineNumber) {

    OTF2_Function temp = {name, canonicalName, description, regionRole, paradigm, regionFlags, sourceFile, beginLineNumber, endLineNumber};
    ParserDefinitionOTF2::_functions[self] = temp;
    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefGroup(void *          /*userData*/,
                                                         OTF2_GroupRef   group_id,
                                                         OTF2_StringRef  name_id,
                                                         OTF2_GroupType  type,
                                                         OTF2_Paradigm   paradigm,
                                                         OTF2_GroupFlag  flags,
                                                         uint32_t        numberOfMembers,
                                                         const uint64_t *members) {
    if(type == OTF2_GROUP_TYPE_COMM_LOCATIONS) {
        struct OTF2_Group *g = new struct OTF2_Group();
        g->_id = group_id;
        g->_name = name_id;
        g->_type = type;
        g->_paradigm = paradigm;
        g->_flags = flags;
        g->_members.resize(numberOfMembers);
        for(uint32_t i=0; i<numberOfMembers; i++) {
            g->_members[i] = members[i];
        }
        ParserDefinitionOTF2::_groups[group_id] = g;
    } else {
        switch(type) {
        case OTF2_GROUP_TYPE_UNKNOWN:
            break;
        case OTF2_GROUP_TYPE_LOCATIONS:
            cout << "New location group: group_id " << group_id << ", name_id" << name_id << endl;
            break;
        case OTF2_GROUP_TYPE_REGIONS:
            cout << "New region group: group_id " << group_id << ", name_id" << name_id << endl;
            break;
        case OTF2_GROUP_TYPE_METRIC:
            cout << "New metric group: group_id " << group_id << ", name_id" << name_id << endl;
            break;
        case OTF2_GROUP_TYPE_COMM_LOCATIONS:
            cout << "New comm location group: group_id " << group_id << ", name_id" << name_id << endl;
            break;
        case OTF2_GROUP_TYPE_COMM_GROUP:
            cout << "New comm group: group_id " << group_id << ", name_id" << name_id << endl;
            break;
        case OTF2_GROUP_TYPE_COMM_SELF:
            cout << "New comm self: group_id " << group_id << ", name_id" << name_id << endl;
            break;
        default :
            cout << "type " << type << " not yet handled" << endl;
        }
        cout<<"\tNot yet implemented\n";
    }
  return OTF2_CALLBACK_SUCCESS;
}


OTF2_CallbackCode ParserDefinitionOTF2::handler_DefComm(void * /*userData*/,
                                                        OTF2_CommRef self,
                                                        OTF2_StringRef name,
                                                        OTF2_GroupRef group,
                                                        OTF2_CommRef parent)
{
    // defines an MPI communicator
    struct OTF2_Comm* c = new struct OTF2_Comm();
    c->_id = self;
    c->_name = name;
    c->_group = group;
    c->_parent = parent;
    ParserDefinitionOTF2::_comms[self] = c;
    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefMetricMember( void*                /*userData*/,
                                                                 OTF2_MetricMemberRef self,
                                                                 OTF2_StringRef       name,
                                                                 OTF2_StringRef       description,
                                                                 OTF2_MetricType      metricType,
                                                                 OTF2_MetricMode      metricMode,
                                                                 OTF2_Type            valueType,
                                                                 OTF2_Base            base,
                                                                 int64_t              exponent,
                                                                 OTF2_StringRef       unit )
{
    OTF2_MetricMember temp;
    temp._id          = self;
    temp._name        = name;
    temp._description = description;
    temp._metricType  = metricType;
    temp._metricMode  = metricMode;
    temp._valueType   = valueType;
    temp._base        = base;
    temp._exponent    = exponent;
    temp._unit        = unit;

    ParserDefinitionOTF2::_metric_member[self] = temp;

    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefMetricClass( void*                       /*userData*/,
                                                                OTF2_MetricRef              self,
                                                                uint8_t                     numberOfMetrics,
                                                                const OTF2_MetricMemberRef* metricMembers,
                                                                OTF2_MetricOccurrence       metricOccurrence,
                                                                OTF2_RecorderKind           recorderKind )
{
    OTF2_MetricClass temp;
    temp._id               = self;
    temp._metricOccurrence = metricOccurrence;
    temp._recorderKind     = recorderKind;

    for(int i=0; i<numberOfMetrics; i++) {
        temp._metricMembers.push_back(metricMembers[i]);
    }

    ParserDefinitionOTF2::_metric_class[self] = temp;
    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefMetricInstance( void*            /*userData*/,
                                                                   OTF2_MetricRef   /*self*/,
                                                                   OTF2_MetricRef   /*metricClass*/,
                                                                   OTF2_LocationRef /*recorder*/,
                                                                   OTF2_MetricScope /*metricScope*/,
                                                                   uint64_t         /*scope*/ )
{
    cout<<__FUNCTION__<<" not implemented\n";
    return OTF2_CALLBACK_SUCCESS;
}

OTF2_CallbackCode ParserDefinitionOTF2::handler_DefMetricClassRecorder( void*            /*userData*/,
                                                                        OTF2_MetricRef   /*metric*/,
                                                                        OTF2_LocationRef /*recorder*/ )
{
    cout<<__FUNCTION__<<" not implemented\n";
    return OTF2_CALLBACK_SUCCESS;
}

//
// Accessors to the data structures
//

OTF2_MetricClass ParserDefinitionOTF2::get_metric_class(const OTF2_MetricRef id) {
    return ParserDefinitionOTF2::_metric_class[id];
}

OTF2_MetricMember ParserDefinitionOTF2::get_metric_member(const OTF2_MetricClass metric_class, int index) {
    OTF2_MetricMemberRef ref = metric_class._metricMembers[index];
    return ParserDefinitionOTF2::_metric_member[ref];
}

OTF2_SystemTreeNode* ParserDefinitionOTF2::get_system_tree_node_by_id(const OTF2_SystemTreeNodeRef id)
{
    return ParserDefinitionOTF2::_system_tree_node[id];
}

OTF2_LocationGroup* ParserDefinitionOTF2::get_location_group_by_id(const OTF2_LocationGroupRef id)
{
    return ParserDefinitionOTF2::_location_group[id];
}

OTF2_Location* ParserDefinitionOTF2::get_location_by_id(const OTF2_LocationRef id)
{
    return ParserDefinitionOTF2::_location[id];
}

OTF2_Location* ParserDefinitionOTF2::get_location_in_communicator(const OTF2_CommRef comm,
                                                                  uint32_t rank) {
    struct OTF2_Comm * c= _comms[comm];
    if(!c) {
        cerr<<"Warning: cannot find communicator "<<comm<<endl;
        // This is probably because the tracing tool did not support communicators
        // Let's assume that rank is actually a locationRef
        return get_location_by_id(rank);
    }

    struct OTF2_Group *g= _groups[c->_group];
    if(!g) {
        cerr<<"Warning: cannot find rank "<<rank<<" in communicator "<<comm<<endl;
        // This is probably because the tracing tool did not support communicators
        // Let's assume that rank is actually a locationRef
        return get_location_by_id(rank);
    }

    if(rank > g->_members.size()) {
        cerr<<"Warning: searching for rank "<<rank<<" in communicator "<<comm<<", but comm_size="<<g->_members.size()<<endl;
        // This is probably because the tracing tool did not support communicators
        // Let's assume that rank is actually a locationRef
        return get_location_by_id(rank);
    }
    return get_location_by_id(g->_members[rank]);
}

OTF2_Function ParserDefinitionOTF2::get_function_by_id(const uint32_t id) {
    return ParserDefinitionOTF2::_functions[id];
}

const char *ParserDefinitionOTF2::get_string_by_id(uint32_t id) {
    return ParserDefinitionOTF2::_strings[id];
}

uint64_t ParserDefinitionOTF2::get_ticks_per_second() {
    return ParserDefinitionOTF2::_ticks_per_second;
}

Color *ParserDefinitionOTF2::get_color(uint32_t func_id) {
    return new Color(*_default_colors[func_id % NB_COLORS]);
}

//
// Other public functions
//
void ParserDefinitionOTF2::read_definitions(OTF2_Reader *reader) {
    OTF2_Reader_RegisterGlobalDefCallbacks(reader, _global_def_reader, _global_def_callbacks, reader);
    uint64_t definitions_read = 0;
    OTF2_Reader_ReadAllGlobalDefinitions(reader, _global_def_reader, &definitions_read);
}

void ParserDefinitionOTF2::generate_string_id(OTF2_Location* l) {
    const char*s = get_string_by_id(l->_name_id);
    l->_id_string=string(s?s:"") +"_"+std::to_string(l->_location_id);
}

void ParserDefinitionOTF2::generate_string_id(OTF2_LocationGroup* lg) {
    const char* s = get_string_by_id(lg->_name_id);
    lg->_id_string= string(s?s:"")+"_"+std::to_string(lg->_group_id);
}

void ParserDefinitionOTF2::generate_string_id(OTF2_SystemTreeNode* n) {
    const char* s = get_string_by_id(n->_name_id);
    n->_id_string=string(s?s:"")+"_"+std::to_string(n->_node_id);
}

string ParserDefinitionOTF2::get_string_id(OTF2_Location* l) {
    return l->_id_string;
}

string ParserDefinitionOTF2::get_string_id(OTF2_LocationGroup* lg) {
    return lg->_id_string;
}

string ParserDefinitionOTF2::get_string_id(OTF2_SystemTreeNode* n) {
    return n->_id_string;
}

ContainerType* define_container_type(Trace*t, const char* name, const char* parent_name) {
    ContainerType *container_type = t->search_container_type(String(name));
    if(container_type == NULL) {
        // first type we create this kind of container. Let's define a container_type
        Name name_temp(name);
        map<std::string, Value *> extra_fields;
        ContainerType *parent_container_type = NULL;
        if(parent_name) {
            parent_container_type = t->search_container_type(String(parent_name));
        }
        t->define_container_type(name_temp, parent_container_type, extra_fields);
        container_type = t->search_container_type(String(name));
        assert(container_type != NULL);
    }
    return container_type;
}

void ParserDefinitionOTF2::create_location(Trace *t, OTF2_Location *l) {
    Name name_temp(get_string_id(l));
    OTF2_LocationGroup* parent=get_location_group_by_id(l->_group_id);
    Container *parent_container=NULL;
    map<string, Value *> extra_fields;
    if(parent != NULL) {
        parent_container = t->search_container(get_string_id(parent));
    }
    const char* parent_name=NULL;
    if(parent) {
        parent_name = get_string_by_id(parent->_name_id);
    }
    ContainerType *container_type = define_container_type(t, get_string_by_id(l->_name_id), parent_name);

    Date d = 0;
    Container* c = t->search_container(name_temp.get_name());
    if(c) {
        cerr<<"Error: container "<<name_temp.get_name()<<" already exists!\n";
        abort();
    }
    t->create_container(d, name_temp, container_type, parent_container, extra_fields);
    l->container = t->search_container(name_temp.get_name());
}


void ParserDefinitionOTF2::create_location_group(Trace *t, OTF2_LocationGroup *lg) {
    Name name_temp(get_string_id(lg));
    OTF2_SystemTreeNode* parent=get_system_tree_node_by_id(lg->_node_id);
    Container *parent_container=NULL;
    map<string, Value *> extra_fields;
    if(parent != NULL) {
        parent_container = t->search_container(get_string_id(parent));
    }

    const char* parent_name=NULL;
    if(parent) {
        parent_name = get_string_by_id(parent->_name_id);
    }
    ContainerType *container_type = define_container_type(t, get_string_by_id(lg->_name_id), parent_name);

    Date d = 0;
    t->create_container(d, name_temp, container_type, parent_container, extra_fields);
}

void ParserDefinitionOTF2::create_system_tree_node(Trace *t, OTF2_SystemTreeNode *node) {

    Name name_temp(get_string_id(node));
    OTF2_SystemTreeNode* parent=get_system_tree_node_by_id(node->_parent);
    Container *parent_container=NULL;

    const char* parent_name=NULL;
    if(parent) {
        parent_name = get_string_by_id(parent->_name_id);
    }
    ContainerType *container_type = define_container_type(t, get_string_by_id(node->_name_id), parent_name);

    map<string, Value *> extra_fields;
    if(parent != NULL) {
        parent_container = t->search_container(get_string_id(parent));
    }
    Date d = 0;
    t->create_container(d, name_temp, container_type, parent_container, extra_fields);
}

void ParserDefinitionOTF2::create_container_types(Trace *t) {

    std::map<OTF2_SystemTreeNodeRef, OTF2_SystemTreeNode* >::const_iterator it_tree, end_tree;
    end_tree = _system_tree_node.end();
    for (it_tree = _system_tree_node.begin() ; it_tree != end_tree ; ++ it_tree) {
        OTF2_SystemTreeNode* n = (*it_tree).second;
        if(n) {
            // Create the containers
            create_system_tree_node(t, n);
        }
    }

    std::map<OTF2_LocationGroupRef, OTF2_LocationGroup* >::const_iterator it_lg, end_lg;
    end_lg = _location_group.end();
    for (it_lg = _location_group.begin() ; it_lg != end_lg ; ++ it_lg) {
        OTF2_LocationGroup* n = (*it_lg).second;
        if(n) {
            // Create the containers
            create_location_group(t, n);
        }
    }

    std::map<OTF2_LocationRef, OTF2_Location* >::const_iterator it_l, end_l;
    end_l = _location.end();
    for (it_l = _location.begin() ; it_l != end_l ; ++ it_l) {
        OTF2_Location* n = (*it_l).second;
        if(n) {
            // Create the containers
            create_location(t, n);
        }
    }
}

void ParserDefinitionOTF2::create_metric_member(Trace *t, OTF2_MetricMember m) {
    ContainerType *temp_container_type = NULL;
    std::map<OTF2_LocationRef, OTF2_Location* >::const_iterator it_l;
    it_l = _location.begin();
    if(it_l != _location.end()) {
        OTF2_Location* n = (*it_l).second;
        if(n) {
            temp_container_type = t->search_container_type(String(get_string_by_id(n->_name_id)));
        }
    }
    if(!temp_container_type)
        temp_container_type = t->search_container_type(String("0"));

    if(temp_container_type == NULL){
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE, Error::VITE_ERRCODE_ERROR);
    }
    else{
        map<string, Value *> extra_fields;
        Name alias_name(get_string_by_id(m._name));
        t->define_variable_type(alias_name, temp_container_type, extra_fields);
    }
}

void ParserDefinitionOTF2::create_metric_class(Trace *          /*t*/,
                                               OTF2_MetricClass /*m*/)
{
    // Nothing to do ?
}

void ParserDefinitionOTF2::initialize_types(Trace *t) {

    std::map<uint32_t, OTF2_MetricMember >::const_iterator it_member, end_member;
    end_member = _metric_member.end();
    for (it_member = _metric_member.begin() ; it_member != end_member ; ++ it_member) {
        OTF2_MetricMember n = (*it_member).second;
        // Create the metricMember
        create_metric_member(t, n);
    }

    std::map<uint32_t, OTF2_MetricClass >::const_iterator it_class, end_class;
    end_class = _metric_class.end();
    for (it_class = _metric_class.begin() ; it_class != end_class ; ++ it_class) {
        OTF2_MetricClass n = (*it_class).second;
        // Create the metricClass
        create_metric_class(t, n);
    }

}

// Debug purposes
void ParserDefinitionOTF2::print_definitions() {
    cout << "Strings:" << endl;
    for (map<uint32_t, const char *>::const_iterator it = _strings.begin() ; it != _strings.end() ; ++ it) {
        cout << "str#" << (*it).first << " " << (*it).second << endl;
    }

    cout << "SystemTreeNode:" << endl;
    for (map<OTF2_SystemTreeNodeRef, OTF2_SystemTreeNode*>::const_iterator it = _system_tree_node.begin() ; it != _system_tree_node.end() ; ++ it) {
        cout << "#" << (*it).first;
        OTF2_SystemTreeNode *temp = (*it).second;
        if(temp) {
            cout << " string_id: '" << temp->_id_string << "' parent:'" << temp->_parent << "'" << endl;
        }
    }

    cout << "LocationGroup:" << endl;
    for (map<OTF2_LocationGroupRef, OTF2_LocationGroup*>::const_iterator it = _location_group.begin() ; it != _location_group.end() ; ++ it) {
        cout << "#" << (*it).first;
        OTF2_LocationGroup *temp = (*it).second;
        if(temp) {
            cout << " name: '" << temp->_id_string << " ' node_id: '" << temp->_node_id << "'" << endl;
        }
    }

    cout << "Location:" << endl;
    for (map<OTF2_LocationRef, OTF2_Location*>::const_iterator it = _location.begin() ; it != _location.end() ; ++ it) {
        cout << "#" << (*it).first;
        OTF2_Location* temp = (*it).second;
        if(temp) {
            cout << " name: '" << temp->_id_string << " ' locationGroup: '" << temp->_group_id << "'" << endl;
        }
    }

    cout << "Function:" << endl;
    for (map<uint32_t, OTF2_Function>::const_iterator it = _functions.begin() ; it != _functions.end() ; ++ it) {
        cout << "#" << (*it).first;
        OTF2_Function temp = (*it).second;
        cout << " name id: '" << temp._name_id << "' name:'"  << _strings[temp._name_id] << "' region_description: '" << _strings[temp._region_description] << "' region_type: '" << temp._regionRole << "'" << endl;
    }
}
