/**
 *
 * @file src/plugin/Plugin_window.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
 * @author Mathieu Faverge
 * @author Luca Bourroux
 *
 * @date 2024-07-17
 */

#include <iostream>
#include <string>
#include <map>
/* -- */
#include <QButtonGroup>
#include <QHBoxLayout>
#include <QTabWidget>
#include <QWidget>
#include <QIcon>
#include <QLibrary>
#include <QDir>
#include <QVariant>
#include <QVBoxLayout>
#include <QPushButton>
/* -- */
#include "common/Session.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityValue.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
/* -- */
#include "core/Core.hpp"
/* -- */
#include "interface/Interface_graphic.hpp"
/* -- */
#include "plugin/Plugin.hpp"
#include "plugin/Plugin_window.hpp"

using namespace std;

Plugin_window::Plugin_window(Interface_graphic *interface_graphic) :
    QMainWindow(interface_graphic), _current_index(0), _plugin_directories() {
    _layout = new QVBoxLayout();
    _tab_widget = new QTabWidget();
    _execute_button = new QPushButton(QStringLiteral("Execute"));
    _layout->addWidget(_tab_widget);
    _layout->addWidget(_execute_button);

    QWidget *central_widget = new QWidget();
    central_widget->setLayout(_layout);
    setCentralWidget(central_widget);

    QIcon icon;
    icon.addPixmap(QPixmap(QStringLiteral(":/icon/icon/vite.png")), QIcon::Normal, QIcon::Off);
    setWindowIcon(icon);
    setWindowTitle(QObject::tr("Plugins"));
    setMinimumSize(800, 600);
    connect(_tab_widget, &QTabWidget::currentChanged, this, &Plugin_window::reload_plugin);
    connect(_execute_button, &QAbstractButton::clicked, this, &Plugin_window::execute_plugin);

    _interface_graphic = interface_graphic;

    Session::load_plugin_directories(_plugin_directories);

    load_shared_plugins();

    // TODO load "compulsory" plugins (stats for example)
    load_plugin("Statistics");
    // Make a link to the menu to open the good tab if possible (menu Preferences->Plugins->...) where ... is the plugin we want to load

    // mainWindow->fillPluginMenu(list<QString> names);
}

Plugin_window::~Plugin_window() {
    _plugin_directories.clear();

    for (auto &_plugin: _plugins) {
        delete _plugin;
        _plugin = nullptr;
    }
    _plugins.clear();
}

void Plugin_window::load_shared_plugins() {

    QStringList::const_iterator it;
    for (it = _plugin_directories.constBegin();
         it != _plugin_directories.constEnd();
         ++it) {

        QDir dir(QDir::toNativeSeparators((*it))); /* directory name where plugin are stored */
        dir.setFilter(QDir::Files);

        /* Create if not exists */
        if (!dir.exists()) {
            dir.mkpath(QStringLiteral("."));
        }

        QFileInfoList list = dir.entryInfoList();

        for (const auto &fileInfo: qAsConst(list)) {
            QString filename = fileInfo.absoluteFilePath();

            if (!QLibrary::isLibrary(filename)) {
                continue;
            }

            QLibrary current_plugin(filename);

            Plugin *(*f)() = (Plugin * (*)()) current_plugin.resolve("create");
            if (!f) {
                cerr << "Unable to load " << current_plugin.errorString().toStdString() << endl;
            }
            else {
                Plugin *plug = f();
                add_plugin(plug);
            }
        }
    }
}

void Plugin_window::update_trace() {
    for (vector<Plugin *>::iterator it = _plugins.begin();
         it < _plugins.end();
         ++it) {
        (*it)->clear();
        (*it)->set_trace(_interface_graphic->get_trace());
    }
}

void Plugin_window::update_render() {
    for (vector<Plugin *>::iterator it = _plugins.begin();
         it < _plugins.end();
         ++it) {
        (*it)->clear();
        (*it)->set_render(_interface_graphic->get_render_area());
    }
}

void Plugin_window::add_plugin(Plugin *plug) {
    _plugins.push_back(plug);
    _tab_widget->addTab(plug, QString::fromStdString(plug->get_name()));
    plug->set_trace(_interface_graphic->get_trace());
    if (_interface_graphic->get_render_area() != nullptr)
        plug->set_render(_interface_graphic->get_render_area());
    plug->init();
}

void Plugin_window::show() {
    reload_plugin(_current_index);
    QMainWindow::show();
}

void Plugin_window::reload_plugin(int index) {
    //_plugins[_current_index].unload();
    if (index < (int)_plugins.size()) {
        _plugins[index]->set_trace(_interface_graphic->get_trace());
        _current_index = index;
    }
}

void Plugin_window::execute_plugin() {
    if (_current_index > (int)_plugins.size() || (_current_index == 0 && _plugins.size() == 0))
        return;

    _plugins[_current_index]->execute();
}

void Plugin_window::clear_plugins() {
    for (Plugin *plugin: _plugins) {
        plugin->clear();
    }
}

void Plugin_window::reload_plugins() {
    // Temporary disconnection for delete current plugins
    disconnect(_tab_widget, &QTabWidget::currentChanged, this, &Plugin_window::reload_plugin);
    _plugin_directories.clear();
    for (auto &_plugin: _plugins) {
        delete _plugin;
        _plugin = nullptr;
    }
    _plugins.clear();
    connect(_tab_widget, &QTabWidget::currentChanged, this, &Plugin_window::reload_plugin);
    Session::load_plugin_directories(_plugin_directories);
    load_shared_plugins();

    load_plugin("Statistics");
}

void Plugin_window::load_list() {
    //     QSettings settings("ViTE", "ViTE");
    //     QStringList list = settings.value("pluginsList").toStringList();
    //     for(QStringList::const_iterator i = list.begin() ; i != list.end() ; ++ i) {
    //         load_plugin((*i).toStdString());
    //     }
}

void Plugin_window::load_plugin(const string &plugin_name) {
    Plugin *plug = Plugin::new_instance(plugin_name);
    if (!plug) {
        cerr << "plugin " << plugin_name << " not found" << endl;
        return;
    }
    add_plugin(plug);

    //     // To save/add a plugin in the settings
    //     QSettings settings("ViTE", "ViTE");
    //     QStringList plugin_list = settings.value("pluginsList").toStringList();
    //     settings.setValue("recentFiles", files);
    //     plugin_list.removeAll(filename);
    //     plugin_list.prepend(filename);
    //     settings.setValue("pluginsList", files);
}

#include "moc_Plugin_window.cpp"
