/*
 ** 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 developpers are (for version 0.* to 1.0):
 **
 **        - COULOMB Kevin
 **        - FAVERGE Mathieu
 **        - JAZEIX Johnny
 **        - LAGRASSE Olivier
 **        - MARCOUEILLE Jule
 **        - NOISETTE Pascal
 **        - REDONDY Arthur
 **        - VUCHENER Clément
 **
 */
#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;
    }
}
