/**
 *
 * @file plugins/CriticalPath/CriticalPath.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Mohamed Faycal Boullit
 *
 * @date 2024-07-17
 */
/*
** 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 for this plugin:  (PFA Team 2020/2021)
**
**             - ELOMARI ALAOUI Ismail
**             - BOULLIT Mohamed Fayçal
**
*/

#include <string>
#include <QFileDialog>
#include "ParserStats.hpp"
#include "CriticalPath.hpp"
#include "DrawStats.hpp"
/* -- */
#include "common/Session.hpp"
/* -- */
#include "plugin/Plugin.hpp"
/* -- */
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Container.hpp"
#include "trace/EntityValue.hpp"
#include "trace/StateChange.hpp"
#include "trace/tree/BinaryTree.hpp"
#include "trace/tree/Node.hpp"
#include "trace/Trace.hpp"

#include "render/vbo/Render_alternate.hpp"
#include "render/opengl/Render_opengl.hpp"

/* Macro used in set_line_edit_defaults to save the path of
opened dag or .rec file in the same use session of the plugin.
These paths can be changed it just sets it as default */
#define SESSION_FILENAME(fname) QString::fromStdString("plugins/cp/files/" + fname)

CriticalPath *CriticalPath::s_plugin = nullptr;
double CriticalPathLength = 0;

Plugin *create() {
    return CriticalPath::get_instance();
}

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

CriticalPath::CriticalPath() {
    setupUi(this);
    s_plugin = this;
    set_line_edit_defaults(this->line_edit_dag, "dag", "file.dot");
    set_line_edit_defaults(this->line_edit_rec, "rec", "file.rec");
}

CriticalPath::~CriticalPath() {
}

void CriticalPath::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);
}

void CriticalPath::init() {
}

void CriticalPath::clear() {
}

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

std::string CriticalPath::get_name() {
    return "Critical Path";
}

void CriticalPath::execute() {
    QString dag_filepath = this->line_edit_dag->text();
    QString rec_filepath = this->line_edit_rec->text();
    QStringList qsl_dag = dag_filepath.split(QStringLiteral("."));
    QStringList qsl_rec = rec_filepath.split(QStringLiteral("."));

    QString text;
    /* This gestion of invalid type errors, while could be working properly on Windows,
    it is not trusted in other operating systems such as linux so we'll think of other options */
    if (!QString::compare(qsl_dag[1], QStringLiteral("dot")) || !QString::compare(qsl_rec[1], QStringLiteral("rec"))) {
        ParserStats ps = ParserStats(dag_filepath.toStdString(),
                                     rec_filepath.toStdString());

        double cp_tasks_count = ps.get_critical_path().size();
        double cpu_count = get_cpu_count(_trace);
        double task_count = ps.get_task_count();
        double computing_volume = task_count / cpu_count;

        text = QString::number(ps.get_critical_path_length());
        lineEdit->setText(text);

        text = QString::number(cp_tasks_count);
        lineEdit_2->setText(text);

        text = QString::number(task_count);
        lineEdit_3->setText(text);

        text = QString::number(cpu_count);
        lineEdit_4->setText(text);

        text = QString::number(computing_volume);
        lineEdit_5->setText(text);

        text = QString::number(ps.get_max_breadth());
        lineEdit_6->setText(text);

        if (_critical_path_checked) {
            _render->set_vertical_line(ps.get_critical_path_length());
            _render->draw_vertical_line();
            std::vector<const State *> critical_path_states(ps.get_critical_path().size(), nullptr);
            get_critical_path_states(_trace, ps.get_critical_path(), critical_path_states);
            link_critical_path(_trace, critical_path_states);
        }
        else {
            LinkType *cp_type = _trace->search_link_type(String("Critical Path Link"));
            if (cp_type != nullptr) {
                Container *ancestor = _trace->search_container(String("program"));
                ancestor->remove_links(cp_type);
            }
        }
    }
    else {
        this->line_edit_rec->setText(QStringLiteral("Error: Invalid File Type"));
        this->line_edit_dag->setText(QStringLiteral("Error: Invalid File Type"));
    }
}

/***********************
 * Buttons
 **********************/
void CriticalPath::on_tool_button_dag_clicked() {
    QString dag_filepath = QFileDialog::getOpenFileName(s_plugin, tr("Open file"),
                                                        s_plugin->line_edit_dag->text());
    s_plugin->line_edit_dag->setText(dag_filepath);
}

void CriticalPath::on_tool_button_rec_clicked() {
    QString rec_filepath = QFileDialog::getOpenFileName(s_plugin, tr("Open file"),
                                                        s_plugin->line_edit_rec->text());
    s_plugin->line_edit_rec->setText(rec_filepath);
}

void CriticalPath::on_critical_path_stateChanged(int x) {
    _critical_path_checked = x == Qt::Checked;
}

#include "moc_CriticalPath.cpp"
