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

#include "Configuration.hpp"
#include "common/Session.hpp"
#include <QFileDialog>

#define SESSION_FILENAME(fname) QString::fromStdString("plugins/mv/files/" + fname)

Matrix_visualizer *Matrix_visualizer::s_plugin = nullptr;
SymbolParser Matrix_visualizer::s_symbol_parser;
OrderParser Matrix_visualizer::s_order_parser;
ValuesParser Matrix_visualizer::s_values_parser;
Matrix_window *Matrix_visualizer::s_matrix_window = nullptr;
symbol_matrix_t *Matrix_visualizer::s_matrix = nullptr;

// Functions to initialize the plugin in ViTE
Plugin *create() { return Matrix_visualizer::get_instance(); }

Matrix_visualizer *Matrix_visualizer::get_instance() {
    if (NULL == s_plugin) {
        s_plugin = new Matrix_visualizer();
    }

    return s_plugin;
}

void Matrix_visualizer::set_line_edit_defaults(QLineEdit *le, const std::string &name, std::string def_name) {
    Session &s = Session::getSession();
    QString lineedit_fname;
    QString session_fname;

    session_fname = SESSION_FILENAME(name);
    if (s.contains(session_fname)) {
        lineedit_fname = s.value(session_fname).toString();
    }
    else {
        lineedit_fname = QString::fromStdString(def_name);
    }
    le->setText(lineedit_fname);
}

// Plugin implementation itself
Matrix_visualizer::Matrix_visualizer() {
    setupUi(this);
    s_plugin = this;

    m_quadtree_button_checked = true;

    set_line_edit_defaults(this->line_edit_symbol, "symbol", "symbol.sps");
    set_line_edit_defaults(this->line_edit_order, "order", "order.ord");
    set_line_edit_defaults(this->line_edit_values, "values", "values.txt");
}

Matrix_visualizer::~Matrix_visualizer() {
}

void Matrix_visualizer::init() {
}

void Matrix_visualizer::clear() {
}

void Matrix_visualizer::set_arguments(std::map<std::string /*argname*/, QVariant * /*argValue*/>) {
}

std::string Matrix_visualizer::get_name() {
    return "Matrix visualizer";
}

int Matrix_visualizer::update_matrix(QString filepath) {
    Session &s = Session::getSession();

    symbol_matrix_t *new_matrix;

    // Check if there is a symbol file
    if (filepath.size() == 0) {
        Helper::log(LogStatus::FATAL, "Empty filepath for symbol matrix file...");
        return -1;
    }

    // Parse the symbol file if any
    Helper::log(LogStatus::MESSAGE, "Parsing symbol file...");
    new_matrix = s_symbol_parser.parse(filepath.toStdString(), nullptr);

    if (new_matrix == nullptr) {
        Helper::log(LogStatus::FATAL, "Parsed matrix is empty");
        return -1;
    }
    s.setValue(QStringLiteral("plugins/mv/files/symbol"), filepath);

    if (s_matrix != nullptr) {
        symbol_matrix_deinit(s_matrix);
    }
    s_matrix = new_matrix;

    Helper::log(LogStatus::MESSAGE, "Successfully read symbol file");
    symbol_matrix_print_stats(s_matrix);

    return 0;
}

int Matrix_visualizer::update_order(QString filepath) {
    void *rc;

    if (s_matrix == nullptr) {
        Helper::log(LogStatus::FATAL, "No symbol matrix has been loaded");
        return -1;
    }

    // Check if there is a symbol file
    if (filepath.size() == 0) {
        Helper::log(LogStatus::FATAL, "Empty filepath for order file...");
        return -1;
    }

    // Parse the symbol file if any
    Helper::log(LogStatus::MESSAGE, "Parsing order file...");
    rc = s_order_parser.parse(filepath.toStdString(), s_matrix);

    if (rc != nullptr) {
        Helper::log(LogStatus::FATAL, "Error parsing order file");
        return -1;
    }

    Helper::log(LogStatus::MESSAGE, "Successfully read order file");
    // symbol_matrix_print_stats(matrix);
    return 0;
}

int Matrix_visualizer::update_values(QString filepath) {
    void *rc;

    if (s_matrix == nullptr) {
        Helper::log(LogStatus::FATAL, "No symbol matrix has been loaded");
        return -1;
    }

    // Check if there is a symbol file
    if (filepath.size() == 0) {
        Helper::log(LogStatus::FATAL, "Empty filepath for values file...");
        return -1;
    }

    // Parse the symbol file if any
    Helper::log(LogStatus::MESSAGE, "Parsing values file...");
    rc = s_values_parser.parse(filepath.toStdString(), s_matrix);

    if (rc != nullptr) {
        Helper::log(LogStatus::FATAL, "Error parsing values file");
        return -1;
    }

    Helper::log(LogStatus::MESSAGE, "Successfully read values file");
    // symbol_matrix_print_stats(matrix);
    return 0;
}

void Matrix_visualizer::execute() {
    QString symbol_filepath = this->line_edit_symbol->text();
    QString order_filepath = this->line_edit_order->text();
    QString values_filepath = this->line_edit_values->text();

    update_matrix(std::move(symbol_filepath));
    update_order(std::move(order_filepath));
    update_values(std::move(values_filepath));

    // Open window for opengl drawing
    if (s_matrix != nullptr) {
        s_matrix_window = new Matrix_window(s_matrix, m_quadtree_button_checked);
        s_matrix_window->show();
    }
}

void Matrix_visualizer::log(LogStatus status, const char *format, va_list ap) {
    char message[256] = { 0 };

    vsnprintf(message, 256, format, ap);

    QString previous_text = this->text_edit_logs->toPlainText();

    switch (status) {
    case WARNING:
        previous_text += QStringLiteral("Warning: ");
        break;
    case FATAL:
        previous_text += QStringLiteral("FATAL: ");
        break;
    default:
        break;
    }

    previous_text += QString::fromStdString(message);
    previous_text += QStringLiteral("\n");

    this->text_edit_logs->clear();
    this->text_edit_logs->setText(previous_text);
}

void Matrix_visualizer::set_infos(const char *format, va_list ap) {
    char message[2048] = { 0 };

    vsnprintf(message, 2048, format, ap);

    QString to_print = QString::fromStdString(message);

    this->text_edit_infos->clear();
    this->text_edit_infos->setText(to_print);
}

/***********************
 * Buttons
 **********************/
void Matrix_visualizer::on_tool_button_symbol_clicked() {
    QString symbol_filepath = QFileDialog::getOpenFileName(s_plugin, tr("Open file"),
                                                           s_plugin->line_edit_symbol->text());

    s_plugin->line_edit_symbol->setText(symbol_filepath);
}

void Matrix_visualizer::on_tool_button_order_clicked() {
    QString order_filepath = QFileDialog::getOpenFileName(s_plugin, tr("Open file"),
                                                          s_plugin->line_edit_order->text());

    s_plugin->line_edit_order->setText(order_filepath);
}

void Matrix_visualizer::on_tool_button_values_clicked() {
    QString values_filepath = QFileDialog::getOpenFileName(s_plugin, tr("Open file"),
                                                           s_plugin->line_edit_values->text());

    s_plugin->line_edit_values->setText(values_filepath);
}

void Matrix_visualizer::on_tool_button_infos_clicked() {
    s_plugin->text_edit_infos->setText(QString());
}

void Matrix_visualizer::on_tool_button_logs_clicked() {
    s_plugin->text_edit_logs->setText(QString());
}

/*****************
 * radio buttons *
 *****************/
void Matrix_visualizer::on_zooming_button_clicked() {
    m_quadtree_button_checked = false;
}

void Matrix_visualizer::on_quadtree_button_clicked() {
    m_quadtree_button_checked = true;
}

#include "moc_MatrixVisualizer.cpp"
