/**
 *
 * @file src/parser/PajeParser/BuilderThread.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Augustin Degomme
 * @author Mathieu Faverge
 *
 * @date 2024-07-17
 */
#include <fstream>
#include <list>
#include <map>
#include <queue>
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "parser/Parser.hpp"
#include "parser/PajeParser/mt_PajeFileManager.hpp"
#include "parser/PajeParser/ParserDefinitionPaje.hpp"
#include "parser/PajeParser/mt_ParserEventPaje.hpp"
/* -- */
#include "parser/PajeParser/BuilderThread.hpp"
#include "trace/TraceBuilderThread.hpp"

BuilderThread::BuilderThread(mt_ParserEventPaje *p, Trace *trace,
                             QWaitCondition *cond, QWaitCondition *trace_cond,
                             QSemaphore *sem1, QSemaphore *sem2, QMutex *mutex,
                             QMutex *mutex2, Parser *parser) {
    _event_parser = p;
    _parser = parser;
    _cond = cond;
    _trace_cond = trace_cond;
    _freeSlots = sem1;
    _mutex = mutex;
    _mutex2 = mutex2;
    _linesProduced = sem2;
    _trace = trace;
    _is_finished = false;
}

void BuilderThread::run(unsigned int n, PajeLine *line) {

    _freeSlots->acquire(); // do not produce too fast (5 blocks max at a time)

    int n_without_errors = 0;
    Trace_builder_struct *tb_structs = new Trace_builder_struct[n];
    unsigned int j;
    for (j = 0; j < n; j++) {
        tb_structs[n_without_errors]._parser = _parser;
        if (_event_parser->store_event(&line[j], *_trace, &tb_structs[n_without_errors]) == 0)
            n_without_errors++;
        free(line[j]._tokens); // release tokens allocated in the PajeFileManager
    }
    Q_EMIT build_trace(n_without_errors, tb_structs);
    _linesProduced->release();
    free(line);
}

bool BuilderThread::is_finished() { return _is_finished; }
void BuilderThread::finish_build() {
    // quit();
    // finish the TraceBuilderThread before closing this one
    // locks the mutex and automatically unlocks it when going out of scope
    QMutexLocker locker2(_mutex2);
    Q_EMIT build_finished();
    _trace_cond->wait(_mutex2);
    locker2.unlock();

    _is_finished = true;
    // locks the mutex and automatically unlocks it when going out of scope
    QMutexLocker locker(_mutex);
    _cond->wakeAll();
}

#include "moc_BuilderThread.cpp"
