/*
 ** 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 developers are (for version 0.* to 1.0):
 **
 **        - COULOMB Kevin
 **        - FAVERGE Mathieu
 **        - JAZEIX Johnny
 **        - LAGRASSE Olivier
 **        - MARCOUEILLE Jule
 **        - NOISETTE Pascal
 **        - REDONDY Arthur
 **        - VUCHENER Clément
 **
 */
/*!
 *\file interface_graphic.cpp
 *\brief This is graphical interface C source code.
 */
#include <fstream>
#include <string>
#include <iostream>
#include <sstream>
#include <stack>
#include <map>
#include <list>
/* -- */
#include <QObject>
#include <QGLWidget>/* for the OpenGL Widget */
#include <QtUiTools>/* for the run-time loading .ui file */
#include <QCloseEvent>
#include <QDir>
#include <QFileDialog>
#include <QRadioButton>
#include <QTextEdit>
#include <QCheckBox>
#include <QMessageBox>
#include <QProgressDialog>
/* -- */
#include "interface/resource.hpp"
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
#include "common/Tools.hpp"
#include "common/Session.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "interface/Interface.hpp"
#include "core/Core.hpp"
#include "interface/Settings_window.hpp"
#include "interface/Interface_graphic.hpp"
/* -- */
#include "plugin/Command_window.hpp"
#include "plugin/Plugin_window.hpp"

using namespace std;

/***********************************
 *
 *
 *
 * Constructors and destructor.
 *
 *
 *
 **********************************/


Interface_graphic::Interface_graphic(Core* core, QWidget *parent):QMainWindow(parent){

    setupUi(this);

    _zoom_box_check_value="";
    _core = core;
    _is_rendering_trace = false;
    _no_warning = Session::get_hide_warnings_setting();/* display warnings */
    _on_manual_change = false;

    _reload_type = Session::get_reload_type_setting();
    no_warning->setChecked(Session::get_hide_warnings_setting());
    reload_from_file->setChecked(Session::get_reload_type_setting());
    vertical_line->setChecked(Session::get_vertical_line_setting());
    shaded_states->setChecked(Session::get_shaded_states_setting());
    _x_factor_virtual_to_real = 0.1;
    _y_factor_virtual_to_real = 0.1;

    load_windows();

    setMouseTracking (true);/* to catch mouse events */

    _progress_dialog = nullptr;
    _plugin_window = nullptr;
    _ui_settings = nullptr;
    _ui_node_selection=nullptr;
    _ui_interval_selection=nullptr;
    _cmd_window = new Command_window(this,this);

    // For drag and drop operations
    setAcceptDrops(true);
}

Interface_graphic::~Interface_graphic(){
    /* Qt desallocates this, _ui_info_window and _render_area automatically */

    delete _plugin_window;
    _plugin_window = nullptr;

    delete _cmd_window;
    _cmd_window = nullptr;
}



/***********************************
 *
 *
 *
 * Window function.
 *
 *
 *
 **********************************/

void Interface_graphic::load_windows(){

    QUiLoader *loader = new QUiLoader();
    QFile file_info(":/window/info_window.ui");
    QFile file_selection_export(":/window/option_export_window.ui");
    QFile file_help(":/window/help_window.ui");
    //  QFile file_kind_of_export(":/window/kind_of_export.ui");
    QFile file_counter_to_export(":/window/list_of_counter_to_export.ui");

    if (!QGLFormat::hasOpenGL())
        qFatal("This system has no OpenGL support");

    /* Load the informative window from a .ui file */
    if ( file_info.exists() ) {
        file_info.open(QFile::ReadOnly);
        CKFP(_ui_info_window = loader->load(&file_info, this), "Cannot open the .ui file: " << ":/window/info_window.ui");
        file_info.close();
    } else {
        cerr << __FILE__ << ":" << __LINE__ << ": The following .ui file doesn't exist: " << ":/window/info_window.ui" << endl;
        exit(EXIT_FAILURE);
    }

    /* Load the _option_export_window from a .ui file */
    if ( file_selection_export.exists() ) {
        file_selection_export.open(QFile::ReadOnly);
        CKFP(_ui_time_selection_export = loader->load(&file_selection_export, this), "Cannot open the .ui file : " << ":/window/option_export_window.ui");
        file_selection_export.close();
    } else {
        cerr << __FILE__ << ":" << __LINE__ << ": The following .ui file doesn't exist: " << ":/window/option_export_window.ui" << endl;
        exit(EXIT_FAILURE);
    }

    /* Load the choice counter for export box */
    if ( file_counter_to_export.exists() ) {
        file_counter_to_export.open(QFile::ReadOnly);
        CKFP(_ui_counter_choice_to_export = loader->load(&file_counter_to_export, this), "Cannot open the .ui file : " << ":/window/list_of_counter_to_export.ui");
        CKFP(_counter_list_names = _ui_counter_choice_to_export->findChild<QComboBox*>("combobox"), "Cannot find the svg export button in the .ui file");
        file_counter_to_export.close();
    } else {
        cerr << __FILE__ << ":" << __LINE__ << ": The following .ui file doesn't exist: " << ":/window/list_of_counter_to_export.ui" << endl;
        exit(EXIT_FAILURE);
    }

    /* Load the help dialog box from a .ui file */
    if ( file_help.exists() ) {
        file_help.open(QFile::ReadOnly);
        CKFP(_ui_help_window = loader->load(&file_help, this), "Cannot open the .ui file : " << ":/window/help_window.ui");
        file_help.close();
    } else {
        cerr << __FILE__ << ":" << __LINE__ << ": The following .ui file doesn't exist: " << ":/window/help_window.ui" << endl;
        exit(EXIT_FAILURE);
    }

    /* Set some windows properties */
    _ui_info_window->setWindowFlags(_ui_info_window->windowFlags() | Qt::WindowStaysOnTopHint);/* Always display info_window on top */
    _ui_time_selection_export->setWindowFlags(_ui_time_selection_export->windowFlags() | Qt::WindowStaysOnTopHint);

    /* Load widget from the .ui file */
    CKFP(_ui_render_area_layout = this->findChild<QVBoxLayout*>("render_area_layout"), "Cannot find the render_area layout in the .ui file");

    CKFP(_ui_fullscreen_menu = this->findChild<QAction*>("fullscreen"), "Cannot find the fullscreen menu in the .ui file");
    CKFP(_ui_info_trace_text = _ui_info_window->findChild<QTextEdit*>("info_trace_text"), "Cannot find the info_trace_text QTextEdit widget in the .ui file");
    CKFP(_ui_info_selection_text = _ui_info_window->findChild<QTextEdit*>("info_selection_text"), "Cannot find the info_selection_text QTextEdit widget in the .ui file");
    CKFP(_ui_toolbar = this->findChild<QToolBar*>("toolBar"), "Cannot find the tool bar in the .ui file");

    CKFP(_ui_x_scroll = this->findChild<QScrollBar*>("x_scroll"), "Cannot find the horizontal scroll bar in the .ui file");
    CKFP(_ui_y_scroll = this->findChild<QScrollBar*>("y_scroll"), "Cannot find the vertical scroll bar in the .ui file");

    CKFP(_ui_zoom_box = this->findChild<QComboBox*>("zoom_box"), "Cannot find the zoom box in the .ui file");

    CKFP(_ui_recent_files_menu = this->findChild<QMenu*>("menuRecent_Files"), "Cannot find the button \"menuRecent_Files\" in the .ui file");

    /* Help window */
    CKFP(_ui_help_ok_button = _ui_help_window->findChild<QPushButton*>("help_ok"), "Cannot find the ok push button in the help dialog .ui file");


    connect(_ui_counter_choice_to_export, SIGNAL(accepted()),
            this, SLOT(counter_choosed_triggered()));

    connect(_ui_help_ok_button, SIGNAL(clicked()),
            _ui_help_window, SLOT(close()));

    // For the recent files menu
    for (auto & _recent_file_action : _recent_file_actions) {
        _recent_file_action = nullptr;
    }
    update_recent_files_menu();

    /*
     Special function of Qt which allows methods declared as slots and which
     name are 'on_[widget]_[action]()' to be called when the 'widget' triggered
     the signal corresponding to 'action'.
     /!\ -> use NULL as argument, else messages will be duplicated!
     */
    QMetaObject::connectSlotsByName(nullptr);

    _ui_x_scroll->setMaximum(_REAL_X_SCROLL_LENGTH);
    _ui_y_scroll->setMaximum(_REAL_Y_SCROLL_LENGTH);

    delete loader;
    /* Display the main window */
    this->show();
}



/***********************************
 *
 *
 *
 * Informative message functions.
 *
 *
 *
 **********************************/

void Interface_graphic::error(const string &s) const{
    if ( true==_no_warning ) return;/* do not display error messages */

    QString buf = s.c_str();
    _ui_info_trace_text->moveCursor(QTextCursor::End);/* Insert the new text on the end */
    _ui_info_trace_text->insertHtml("<font color='red'>"+buf+"</font><br /><br />");

    _ui_info_window->show();/* show info_window */
}

void Interface_graphic::warning(const string &s) const{
    if ( true==_no_warning ) return;/* do not display warning messages */

    QString buf = s.c_str();
    _ui_info_trace_text->moveCursor(QTextCursor::End);/* Insert the new text on the end */
    _ui_info_trace_text->insertHtml("<font color='orange'>"+buf+"</font><br /><br />");

    _ui_info_window->show();/* show info_window */
}

void Interface_graphic::information(const string &s) const{
    QString buf = s.c_str();
    _ui_info_trace_text->moveCursor(QTextCursor::End);/* Insert the new text on the end */
    _ui_info_trace_text->insertHtml("<font color='green'>"+buf+"</font><br /><br />");
}

/***********************************
 *
 * Selected Trace entity informative function.
 *
 **********************************/

void Interface_graphic::selection_information(const string &s) const{
    QString buf = s.c_str();
    _ui_info_selection_text->clear();/* Clear the current text (if exists) */
    _ui_info_selection_text->insertHtml("<font color='blue'>"+buf+"</font>");
    _ui_info_selection_text->moveCursor(QTextCursor::Start);/* Insert the new text on the begin */

    _ui_info_window->show();/* show info_window */
}

/***********************************
 *
 * Tool functions.
 *
 **********************************/

void Interface_graphic::opening_file(const string &path){

    information(string("File opened: ")+ path);

    _trace_path = path;

    this->setWindowTitle(QString("ViTE :: ")+_trace_path.c_str());

    QApplication::setOverrideCursor(Qt::WaitCursor);

    _is_rendering_trace = true;

    QApplication::restoreOverrideCursor();
}

void Interface_graphic::bind_render_area(QGLWidget* render_area){
    /* Bind the render area to a layout (_ui_render_area_layout) */
    _ui_render_area = render_area;
    _ui_render_area_layout->addWidget(_ui_render_area);
}

void Interface_graphic::set_scroll_bars_length(Element_pos new_x_virtual_length, Element_pos new_y_virtual_length){
    _x_factor_virtual_to_real = _REAL_X_SCROLL_LENGTH / new_x_virtual_length;
    _y_factor_virtual_to_real = _REAL_Y_SCROLL_LENGTH / new_y_virtual_length;
}

void Interface_graphic::linking_scroll_bars(Element_pos x_bar_new_value, Element_pos y_bar_new_value){
    _on_manual_change = true;
    _ui_x_scroll->setValue(virtual_to_real_scroll_unit(x_bar_new_value, 'x'));
    _ui_y_scroll->setValue(virtual_to_real_scroll_unit(y_bar_new_value, 'y'));
    _on_manual_change = false;
}

Element_pos Interface_graphic::real_to_virtual_scroll_unit(int scroll_position, const char &axe){
    switch (axe){
    case 'x':
        return (scroll_position/_x_factor_virtual_to_real);
        break;
    case 'y':
        return (scroll_position/_y_factor_virtual_to_real);
        break;

    default:
        error("Option not recognized.");
        break;
    }
    return scroll_position;
}

int Interface_graphic::virtual_to_real_scroll_unit(Element_pos scroll_position, const char &axe){
    switch (axe){
    case 'x':
        return (int)(scroll_position*_x_factor_virtual_to_real);
        break;
    case 'y':
        return (int)(scroll_position*_y_factor_virtual_to_real);
        break;
    default:
        error("Option not recognized.");
        break;
    }
    return (int)scroll_position;
}

void Interface_graphic::change_zoom_box_value(int new_value){
    QString formated_value;
    ostringstream int_to_string;
    int index;

    int max_value = INT_MIN;

    if (max_value == new_value)/* prevent overflow value */
        new_value = INT_MAX;

    int_to_string << new_value;

    formated_value = QString(int_to_string.str().c_str())+QString("%");

    index = _ui_zoom_box->findText( formated_value, Qt::MatchExactly);

    _zoom_box_check_value = formated_value;

    if (-1 == index){/* value does not exist in the list */
        _ui_zoom_box->removeItem(0);
        _ui_zoom_box->insertItem(0,  formated_value);/* add the value */
        _ui_zoom_box->setCurrentIndex(0);

    }
    else{
        _ui_zoom_box->setCurrentIndex(index);/* value exists, select it */
    }

    //update the interval selection display
    if(_ui_interval_selection!=nullptr)_ui_interval_selection->update_values();
}

/***********************************
 *
 * Widget slot functions.
 *
 **********************************/

void Interface_graphic::on_open_triggered(){

    /*
     Be careful! Here, this is used instead 'this' pointer because 'this' is not a window,
     it's an interface class (Interface_graphic*). The real window is this.
     If 'this' is put, the application closes after the getOpenFilename() dialog box closes.
     */
    QString filename = QFileDialog::getOpenFileName(this);

    if (!filename.isEmpty()){
        open_trace(filename);
    }/* end if (!filename.isEmpty()) */

}

void Interface_graphic::on_export_file_triggered(){

    QStringList selected_files;
    QFileDialog file_dialog(this);
    QString filename;
    QString extension;
    signed int filename_size;/* Must be signed to check if size is negative */

    if(_is_rendering_trace == false)
        return;

    ExportSettings &ES = Session::getSessionExport();

    /* Try to recover the last file dialog state. */
    if ( ! ES.is_default() ) {
        if (!file_dialog.restoreState( ES.file_dialog_state ))
            warning("Cannot restore the export file dialog state");
    }

    file_dialog.setLabelText(QFileDialog::FileName, QString(_trace_path.substr(0, _trace_path.find_last_of('.')).c_str()) + ".svg");
    file_dialog.setFileMode(QFileDialog::AnyFile);/* Allow to browse among directories */
    file_dialog.setAcceptMode(QFileDialog::AcceptSave);/* Only save file */
    file_dialog.setNameFilter(tr("Vector (*.svg);;Bitmap PNG (*.png);;Bitmap JPEG (*.jpeg *.jpg);;Counter (*.txt)"));

    if (file_dialog.exec()){/* Display the file dialog */
        selected_files = file_dialog.selectedFiles();//"/tmp/test.png";//file_dialog.selectedFile();

        if (selected_files.size()==1)
            filename = selected_files[0];/* Get the first filename */
        else{

            if (selected_files.size()==0)
                warning("No file was selected.");
            else
                warning("Cannot save: too much files were selected.");

            return;
        }

        filename_size = filename.size() - 4;/* filename without extension */

        if (filename_size <= 0){

            error("Filename is not valid. Must be {filename}.{extension}");
            return;

        }else if (filename.at(filename_size) != QChar('.')){/* No extension or extension is not correct */

            /* Add it manually */
            const QString filter_selected = file_dialog.selectedNameFilter();

            if ("Vector (*.svg)"==filter_selected){
                filename += ".svg";
                extension = "svg";
            }else if ("Bitmap PNG (*.png)"==filter_selected){
                filename += ".png";
                extension = "png";
            }else if ("Bitmap JPEG (*.jpeg *.jpg)"==filter_selected){
                filename += ".jpg";
                extension = "jpg";
            }else if ("Counter (*.txt)"==filter_selected){
                filename += ".txt";
                extension = "txt";
            }else
                warning("Cannot recognize the filter: "+filter_selected.toStdString());

            /* Update the _export_filename attribute which will be used in SVG or Counter export functions */
            _export_filename = filename;

        }
        else {
            extension = filename.right(3).toLower();/* in lower case */
            /* Update the _export_filename attribute which will be used in SVG or Counter export functions */
            _export_filename = filename;
        }
    }

    /* Save the file dialog state (History and current directory) */
    ES.file_dialog_state = file_dialog.saveState();

    if (extension=="svg"){

        _core->set_path_to_export(filename.toStdString());
        _core->launch_action(Core::_STATE_EXPORT_FILE_IN_INTERVAL);

    }
    else if (extension=="txt"){
        // In order to easily retrieve the good variable, we store them with an
        // index representing the container name followed by the variabletype
        // name (because a variable has no name)
        _all_variables.clear();

        _core->get_trace()->get_all_variables(_all_variables);
        map<string, Variable *>::const_iterator it_end = _all_variables.end();

        _counter_list_names->clear();
        for(map<string, Variable *>::const_iterator it = _all_variables.begin();
            it != it_end; it ++)
        {
            _counter_list_names->addItem(QString::fromStdString((*it).first));
        }

        if(_counter_list_names->count() == 0) {
            error("The trace has no counter");
            return;
        }

        _ui_counter_choice_to_export->show();
    }
    else if (extension=="png" || extension=="jpg" || extension=="jpeg"){

        QImage tempImage = _ui_render_area->grabFrameBuffer(true);/* true = with alpha channel */

        if ( !tempImage.save( filename, extension.toUpper().toStdString().c_str()) ){
            error("The trace cannot be exported into "+filename.toStdString()+" file.");
        }
        else{
            information("The trace was exported into "+filename.toStdString()+" file.");
        }
    }
    else if(selected_files.size() != 0) { // No error if we canceled the save
        error("Cannot recognize the file extension: "+extension.toStdString()+".");
    }
}

void Interface_graphic::on_reload_triggered() {
    if(_is_rendering_trace) {
        Element_pos zoom[2] = { Info::Splitter::_x_min,
                                Info::Splitter::_x_max };
        if( _ui_settings != nullptr ) {
            _ui_settings->refresh();
        }
        // if(_ui_node_selection!=NULL)
        //     _ui_node_selection->on_reset_button_clicked();
        // if(_ui_interval_selection!=NULL)
        //  _ui_interval_selection->on_reset_button_clicked();
        if( _reload_type ) {
            _core->launch_action(Core::_STATE_RELEASE_RENDER_AREA);
        }
        else {
            _core->launch_action(Core::_STATE_CLEAN_RENDER_AREA);
        }
        _core->draw_trace(_trace_path, Core::_DRAW_OPENGL);

        if( Info::Splitter::_x_max != 0.0 ) {
            _core->launch_action(Core:: _STATE_ZOOM_IN_AN_INTERVAL, &zoom);
        }

        _core->launch_action(Core:: _STATE_RENDER_UPDATE);

        //reset the slider to its original value
        scale_container_state->setValue(20);

        //update the interval selection display
        if( _ui_interval_selection != nullptr ) {
            _ui_interval_selection->update_values();
        }
    }
}

void Interface_graphic::open_recent_file() {
    QAction *action = qobject_cast<QAction *>(sender());
    if (action)
        open_trace(action->data().toString());
}

void Interface_graphic::on_clear_recent_files_triggered() {
    Session::clear_recent_files();
    // We remove the elements from the menu
    for(auto & _recent_file_action : _recent_file_actions) {
        if(_recent_file_action != nullptr) {
            _ui_recent_files_menu->removeAction(_recent_file_action);
        }
    }
}

void Interface_graphic::counter_choosed_triggered() {
    // Il faut faire choisir le nom du fichier! et enfin on peut lancer l'action !
    // const QString path_by_default = QString(_trace_path.substr(0, _trace_path.find_last_of('.')).c_str()) + ".txt";
    //QString filename = QFileDialog::getSaveFileName(this, QObject::tr("Export File"),
    //                                                path_by_default,
    //                                                QObject::tr("All files"));

    Variable *temp = _all_variables[_counter_list_names->currentText().toStdString()];
    //    _core->export_variable(temp, filename.toStdString());
    _core->export_variable(temp, _export_filename.toStdString());
}

/*void Interface_graphic::on_export_file_triggered(){
 if(_is_rendering_trace == false)
 return;

 _ui_kind_of_export_choice->show();
 }*/

void Interface_graphic::option_export_ok_pressed(){
    // We have to save the option from _ui_time_selection_export and hide her if it is not do automatically

    _ui_time_selection_export->hide();
    //   const QString path_by_default = QString(_trace_path.substr(0, _trace_path.find_last_of('.')).c_str()) + ".svg";
    //QString filename = QFileDialog::getSaveFileName(this, tr("Export File"),
    //                                              path_by_default,
    //                                              tr("Images (*.svg)"));

    QString filename = _export_filename;

    if (!filename.isEmpty()) {
        // Adding .svg to the end
        /*   if(!filename.endsWith(".svg")) {
         filename += ".svg";
         }*/

        information(string("Exporting trace to ")+filename.toStdString());

        _core->set_path_to_export(filename.toStdString());
        // _core->draw_trace(_trace_path, Core::_DRAW_SVG);

        //  if(_ui_CheckBox_time_export->isChecked()){
        //   _core->set_min_value_for_export(convert_to_double(_ui_min_time_export->text().toStdString()));
        //    _core->set_max_value_for_export(convert_to_double(_ui_max_time_export->text().toStdString()));
        /* }
         else{
         _core->set_min_value_for_export(0);
         _core->set_max_value_for_export(Info::Entity::x_max);//TO DO TODO max_size de la trace?
         }*/

        _core->launch_action(Core::_STATE_EXPORT_FILE_IN_INTERVAL);
    }
    else {
        error("No file specified for exportation");
    }

}


void Interface_graphic::on_close_triggered(){

    if(_is_rendering_trace == false)
        return;

    /*
     * Clear the informative window texts and hide it.
     */
    _ui_info_trace_text->clear();/* Clear the current text (if exists) */
    _ui_info_selection_text->clear();/* Clear the current text (if exists) */
    _ui_info_window->hide();/* Hide the informative window */

    if(_ui_settings) {
        _ui_settings->hide();
    }

    if(_plugin_window != nullptr) {
        _plugin_window->hide();
        //_plugin_window->clear_plugins();
    }

    _core->launch_action(Core::_STATE_RELEASE_RENDER_AREA);
    if (_cmd_window){
        delete _cmd_window;
        _cmd_window = nullptr;
    }

    _is_rendering_trace = false;

    information(string("File closed."));

    this->setWindowTitle(QString("ViTE"));
}


void Interface_graphic::on_quit_triggered(){

    if( nullptr != _ui_node_selection)
        ((QWidget*)_ui_node_selection)->close();
    if( nullptr != _ui_interval_selection)
        ((QWidget*)_ui_interval_selection)->close();
    if( nullptr != _ui_help_window)
        ((QWidget*)_ui_help_window)->close();
    if( nullptr != _ui_info_window)
        ((QWidget*)_ui_info_window)->close();
    ((QWidget*)this)->close();
}


void Interface_graphic::on_fullscreen_triggered(){

    /*
     Notice that some problems can appears under X systems with
     the window decoration. Please refer to the Qt official documentation.
     */

    /*
     The menu is checked before function call, so if 'fullscreen menu' is checked,
     the main window is displayed in fullscreen mode
     */
    if (_ui_fullscreen_menu->isChecked())
        this->showFullScreen();
    else
        this->showNormal();
}

void Interface_graphic::on_vertical_line_triggered(){
    Info::Render::_vertical_line=!Info::Render::_vertical_line;
    Session::update_vertical_line_setting(Info::Render::_vertical_line);
}

void Interface_graphic::on_shaded_states_triggered(){
    Info::Render::_shaded_states=!Info::Render::_shaded_states;
    Session::update_shaded_states_setting(Info::Render::_shaded_states);

    /* Reload render area */
    if (_is_rendering_trace){
        if(_reload_type)
            _core->launch_action(Core::_STATE_RELEASE_RENDER_AREA);
        else
            _core->launch_action(Core::_STATE_CLEAN_RENDER_AREA);
        _core->draw_trace(_trace_path, Core::_DRAW_OPENGL);
    }
}

void Interface_graphic::on_toolbar_menu_triggered(){
    static bool checked = true;/* Suppose that toolbar_menu is initially checked */

    checked = !checked;

    if (!checked)
        _ui_toolbar->show();
    else
        _ui_toolbar->hide();
}


void Interface_graphic::on_minimap_menu_triggered(){
    _core->launch_action(Core::_STATE_RENDER_SHOW_MINIMAP,nullptr);
}


void Interface_graphic::on_show_info_triggered(){
    if (_ui_info_window->isHidden())
        _ui_info_window->show();
    else
        _ui_info_window->hide();
}

void Interface_graphic::on_help_triggered(){

    if(_ui_help_window->isVisible()){
        _ui_help_window->hide();
    }
    else{
        _ui_help_window->show();
    }
}


void Interface_graphic::on_about_triggered(){

    QMessageBox::about(this, tr("About ViTE"),
                       tr("<h2>ViTE</h2>"
                          "the <b>Vi</b><i>sual </i><b>T</b><i>race</i> <b>E</b><i>xplorer</i> - <i>version "
                          VITE_VERSION
                          "</i> - <i>"
                          VITE_DATE
                          "</i>.<br /><br />"
                          "Under the CeCILL A licence. The content can be found <a href=\"http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt\">here</a>."
                          "<p><b>Developers:</b><ul>"
                          "<li>Kevin COULOMB</li>"
                          "<li>Mathieu FAVERGE</li>"
                          "<li>Johnny JAZEIX</li>"
                          "<li>Olivier LAGRASSE</li>"
                          "<li>Jule MARCOUEILLE</li>"
                          "<li>Pascal NOISETTE</li>"
                          "<li>Arthur REDONDY</li>"
                          "<li>Cl&eacute;ment VUCHENER</li>"
                          "</ul></p>"
                          "The main page project is: <a href=\""
                          VITE_WEBSITE
                          "\">"
                          VITE_WEBSITE
                          "</a>.<br /><br />"));
}

void Interface_graphic::on_show_plugins_triggered()
{
    if(_plugin_window == nullptr) { //Creation of the window
        _plugin_window = new Plugin_window( _core, this );
    }

    if( _core->get_trace() != nullptr ) {
        _plugin_window->update_trace();
    }

    _plugin_window->show();
}


void Interface_graphic::on_show_settings_triggered() {

    if (!_ui_settings) {
        _ui_settings = new Settings_window(_core);
        connect(_ui_settings, SIGNAL(settings_changed()), this, SLOT(update_settings()));
        // To close the window when we quit the application
        connect(quit, SIGNAL(triggered()), _ui_settings, SLOT(close()));
    }
    _ui_settings->show();
}


void Interface_graphic::on_node_selection_triggered() {

    if (!_ui_node_selection){
     _ui_node_selection = new Node_select(this, nullptr);
     connect(quit, SIGNAL(triggered()),  _ui_node_selection, SLOT(close()));
    }
    if(_core->get_trace() != nullptr) {
        if(!_ui_node_selection->get_trace()){//first use
            _ui_node_selection->set_trace(_core->get_trace());
        }
        _ui_node_selection->show();
    }else{
        error("Must load a trace before using node selection on a trace");
    }
}

void Interface_graphic::on_interval_selection_triggered() {
    if(!_ui_interval_selection){
        _ui_interval_selection = new Interval_select(this, nullptr);
        connect(quit, SIGNAL(triggered()),  _ui_interval_selection, SLOT(close()));
    }
    if(_core->get_trace() != nullptr) {
        if(!_ui_interval_selection->get_trace() && _core->get_trace()){//first use
            _ui_interval_selection->set_trace(_core->get_trace());

        }
        _ui_interval_selection->show();
    }else{
        error("Must load a trace before using interval selection on a trace");
    }
}

void Interface_graphic::on_actionCommand_triggered(){
    if(_core->get_trace()){
        if (!_cmd_window)
            _cmd_window = new Command_window (this, this);
        _cmd_window->set_trace(_core->get_trace());
        _cmd_window->init_window();
        _cmd_window->show();
    }
    else{
        error("Must load a trace before using an external command on a trace");
    }
}

void Interface_graphic::on_no_warning_triggered(){
    _no_warning = !_no_warning;
    Session::update_hide_warnings_settings(_no_warning);
}

void Interface_graphic::on_no_arrows_triggered(){
    std::cout << "no_arrows triggered" << std::endl;
    Info::Render::_no_arrows = !Info::Render::_no_arrows;
    _core->launch_action(Core::_STATE_RENDER_UPDATE);
}

void Interface_graphic::on_no_events_triggered(){
    Info::Render::_no_events = !Info::Render::_no_events;
    _core->launch_action(Core::_STATE_RENDER_UPDATE);
}

void Interface_graphic::on_reload_from_file_triggered(){
    _reload_type=!_reload_type;
    Session::update_reload_type_setting(_reload_type);
}

void Interface_graphic::on_zoom_in_triggered(){
    Element_pos t = 1;

    if (true==Info::Render::_key_alt)/* on Y axe */
        _core->launch_action(Core::_STATE_RENDER_AREA_CHANGE_SCALE_Y, &t);
    else/* on X axe */
        _core->launch_action(Core::_STATE_RENDER_AREA_CHANGE_SCALE, &t);
}

void Interface_graphic::on_zoom_out_triggered(){
    Element_pos t = -1;

    if (true==Info::Render::_key_alt)/* on Y axe */
        _core->launch_action(Core::_STATE_RENDER_AREA_CHANGE_SCALE_Y, &t);
    else/* on X axe */
        _core->launch_action(Core::_STATE_RENDER_AREA_CHANGE_SCALE, &t);
}

void Interface_graphic::on_goto_start_triggered(){
    int id;

    if (true==Info::Render::_key_alt)/* on Y axe */
        id = Info::Render::Y_TRACE_BEGINNING;
    else/* on X axe */
        id = Info::Render::X_TRACE_BEGINNING;

    _core->launch_action(Core::_STATE_RENDER_AREA_REGISTERED_TRANSLATE, &id);
}

void Interface_graphic::on_goto_end_triggered(){
    int id;

    if (true==Info::Render::_key_alt)/* on Y axe */
        id = Info::Render::Y_TRACE_ENDING;
    else/* on X axe */
        id = Info::Render::X_TRACE_ENDING;

    _core->launch_action(Core::_STATE_RENDER_AREA_REGISTERED_TRANSLATE, &id);
}

void Interface_graphic::on_show_all_trace_triggered(){
    int id = Info::Render::X_TRACE_ENTIRE;/* on X axe */
    _core->launch_action(Core::_STATE_RENDER_AREA_REGISTERED_TRANSLATE, &id);
    id = Info::Render::Y_TRACE_ENTIRE;/* on Y axe */
    _core->launch_action(Core::_STATE_RENDER_AREA_REGISTERED_TRANSLATE, &id);
}

#if QT_VERSION < 0x050000
void Interface_graphic::on_zoom_box_textChanged(const QString &s)
#else
void Interface_graphic::on_zoom_box_currentTextChanged(const QString &s)
#endif
{
    QRegExp reg_exp_number("^(\\d+)");
    QString result;
    Element_pos d;

    if (s=="")/* if there is not value, go out */
        return;

    if (_zoom_box_check_value == s)/* We have just change the zoom box value (in  change_zoom_box_value()) what emits the signal.
                                    So ignore this function call */
        return;

    if (-1 != reg_exp_number.indexIn(s)){/* match a number */
        result = reg_exp_number.cap(1);/* capture number inside parenthesis in the RegExp */
        d = 0.01*result.toDouble();
        if (0 == d)/* if zoom is null ignore it */
            return;

        _core->launch_action(Core::_STATE_RENDER_AREA_REPLACE_SCALE, &d);
    }

}

void Interface_graphic::on_x_scroll_valueChanged(int new_value){
    if (!_on_manual_change){
        Element_pos converted_new_value = real_to_virtual_scroll_unit(new_value, 'x');/* change type of new_value */
        _core->launch_action(Core::_STATE_RENDER_AREA_REPLACE_TRANSLATE, &converted_new_value);
    }
}

void Interface_graphic::on_y_scroll_valueChanged(int new_value){
    if (!_on_manual_change){
        Element_pos converted_new_value = real_to_virtual_scroll_unit(new_value, 'y');/* change type of new_value */
        _core->launch_action(Core::_STATE_RENDER_AREA_REPLACE_TRANSLATE_Y, &converted_new_value);
    }
}

void Interface_graphic::on_scale_container_state_valueChanged(int new_value){
    _core->launch_action(Core::_STATE_RENDER_AREA_CHANGE_CONTAINER_SCALE, &new_value);
}

void Interface_graphic::closeEvent(QCloseEvent *event){
    //   _ui_help_widget->close();
    /* Now, release render */
    if(_is_rendering_trace)
        _core->launch_action(Core::_STATE_RELEASE_RENDER_AREA);
    _is_rendering_trace = false;

    if(isEnabled()){
        event->accept();/* accept to hide the window for a further destruction */
    }
    else{
        event->ignore();
    }
    if(_ui_settings)
        _ui_settings->close();

    if(_ui_node_selection)
        _ui_node_selection->close();

    if(_ui_interval_selection)
        _ui_interval_selection->close();
}

const std::string Interface_graphic::get_filename() const{
    return _trace_path;
}

Core * Interface_graphic::get_console(){
    return _core;
}

Node_select*  Interface_graphic::get_node_select(){
    return _ui_node_selection;
}

Interval_select*  Interface_graphic::get_interval_select(){
    return _ui_interval_selection;
}

void Interface_graphic::update_recent_files_menu() {
    const QStringList filenames = Session::get_recent_files();
    QString absoluteFilename;

    for (int i = 0 ; i < Session::_MAX_NB_RECENT_FILES && i < filenames.size() ; ++ i) {
        if(_recent_file_actions[i] != nullptr) {
            delete _recent_file_actions[i];
        }
        _recent_file_actions[i] = new QAction(this);
        _recent_file_actions[i]->setVisible(true);
        absoluteFilename = QFileInfo(filenames[i]).absoluteFilePath();

        const QString text = tr("&%1 %2").arg(i+1).arg(absoluteFilename);
        _recent_file_actions[i]->setText(text);
        _recent_file_actions[i]->setData(absoluteFilename);
        connect(_recent_file_actions[i], SIGNAL(triggered()),
                this, SLOT(open_recent_file()));

        // We add to the menu
        _ui_recent_files_menu->addAction(_recent_file_actions[i]);
    }
}

void Interface_graphic::dragEnterEvent(QDragEnterEvent *event) {
    setBackgroundRole(QPalette::Highlight);
    event->acceptProposedAction();
}

void Interface_graphic::dragMoveEvent(QDragMoveEvent *event) {
    event->acceptProposedAction();
}

void Interface_graphic::dragLeaveEvent(QDragLeaveEvent *event) {
    event->accept();
}

void Interface_graphic::dropEvent(QDropEvent *event) {
    const QMimeData *mimeData = event->mimeData();

    if(!mimeData->hasUrls()) {
        return ;
    }

    foreach (QUrl url, event->mimeData()->urls()) {
#ifdef WIN32
        const QString filename = url.toString().right(url.toString().size()-8);
#else
        // We remove file:// from the filename
        const QString filename = url.toString().right(url.toString().size()-7);
#endif
        open_trace(filename);
    }
}

/* Graphical handling for parsing files */
void Interface_graphic::init_parsing(const std::string &filename) {
    if(!_progress_dialog) {
        _progress_dialog = new QProgressDialog(QObject::tr("Parsing"), QObject::tr("Cancel"), 0, 100, this);
    }
    _progress_dialog->setWindowTitle(QObject::tr("Loading of ")+QString::fromStdString(filename));
    _progress_dialog->show();

    setDisabled(true); // Disable the main window

    _progress_dialog->setDisabled(false); // to be able to cancel while parsing
}

void Interface_graphic::update_progress_bar(const QString &text, const int loaded) {
    _progress_dialog->setLabelText(text);
    _progress_dialog->setValue(loaded);
    _progress_dialog->update();
}

bool Interface_graphic::is_parsing_canceled() {
    return _progress_dialog->wasCanceled();
}

void Interface_graphic::end_parsing() {
    _progress_dialog->reset();
    _progress_dialog->hide();
    setDisabled(false); // Enable the main window
}

void Interface_graphic::open_trace(const QString &filename) {

    // We open the trace
    if (_is_rendering_trace == true){ /* open a new process */

        QStringList arguments = (QStringList() << filename);
        QString program;
        const QString** run_env = _core->get_runenv();
        QDir::setCurrent(*run_env[0]);
        QString run_cmd = *run_env[1];

#ifdef VITE_DEBUG
        cout << __FILE__ << " " << __LINE__ << " : " << run_env[0]->toStdString() << " " << run_env[1]->toStdString() << endl;
#endif

        if (run_cmd.startsWith("."))
            program = *run_env[0]+(run_cmd.remove(0,1));
        else
            program = run_cmd;

        QProcess new_process;
        new_process.startDetached(program, arguments);
    }
    else{
        opening_file(filename.toStdString());

        if(false==_core->draw_trace(filename.toStdString(), Core::_DRAW_OPENGL))
            error("Draw trace failed");
    }/* end else of if (_is_rendering_trace == true) */
}

void Interface_graphic::update_settings() {
    // Reload plugins
    if(_plugin_window) {
        _plugin_window->reload_plugins();
    }
    cout << "Settings changed, need to update classes" << endl;

    _core->launch_action(Core::_STATE_RENDER_UPDATE);
}
