/*
** 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 ParserEventOTF.cpp
 *
 *  @author Lagrasse Olivier 
 *  @author Johnny Jazeix
 *  @author Mathieu Faverge
 *
 */
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <list>
/* -- */
#include <otf.h>
/* -- */
#include "common/Errors.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityValue.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "parser/OTFParser/ParserDefinitionOTF.hpp"
#include "parser/OTFParser/ParserEventOTF.hpp"
/* -- */
using namespace std;

#define VITE_OTF_UNKNOWN_NOOP          "NoOp event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_COLLOP        "CollOp event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_BEGINCOLLOP   "BeginCollOp event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_ENDCOLLOP     "EndCollOp event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_EVENTCOMMENT  "EventComment event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_FILEOPERATION "FileOperation event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_BEGINFILEOP   "BeginFileOp event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_ENDFILEOP     "EndFileOp event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_RMAPUT        "RMAPut event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_RMAPUTRE      "RMAPutRe event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_RMAGET        "RMAGet event is actually not handled in ViTE"
#define VITE_OTF_UNKNOWN_RMAEND        "RMAEnd event is actually not handled in ViTE"

uint64_t ParserEventOTF::_cur_time = 0;
uint64_t ParserEventOTF::_min_time = 0;
uint64_t ParserEventOTF::_max_time = 0;
map <const String, Container *, String::less_than> ParserEventOTF::_containers;
std::map<uint32_t, Marker > ParserEventOTF::_marker;

ParserEventOTF::ParserEventOTF() : _handlers(OTF_HandlerArray_open()) {
}

ParserEventOTF::~ParserEventOTF() {
    OTF_HandlerArray_close(_handlers);
    _containers.clear();
}

void ParserEventOTF::set_handlers(Trace *t) {
    // Handlers for OTF event records
    SET_HANDLER(_handlers, handler_NoOp, t, OTF_NOOP_RECORD);
    SET_HANDLER(_handlers, handler_Enter, t, OTF_ENTER_RECORD);
    SET_HANDLER(_handlers, handler_Leave, t, OTF_LEAVE_RECORD);
    SET_HANDLER(_handlers, handler_SendMsg, t, OTF_SEND_RECORD);
    SET_HANDLER(_handlers, handler_RecvMsg, t, OTF_RECEIVE_RECORD);
    SET_HANDLER(_handlers, handler_Counter, t, OTF_COUNTER_RECORD);
    SET_HANDLER(_handlers, handler_CollectiveOperation, t, OTF_COLLOP_RECORD);
    SET_HANDLER(_handlers, handler_BeginCollectiveOperation, t, OTF_BEGINCOLLOP_RECORD);
    SET_HANDLER(_handlers, handler_EndCollectiveOperation, t, OTF_ENDCOLLOP_RECORD);
    SET_HANDLER(_handlers, handler_EventComment, t, OTF_EVENTCOMMENT_RECORD);
    SET_HANDLER(_handlers, handler_BeginProcess, t, OTF_BEGINPROCESS_RECORD);
    SET_HANDLER(_handlers, handler_EndProcess, t, OTF_ENDPROCESS_RECORD);
    SET_HANDLER(_handlers, handler_FileOperation, t, OTF_FILEOPERATION_RECORD);
    SET_HANDLER(_handlers, handler_BeginFileOperation, t, OTF_BEGINFILEOP_RECORD);
    SET_HANDLER(_handlers, handler_EndFileOperation, t, OTF_ENDFILEOP_RECORD);
    SET_HANDLER(_handlers, handler_RMAPut, t, OTF_RMAPUT_RECORD);
    SET_HANDLER(_handlers, handler_RMAPutRemoteEnd, t, OTF_RMAPUTRE_RECORD);
    SET_HANDLER(_handlers, handler_RMAGet, t, OTF_RMAGET_RECORD);
    SET_HANDLER(_handlers, handler_RMAEnd, t, OTF_RMAEND_RECORD);

    // Handlers for OTF marker records
    SET_HANDLER(_handlers, handler_DefMarker, t, OTF_DEFMARKER_RECORD);
    SET_HANDLER(_handlers, handler_Marker,    t, OTF_MARKER_RECORD);
}

//
// Start definition of handlers for OTF event records
//
int ParserEventOTF::handler_NoOp( void* userData,
                                  uint64_t time,
                                  uint32_t process,
                                  OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_NOOP, 0, Error::VITE_ERRCODE_WARNING);
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_Enter( void* userData,
                                   uint64_t time,
                                   uint32_t func_id,
                                   uint32_t proc_id,
                                   uint32_t source,
                                   OTF_KeyValueList *list )
{
    Trace *t = (Trace *)userData;
    
    Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();

    Function &temp_function = ParserDefinitionOTF::get_function_by_id(func_id);
    const FunctionGroup temp_function_group = ParserDefinitionOTF::get_function_group_by_id(temp_function._func_group);
    Process temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);
    const ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(proc_id);

    const String function_name = String(temp_function._name);
    const String function_group_name = String(temp_function_group._name);
    const String proc_name = String(temp_proc._name);

    Container *temp_container = NULL;
    ContainerType *temp_container_type = t->search_container_type(String(process_group._name));

    StateType *temp_state_type = t->search_state_type(function_group_name);
    EntityValue *temp_value = NULL;
    map<string, Value *> extra_fields;
    
    if(_containers.find(proc_name) != _containers.end()) {
        temp_container = _containers[proc_name];
    }
    else {
        temp_container = t->search_container(proc_name);
        _containers[proc_name] = temp_container;
    }

    if(temp_state_type == 0) {
        Name name_temp(temp_function_group._name, "");
        t->define_state_type(name_temp, temp_container_type, extra_fields);
        temp_state_type = t->search_state_type(function_group_name);
    }

    if(!temp_function._is_defined) {
        temp_function._is_defined = true;
        
        Name name_temp(temp_function._name, "");
        map<string, Value *> opt;
        
        /* Optional fields */
        FileLine source_file_locator;
        FileSource source_file;
        
        if(temp_function._file_source != 0) {
            source_file_locator = ParserDefinitionOTF::get_fileline_by_id(temp_function._file_source);
            source_file = ParserDefinitionOTF::get_filesource_by_id(source_file_locator._file_id);
        }

        if(source_file._name != "") {
            opt["File name"] = new String(source_file._name);
            opt["Line"] = new Integer(source_file_locator._line_number);
        }
        
        opt["Color"] = ParserDefinitionOTF::get_color(func_id);

        t->define_entity_value(name_temp, t->search_entity_type(function_group_name), opt);
    }

    temp_value = t->search_entity_value(function_name, temp_state_type);


    if(temp_container == NULL && temp_proc._name != "0") {
        // Creation of the container if not already done with beginProcess
        handler_BeginProcess(userData, time, proc_id, NULL);
        temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);
        temp_container = t->search_container(proc_name);
        temp_container_type = t->search_container_type(proc_name);
    }

    // Check if nothing is empty
    if(temp_state_type == 0 && temp_function_group._name != "0") {
        Error::set(Error::VITE_ERR_UNKNOWN_STATE_TYPE + temp_function_group._name, Error::VITE_ERRCODE_ERROR);
    }
    if(temp_container == 0 && temp_proc._name != "0") {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER + temp_function_group._name, Error::VITE_ERRCODE_ERROR);
    }
    if(temp_value == 0 && temp_proc._name != "0") {
        Error::set(Error::VITE_ERR_UNKNOWN_ENTITY_VALUE + temp_proc._name, Error::VITE_ERRCODE_ERROR);
    }

    t->set_state(d, temp_state_type, temp_container, temp_value, extra_fields);
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_Leave( void* userData,
                                   uint64_t time,
                                   uint32_t func_id,
                                   uint32_t proc_id,
                                   uint32_t source,
                                   OTF_KeyValueList *list )
{
    //Trace *t = (Trace *)userData;
    
    //Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();

    //Function temp_function = ParserDefinitionOTF::get_function_by_id(func_id);
    //Process temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);

    //StateType *temp_type = t->search_state_type(String(temp_function._name));
    //Container *temp_container = t->search_container(String(temp_proc._name));
    //EventType *temp_event_type = t->search_event_type(String(temp_function._name));
    //EntityValue *temp_value = t->search_entity_value(String(temp_function._name), temp_event_type);
    //map<string, Value *> extra_fields;

    //t->set_state(d, temp_type, temp_container, temp_value, extra_fields);
    //t->pop_state(d, temp_type, temp_container, extra_fields);

    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_SendMsg( void* userData,
                                     uint64_t time,
                                     uint32_t sender,
                                     uint32_t receiver,
                                     uint32_t group,
                                     uint32_t type,
                                     uint32_t length,
                                     uint32_t source,
                                     OTF_KeyValueList *list )
{
    // We define the LinkType if not exist and we store the time and other fields
    Trace *t  = (Trace *)userData;
    Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();
    
    Process temp_sender = ParserDefinitionOTF::get_process_by_id(sender);
    Process temp_receiver = ParserDefinitionOTF::get_process_by_id(receiver);
    // The sender process may have no ancestor, so let's say that his ancestor is himself
    Process temp_ancestor = temp_sender;
    ProcessGroup sender_group = ParserDefinitionOTF::get_processgroup_by_process(sender);
    ProcessGroup receiver_group = ParserDefinitionOTF::get_processgroup_by_process(receiver);
    ProcessGroup ancestor_group = ParserDefinitionOTF::get_processgroup_by_process(temp_sender._parent);

    String sender_string = String(temp_sender._name);
    String ancestor_string = String(temp_ancestor._name);
    String receiver_string = String(temp_receiver._name);

    String sender_group_string = String(sender_group._name);
    String ancestor_group_string = String(ancestor_group._name);
    String receiver_group_string = String(receiver_group._name);

    /* Value */
    string name = temp_sender._name + " to " + temp_receiver._name;
    String name_string = String(name);

    ostringstream link_type_oss;
    link_type_oss << type;
    String link_type_string = String(link_type_oss.str());

    Name name_temp = Name(name, "");
    LinkType *link_type = t->search_link_type(link_type_string);
    
    Container *source_container = NULL;
    Container *ancestor_container = NULL;

    ContainerType *source_type = t->search_container_type(sender_group_string);
    ContainerType *destination_type = t->search_container_type(receiver_group_string);
    ContainerType *ancestor_type = t->search_container_type(ancestor_group_string);

    EntityValue *value;

    map<string, Value *> opt;
    
    if(_containers.find(sender_string) != _containers.end()) {
        source_container = _containers[sender_string];
    }
    else {
        source_container = t->search_container(sender_string);
        _containers[sender_string] = source_container;
    }

    if(_containers.find(ancestor_string) != _containers.end() && !_containers.empty()) {
        // found
        ancestor_container = _containers[ancestor_string];
    }
    else {
        // receiver not found
        ancestor_container = t->search_container(ancestor_string);
        if(ancestor_container) {
	    _containers[ancestor_string] = ancestor_container;
        }
    }

    if(ancestor_type == 0) {
        // No ancestor
        ancestor_type = source_type;
    }

    if(ancestor_container == 0) {
        // No ancestor
        ancestor_container = source_container;
    }

    if(link_type == 0) {
        Name link_name = Name(link_type_oss.str(), "");
        t->define_link_type(link_name, ancestor_type, destination_type, destination_type, opt);
        link_type = t->search_link_type(link_type_string);
    }

    value = t->search_entity_value(name_string, link_type);

    // Check if nothing is empty
    if(source_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE + temp_sender._name, Error::VITE_ERRCODE_ERROR);
    }
    if(destination_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE + temp_receiver._name, Error::VITE_ERRCODE_ERROR);
    }
    if(ancestor_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE + temp_ancestor._name, Error::VITE_ERRCODE_ERROR);
    }
    if(link_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_LINK_TYPE + link_type_oss.str(), Error::VITE_ERRCODE_ERROR);
    }

    /* Creation of the optional fields */
    if(group != 0) {
        ProcessGroup proc_group = ParserDefinitionOTF::get_processgroup_by_id(group);
        String *proc_group_string = new String(proc_group._name);
        opt["ProcessGroup"] = proc_group_string;
    }

    if(length != 0) {
        Integer *length_int = new Integer(length);
        opt["Length"] = length_int;
    }

    if(source != 0) {
        FileLine source_file_locator;
        FileSource source_file;
        source_file_locator = ParserDefinitionOTF::get_fileline_by_id(source);
        source_file = ParserDefinitionOTF::get_filesource_by_id(source_file_locator._file_id);
        if(source_file._name != "") {
            opt["File name"] = new String(source_file._name);
            opt["Line"] = new Integer(source_file_locator._line_number);
        }
    }

    t->start_link(d, link_type, ancestor_container, source_container, value, name_string, opt);

    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_RecvMsg( void* userData,
                                     uint64_t time,
                                     uint32_t receiver,
                                     uint32_t sender,
                                     uint32_t group,
                                     uint32_t type,
                                     uint32_t length,
                                     uint32_t source,
                                     OTF_KeyValueList *list )
{

    Trace *t  = (Trace *)userData;
    Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();

    Process temp_sender = ParserDefinitionOTF::get_process_by_id(sender);
    Process temp_receiver = ParserDefinitionOTF::get_process_by_id(receiver);
    // The sender process may have no ancestor, so let's say that his ancestor is himself
    Process temp_ancestor = temp_sender;
    String sender_string = String(temp_sender._name);
    String ancestor_string = String(temp_ancestor._name);
    String receiver_string = String(temp_receiver._name);

    ProcessGroup sender_group = ParserDefinitionOTF::get_processgroup_by_process(sender);
    ProcessGroup receiver_group = ParserDefinitionOTF::get_processgroup_by_process(receiver);
    ProcessGroup ancestor_group = ParserDefinitionOTF::get_processgroup_by_process(temp_sender._parent);

    String sender_group_string = String(sender_group._name);
    String ancestor_group_string = String(ancestor_group._name);
    String receiver_group_string = String(receiver_group._name);

    /* Value */
    string name = temp_sender._name + " to " + temp_receiver._name;
    
    String name_string = String(name);

    ostringstream link_type_oss;
    link_type_oss << type;
    String link_type_string = String(link_type_oss.str());

    Name name_temp = Name(name, "");
    LinkType *link_type = t->search_link_type(link_type_string);

    Container *destination_cont = NULL;
    Container *ancestor_cont = NULL;
    Container *sender_cont = NULL;

    ContainerType *destination_type = t->search_container_type(receiver_group_string);
    ContainerType *ancestor_type = t->search_container_type(ancestor_group_string);
    ContainerType *sender_type = t->search_container_type(sender_group_string);

    EntityValue *value;

    map<string, Value *> opt;

    if(_containers.find(receiver_string) != _containers.end()) {
        destination_cont = _containers[receiver_string];
    }
    else {
        destination_cont = t->search_container(receiver_string);
        _containers[receiver_string] = destination_cont;
    }

    if(_containers.find(ancestor_string) != _containers.end() && !_containers.empty()) {
        ancestor_cont = _containers[ancestor_string];
    }
    else {
        ancestor_cont = t->search_container(ancestor_string);
        if(ancestor_cont)
	    _containers[ancestor_string] = ancestor_cont;
    }

    if(ancestor_type == 0) {
        // No ancestor
        ancestor_type = sender_type;
    }

    if(ancestor_cont == 0) {
        // No ancestor
        ancestor_cont = sender_cont;
    }

    if(link_type == 0) {
        Name link_name = Name(link_type_oss.str(), "");
        t->define_link_type(link_name, ancestor_type, destination_type, destination_type, opt);
        link_type = t->search_link_type(link_type_string);
    }

    value = t->search_entity_value(name_string, link_type);

    // Check if nothing is empty
    if(destination_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE + temp_receiver._name, Error::VITE_ERRCODE_ERROR);
    }
    if(ancestor_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE + temp_ancestor._name, Error::VITE_ERRCODE_ERROR);
    }
    if(link_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_LINK_TYPE + link_type_oss.str(), Error::VITE_ERRCODE_ERROR);
    }

    /* Creation of the optional fields */
    if(group != 0) {
        ProcessGroup proc_group = ParserDefinitionOTF::get_processgroup_by_id(group);
        String *proc_group_string = new String(proc_group._name);
        opt["ProcessGroup"] = proc_group_string;
    }

    if(length != 0) {
        Integer *length_int = new Integer(length);
        opt["Length"] = length_int;
    }

    if(source != 0) {
        FileLine source_file_locator;
        FileSource source_file;
        source_file_locator = ParserDefinitionOTF::get_fileline_by_id(source);
        source_file = ParserDefinitionOTF::get_filesource_by_id(source_file_locator._file_id);
        if(source_file._name != "") {
            opt["File name"] = new String(source_file._name);
            opt["Line"] = new Integer(source_file_locator._line_number);
        }
    }

    t->end_link(d, link_type, ancestor_cont, destination_cont, value, name_string, opt);
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_Counter( void* userData,
                                     uint64_t time,
                                     uint32_t proc_id,
                                     uint32_t counter_id,
                                     uint64_t value,
                                     OTF_KeyValueList *list )
{
    Trace *t = (Trace *)userData;
    Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();

    Counter temp_counter = ParserDefinitionOTF::get_counter_by_id(counter_id);
    Process temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);
    CounterGroup temp_counter_group = ParserDefinitionOTF::get_counter_group_by_id(temp_counter._counter_group);
    Container *temp_container = NULL;
    map<string, Value *> extra_fields;

    String counter_name = String(temp_counter._name);

    VariableType *temp_variable_type = t->search_variable_type(counter_name);
    ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(proc_id);
    ContainerType *temp_container_type = t->search_container_type(String(process_group._name));

    const String temp_proc_name = String(temp_proc._name);

    if(_containers.find(temp_proc_name) != _containers.end()) {
        temp_container = _containers[temp_proc_name];
    }
    else {
        temp_container = t->search_container(temp_proc_name);
        _containers[temp_proc_name] = temp_container;
    }

    if(temp_variable_type == 0) {
        // cannot find this counter. Define it.
        Name name_temp(counter_name);
        t->define_variable_type(name_temp, temp_container_type, extra_fields);
        temp_variable_type = t->search_variable_type(counter_name);
    }

    if(temp_container == NULL && temp_proc._name != "0") {
        // Creation of the container if not already done with beginProcess
        handler_BeginProcess(userData, time, proc_id, NULL);
        temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);
        temp_container = t->search_container(temp_proc_name);
    }

    // Check if nothing is empty
    if(temp_variable_type == 0 && temp_counter_group._name != "0") {
        Error::set(Error::VITE_ERR_UNKNOWN_VARIABLE_TYPE + temp_counter_group._name, Error::VITE_ERRCODE_ERROR);
    }
    if(temp_container == 0 && temp_proc._name != "0") {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER + temp_counter_group._name, Error::VITE_ERRCODE_ERROR);
    }

    t->set_variable(d, temp_variable_type, temp_container, value, extra_fields);
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_CollectiveOperation( void* userData,
                                                 uint64_t time,
                                                 uint32_t process,
                                                 uint32_t collective,
                                                 uint32_t procGroup,
                                                 uint32_t rootProc,
                                                 uint32_t sent,
                                                 uint32_t received,
                                                 uint64_t duration,
                                                 uint32_t source,
                                                 OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_COLLOP, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_BeginCollectiveOperation( void* userData,
                                                      uint64_t time,
                                                      uint32_t process,
                                                      uint32_t collOp,
                                                      uint64_t matchingId,
                                                      uint32_t procGroup,
                                                      uint32_t rootProc,
                                                      uint64_t sent,
                                                      uint64_t received,
                                                      uint32_t scltoken,
                                                      OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_BEGINCOLLOP, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_EndCollectiveOperation( void* userData,
                                                    uint64_t time,
                                                    uint32_t process,
                                                    uint64_t matchingId,
                                                    OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_ENDCOLLOP, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_EventComment( void* userData,
                                          uint64_t time,
                                          uint32_t process,
                                          const char* comment,
                                          OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_EVENTCOMMENT, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_BeginProcess( void* userData,
                                          uint64_t time,
                                          uint32_t process,
                                          OTF_KeyValueList *list )
{
    Trace *t = (Trace *)userData;

    Process      current_process = ParserDefinitionOTF::get_process_by_id(process);
    Process      process_parent  = ParserDefinitionOTF::get_process_by_id(current_process._parent);
    ProcessGroup process_group   = ParserDefinitionOTF::get_processgroup_by_process(process);

    map<string, Value *> extra_fields;
    Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();
    Name n = Name(current_process._name, "");
    
    ContainerType *process_container_type = t->search_container_type(String(process_group._name));
    Container *parent_container = t->search_container(String(process_parent._name));

    if(t->search_container(String(current_process._name))) {
        return OTF_RETURN_OK; // Already created so we quit the function
    }

    if(process_container_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE + process_group._name, 
                   Error::VITE_ERRCODE_ERROR);
    }
    if(parent_container == 0 && process_parent._name != "0") {
        // Create the parent process
        handler_BeginProcess(userData, time, current_process._parent, NULL);
        parent_container = t->search_container(String(process_parent._name));
    }

    t->create_container(d, n, process_container_type, parent_container, extra_fields);

    // We store the container in the map
    _containers[n.to_string()] = t->search_container(n.to_string());

    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_EndProcess( void* userData,
                                        uint64_t time,
                                        uint32_t proc_id,
                                        OTF_KeyValueList *list )
{
    Trace *t = (Trace *)userData;
        
    Process process = ParserDefinitionOTF::get_process_by_id(proc_id);
    ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(proc_id);

    map<string, Value *> extra_fields;
    Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();

    Container *temp_container = NULL;
    ContainerType *temp_container_type = t->search_container_type(String(process_group._name));

    const String process_name = String(process._name);
    if(_containers.find(process_name) != _containers.end()) {
        temp_container = _containers[process_name];
    }
    else {
        temp_container = t->search_container(process_name);
        _containers[process_name] = temp_container;
    }

    if(temp_container_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER_TYPE + process_group._name, Error::VITE_ERRCODE_ERROR);
    }
    else if(temp_container == 0 && process._name != "0") {
        Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER + process._name, Error::VITE_ERRCODE_ERROR);
    }

    t->destroy_container(d, temp_container, temp_container_type, extra_fields);
    return OTF_RETURN_OK;
}


int ParserEventOTF::handler_FileOperation( void* userData,
                                           uint64_t time,
                                           uint32_t fileid,
                                           uint32_t process,
                                           uint64_t handleid,
                                           uint32_t operation,
                                           uint64_t bytes,
                                           uint64_t duration,
                                           uint32_t source,
                                           OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_FILEOPERATION, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_BeginFileOperation( void* userData,
                                                uint64_t time,
                                                uint32_t process,
                                                uint64_t matchingId,
                                                uint32_t scltoken,
                                                OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_BEGINFILEOP, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_EndFileOperation( void* userData,
                                              uint64_t time,
                                              uint32_t process,
                                              uint32_t fileid,
                                              uint64_t matchingId,
                                              uint64_t handleId,
                                              uint32_t operation,
                                              uint64_t bytes,
                                              uint32_t scltoken,
                                              OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_ENDFILEOP, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_RMAPut( void* userData,
                                    uint64_t time,
                                    uint32_t process,
                                    uint32_t origin,
                                    uint32_t target,
                                    uint32_t communicator,
                                    uint32_t tag,
                                    uint64_t bytes,
                                    uint32_t source,
                                    OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_RMAPUT, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_RMAPutRemoteEnd( void* userData,
                                             uint64_t time,
                                             uint32_t process,
                                             uint32_t origin,
                                             uint32_t target,
                                             uint32_t communicator,
                                             uint32_t tag,
                                             uint64_t bytes,
                                             uint32_t source,
                                             OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_RMAPUTRE, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_RMAGet( void* userData,
                                    uint64_t time,
                                    uint32_t process,
                                    uint32_t origin,
                                    uint32_t target,
                                    uint32_t communicator,
                                    uint32_t tag,
                                    uint64_t bytes,
                                    uint32_t source,
                                    OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_RMAGET, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_RMAEnd( void* userData,
                                    uint64_t time,
                                    uint32_t process,
                                    uint32_t remote,
                                    uint32_t communicator,
                                    uint32_t tag,
                                    uint32_t source,
                                    OTF_KeyValueList *list )
{
    Error::set( VITE_OTF_UNKNOWN_RMAEND, 0, Error::VITE_ERRCODE_WARNING );
    return OTF_RETURN_OK;
}


//
// Start definition of handlers for OTF marker records
//
int ParserEventOTF::handler_DefMarker(void *, 
                                      uint32_t stream, 
                                      uint32_t id, 
                                      const char *name, 
                                      uint32_t type,
                                      OTF_KeyValueList *list ) 
{
    Marker temp = {name, stream, type};
    ParserEventOTF::_marker[id] = temp;
    return OTF_RETURN_OK;
}

int ParserEventOTF::handler_Marker(void *trace, 
                                   uint64_t time, 
                                   uint32_t proc_id, 
                                   uint32_t id, 
                                   const char *text,
                                   OTF_KeyValueList *list ) 
{
    Trace *t = (Trace *)trace;
    Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();

    Marker temp_marker = _marker[id];
    Process temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);
    Container *temp_container = NULL;
    map<string, Value *> extra_fields;

    String str_eventType(temp_marker._name);
    String str_event(text);
    Name n(text, "");
    EventType *event_type = t->search_event_type(str_eventType);

    ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(proc_id);
    ContainerType *temp_container_type = t->search_container_type(String(process_group._name));
    EntityValue *value = NULL;

    const String temp_proc_name = String(temp_proc._name);
 
    if(_containers.find(temp_proc_name) != _containers.end()) {
        temp_container = _containers[temp_proc_name];
    }
    else {
        temp_container = t->search_container(temp_proc_name);
        _containers[temp_proc_name] = temp_container;
    }

    if(event_type == 0) {
        Name name_temp(temp_marker._name, "");
        t->define_event_type(name_temp, temp_container_type, extra_fields);
        event_type = t->search_event_type(str_eventType);
    }

    value = t->search_entity_value(str_event, event_type);

    if(temp_container == NULL && temp_proc._name != "0") {
        // Creation of the container if not already done with beginProcess
        handler_BeginProcess(trace, time, proc_id, NULL);
        temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);
        temp_container = t->search_container(temp_proc_name);
    }

    // Check if nothing is empty
    if(event_type == 0) {
        Error::set(Error::VITE_ERR_UNKNOWN_EVENT_TYPE + n.to_string(), Error::VITE_ERRCODE_ERROR);
    }
    if(temp_container == 0 && temp_proc._name != "0") {
        //Error::set(Error::VITE_ERR_UNKNOWN_CONTAINER + temp_counter_group._name, Error::VITE_ERRCODE_ERROR);
    }

    t->new_event(d, event_type, temp_container, value, extra_fields);
    return OTF_RETURN_OK;
}


//
//  End of all handlers
//

int ParserEventOTF::read_events(OTF_Reader *reader) {
    int return_value = OTF_Reader_readEvents(reader, _handlers);
    OTF_Reader_eventTimeProgress(reader, 
                                 &ParserEventOTF::_min_time, 
                                 &ParserEventOTF::_cur_time, 
                                 &ParserEventOTF::_max_time);
    return return_value;
}

void ParserEventOTF::read_markers(OTF_Reader *reader) {
    OTF_Reader_readMarkers(reader, _handlers);
}

void ParserEventOTF::set_number_event_read_by_each_pass(OTF_Reader *reader, int number) {
    OTF_Reader_setRecordLimit(reader, number);
}

float ParserEventOTF::get_percent_loaded() {
    if(ParserEventOTF::_max_time != ParserEventOTF::_min_time) {
        return (float)(ParserEventOTF::_cur_time - ParserEventOTF::_min_time) / 
               (float)(ParserEventOTF::_max_time - ParserEventOTF::_min_time) ;
    }
    else {
        return 0.0f;
    }
}
