// ========================================================================== //
// Class inclusion
#include "Utilities/string_operations.hpp"

// Standard libraries
#include <filesystem>
#include <iostream>
#include <map>
#include <string>

// Parallelisation
#if USE_MPI == 1
    #include <mpi.h>
#endif

// Macros
#ifndef MPI_VERSION
    #define MPI_VERSION 0
#endif

// Convert input string to a boolean
bool Utilities::stob(const std::string &input) {

    // Map of possible values.
    const std::map<std::string, bool> reader = {
        {"0", false}, {"false", false}, {"False", false}, {"FALSE", false},
        {"1", true},  {"true", true},   {"True", true},   {"TRUE", true},
    };

    return reader.at(input);
}

// Debug function used to properly print debug messages
void Utilities::debug_info(const std::string &message, const bool &toggle) {

    if (!toggle) return;

#if MPI_VERSION > 0
    int mpi_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
    if (mpi_rank != 0) return;
#endif

    static size_t previous = 0;
    if (previous == std::hash<std::string>{}(message)) return;
    previous = std::hash<std::string>{}(message);

    // Print warning message
    std::cout << "Debug: " << message << std::endl;
}
// Debug function used to properly print debug messages
void Utilities::debug_info(const std::string &file_name, const int &line_number,
                           const std::string &message, const bool &toggle) {

    if (!toggle) return;

#if MPI_VERSION > 0
    int mpi_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
    if (mpi_rank != 0) return;
#endif

    static size_t previous = 0;
    if (previous == std::hash<std::string>{}(message)) return;
    previous = std::hash<std::string>{}(message);

    // Print warning message
    printf("Debug: %s:%d\n\t%s", file_name.c_str(), line_number,
           message.c_str());
    std::cout << std::endl;
}
// Error function used to properly print error messages
void Utilities::error(const std::string &file_name, const int &line_number,
                      const std::string &message) {

#if MPI_VERSION > 0
    int mpi_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
    if (mpi_rank == 0) {
#endif
        fprintf(stderr, "error: %s:%d\n\t%s", file_name.c_str(), line_number,
                message.c_str());
        std::cerr << std::endl;

#if MPI_VERSION > 0
    }
    MPI_Finalize();
#endif
    exit(EXIT_FAILURE);
}
// Warning function used to properly print warning messages
void Utilities::warning(const std::string &file_name, const int &line_number,
                        const std::string &message) {

#if MPI_VERSION > 0
    int mpi_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
    if (mpi_rank != 0) return;
#endif
    printf("warning: %s:%d\n\t%s", file_name.c_str(), line_number,
           message.c_str());
    std::cout << std::endl;
}

void Utilities::valid_directory(const std::string &location) {

#if MPI_VERSION > 0
    int mpi_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
    while (mpi_rank != 0 && !std::filesystem::is_directory(location)) {}
#endif

    if (!std::filesystem::is_directory(location))
        std::filesystem::create_directory(location);

    // If the directory exist or can be created return
    if (!std::filesystem::is_directory(location))
        error(__FILE__, __LINE__,
              "Directory does not exist and could not be created:\n\t" +
                  location);
}

// End of File
// ========================================================================== //