/**
 *
 * @file src/parser/PajeParser/ParserVite.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Olivier Lagrasse
 * @author Mathieu Faverge
 *
 * @date 2024-07-17
 */

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <map>
#include <list>
#include <stack>
/* -- */
#include <QDir>
#include <QFileInfo>
/* -- */
#include "common/Errors.hpp"
/* -- */
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "parser/Parser.hpp"
#include "parser/PajeParser/ParserVite.hpp"
#include "parser/PajeParser/PajeFileManager.hpp"
#include "parser/PajeParser/ParserPaje.hpp"
#include "parser/PajeParser/ParserEventPaje.hpp"
#include "parser/PajeParser/ParserDefinitionPaje.hpp"
/* -- */
using namespace std;

ParserVite::ParserVite() = default;
ParserVite::ParserVite(const std::string &filename) :
    Parser(filename) { }
ParserVite::~ParserVite() = default;

void ParserVite::parse(Trace &trace,
                       bool finish_trace_after_parse) {

    const std::string filename = get_next_file_to_parse();
    while (filename != "") {

        ParserPaje parserpaje(filename);
        QString name;
        stack<Container *> CTstack;
        const Container::Vector *root_containers;
        const map<std::string, Value *> *extra_fields;
        map<string, Value *>::const_iterator fnamefield;

        // Store the absolute directory of the first file for relative path in the others
        QString absdir = QFileInfo(QString::fromStdString(filename.c_str())).absolutePath();

        // Parse the first file with definitions
        try {
            parserpaje.parse(trace, false);
        } catch (...) {
            finish();
            trace.finish();
            return;
        }

#ifdef DBG_PARSER_VITE
        std::cerr << "First file parsed" << std::endl;
        std::cerr << "Add container : ";
#endif

        /* Loop over root containers to add them in the stack */
        root_containers = trace.get_root_containers();

        for (const auto &root_container: *root_containers) {
#ifdef DBG_PARSER_VITE
            std::cerr << "+";
#endif
            CTstack.push(root_container);
        }

#ifdef DBG_PARSER_VITE
        std::cerr << std::endl;
#endif

        /* Deep-First search over container to parse extra files */
        while (!CTstack.empty()) {
            Container *c = CTstack.top();
            CTstack.pop();

            extra_fields = c->get_extra_fields();
            fnamefield = extra_fields->find(string("FileName"));

            // Search the filename
            if (fnamefield != extra_fields->end()) {
                name = QString::fromStdString(((String *)(*fnamefield).second)->to_string());
            }
            else {
                name = QString();
            }

            if (!name.isEmpty()) {
#ifdef DBG_PARSER_VITE
                std::cerr << ((absdir + QDir::separator() + name).toStdString()) << std::endl;
#endif
                parserpaje.set_file_to_parse(QString(absdir + QDir::separator() + name).toStdString());

                try {
                    parserpaje.parse(trace, false);
                } catch (...) {
                    finish();
                    trace.finish();
                    return;
                }
            }

            // We add the children
            Container::VectorIt children_end = c->get_children()->end();
            for (Container::VectorIt i = c->get_children()->begin();
                 i != children_end; ++i) {
                CTstack.push(*i);
            }
        }

        finish();
    }
    if (finish_trace_after_parse) {
        trace.finish();
    }
}

float ParserVite::get_percent_loaded() const {
    // TODO when multithread :) else we cannot determine it except in computing the sum of all the file sizes and storing already loaded ^^
    return 0.5;
}
