#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, 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;

    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( "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( this->line_edit_symbol->text() );
    update_order(  this->line_edit_order->text() );
    update_values( this->line_edit_values->text() );

    // Open window for opengl drawing
    if ( s_matrix != nullptr )
    {
        s_matrix_window = new Matrix_window(s_matrix);
        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 += "Warning: ";
        break;
    case FATAL:
        previous_text += "FATAL: ";
        break;
    default:
        break;
    }

    previous_text += message;
    previous_text += '\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 = 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("");
}

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