/**
 *
 * @file tests/stubs/Errors.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Mathieu Faverge
 *
 * @date 2024-07-17
 */
#include "Errors.hpp"

using namespace std;

queue<string> Error::_errors;
queue<string> Error::_warnings;

const int Error::_EVERYTHING = 0;
const int Error::_WARNING = 1;
const int Error::_ERROR = 2;

string Error::_content = "";

const string Error::_PARSE = "expected \" before end of file";
const string Error::_MMAP = "mmap error";
const string Error::_EMPTY_FILE = "empty file";
const string Error::_FSTAT = "status file error";
const string Error::_OPEN = "open file error";
const string Error::_MUNMAP = "munmap error";
const string Error::_EXPECT_END_DEF = "expected %EndEventDef";
const string Error::_EXPECT_EVENT_DEF = "expected %EventDef";
const string Error::_EXPECT_NAME_DEF = "the definition is not named";
const string Error::_EXPECT_ID_DEF = "the definition is not identified";
const string Error::_UNKNOWN_ID_DEF = "there is no definition with the identity: ";
const string Error::_EXTRA_TOKEN = "extra token(s) ignored";
const string Error::_UNKNOWN_EVENT_DEF = "the following event doesn't match with any event known: ";
const string Error::_FIELD_TYPE_MISSING = "a field type is missing ";
const string Error::_FIELD_TYPE_UNKNOWN = "the following field type is unknown: ";
const string Error::_EMPTY_DEF = "a definition line is empty";
const string Error::_INCOMPATIBLE_VALUE_IN_EVENT = "incompatible value: ";
const string Error::_BAD_FILE_EXTENSION = "the extension of the file is not .trace";
const string Error::_LINE_TOO_SHORT_EVENT = "missing field value(s) in an event";

const string Error::_UNKNOWN_CONTAINER_TYPE = "Unknown container type: ";
const string Error::_UNKNOWN_CONTAINER = "Unknown container: ";
const string Error::_UNKNOWN_EVENT_TYPE = "Unknown event type: ";
const string Error::_UNKNOWN_STATE_TYPE = "Unknown state type: ";
const string Error::_UNKNOWN_VARIABLE_TYPE = "Unknown variable type: ";
const string Error::_UNKNOWN_LINK_TYPE = "Unknown link type: ";
const string Error::_UNKNOWN_ENTITY_TYPE = "Unknown entity type: ";

void Error::set(const string &kind_of_error, const int priority) {
    Error::_content = kind_of_error;
    switch (priority) {
    case _WARNING:
        Error::_warnings.push(Error::_content);
        break;
    default: // Include the _ERROR
        Error::_errors.push(Error::_content);
        break;
    }
}

void Error::set(const string &kind_of_error, const unsigned int line_number, const int priority) {
    char line[10];
    sprintf(line, "%u", line_number);
    set(kind_of_error + " on line " + line, priority);
}

void Error::set_and_print(const string &kind_of_error, const int priority) {
    set(kind_of_error, priority);
    print(priority);
}

void Error::set_and_print(const string &kind_of_error, const unsigned int line_number, const int priority) {
    char line[10];
    sprintf(line, "%u", line_number);
    set(kind_of_error + " on line " + line, priority);
    print(priority);
}

bool Error::set_if(bool condition, const string &kind_of_error, const unsigned int line_number, const int priority) {
    if (condition) {
        char line[10];
        sprintf(line, "%u", line_number);
        set(kind_of_error + " on line " + line, priority);
        return true;
    }
    return false;
}

void Error::print(const int priority) {
    cerr << _content;
    switch (priority) {
    case _WARNING:
        cerr << " warning" << endl;
        break;
    default: // Include the _ERROR
        cerr << " error" << endl;
        break;
    }
}

void Error::print(const string &content, const int priority) {
    cerr << content;
    switch (priority) {
    case _WARNING:
        cerr << " warning" << endl;
        break;
    default: // Include the _ERROR
        cerr << " error" << endl;
        break;
    }
}

void Error::print_numbers() {
    cerr << Error::_errors.size() << " errors and " << Error::_warnings.size() << " warnings were found during parsing.";
    if (Error::_warnings.size() == 0 && Error::_errors.size() == 0) {
        cerr << " info" << endl;
    }
    else if (Error::_errors.size() == 0) {
        cerr << " warning" << endl;
    }
    else {
        cerr << " error" << endl;
    }
}

void Error::flush(const string &filename) {

    if (_errors.empty() && _warnings.empty()) {
        return;
    }
    else {

        const int number_of_errors = Error::_errors.size();
        const int number_of_warnings = Error::_warnings.size();

        // Print the errors
        while (!_errors.empty()) {
            _errors.pop();
        }

        while (!_warnings.empty()) {
            _warnings.pop();
        }

        cerr << endl
             << "Your trace has " << number_of_errors << " errors and " << number_of_warnings << " warnings." << endl;
    }
}
