/*
 ** 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 Session.cpp
 */

#include <iostream>
/* -- */
#include <QByteArray>
#include <QStringList>
#include <QSettings>
#include <QColor>
#include <QMap>
#include <QVariant>
#include <QCoreApplication>
#include <QDir>
#include <list>
/* -- */
#include "common/common.hpp"
/* -- */
#include "trace/values/Value.hpp"
#include "trace/values/Color.hpp"
#include "common/Palette.hpp"
#include "common/Session.hpp"

using namespace std;

/*
 *
 * Minimap Settings
 *
 */
MinimapSettings::MinimapSettings(){
    // Initialize Minimap default
    _x           = 0;
    _y           = 0;
    _width       = 200;
    _height      = 150;
    _pen_size    = 3;
    _pen_color   = Qt::red;
    _brush_color = QColor::fromRgbF(1, 1, 0, 0.5);
    _is_closed   = true;

    load();
}

MinimapSettings::~MinimapSettings() {
    save();
}

void MinimapSettings::load() {
    Session &s = Session::getSession();

    //Session::Minimap::is_closed = isHidden();
    if (s.contains("minimap/x")) {
        _x           = s.value("minimap/x").value<int>();
        _y           = s.value("minimap/y").value<int>();
        _width       = s.value("minimap/width").value<int>();
        _height      = s.value("minimap/height").value<int>();
        _pen_size    = s.value("minimap/pen_size").value<int>();
        _pen_color   = s.value("minimap/pen_color").value<QColor>();
        _brush_color = s.value("minimap/brush_color").value<QColor>();
        _is_closed   = s.value("minimap/is_closed").toBool();
    }
}

void MinimapSettings::save( ) {
    Session &s = Session::getSession();

    s.setValue( "minimap/x"        , _x );
    s.setValue( "minimap/y"        , _y );
    s.setValue( "minimap/width"    , _width );
    s.setValue( "minimap/height"   , _height );
    s.setValue( "minimap/is_closed", _is_closed );

    s.sync();
}

void MinimapSettings::save(int x, int y, int w, int h, bool hidden ) {
    _x         = x;
    _y         = y;
    _width     = w;
    _height    = h;
    _is_closed = hidden;

    save();
}

/*
 *
 * Export Settings
 *
 */
ExportSettings::ExportSettings() {
    file_dialog_state = QByteArray::number(-1);
}

bool ExportSettings::is_default() {
    return file_dialog_state == QByteArray::number(-1);
}

/*
 *
 * Common Settings
 *
 */

//QSettings *Session::_settings    = NULL;
Session   *Session::S = nullptr;
Palette   *Session::_palettes_state = nullptr;
Palette   *Session::_palettes_link  = nullptr;
Palette   *Session::_palettes_event = nullptr;
bool       Session::_use_palettes = false;
bool       Session::_use_palettes_is_set = false;

MinimapSettings *Session::_mmSettings = nullptr;
ExportSettings  *Session::_exportSettings = nullptr;

Session::Session() : QSettings( VITE_ORGANISATION_NAME, VITE_APPLICATION_NAME ) {
    QCoreApplication::setOrganizationName(VITE_ORGANISATION_NAME);
    QCoreApplication::setOrganizationDomain(VITE_ORGANISATION_DOMAIN);
    QCoreApplication::setApplicationName(VITE_APPLICATION_NAME);
}

Session::~Session() {
    delete _palettes_event;
    delete _palettes_link;
    delete _palettes_state;
    delete _mmSettings;
    delete _exportSettings;
}

void Session::init() {
    _palettes_state = get_palette("palette",     get_current_palette("palette"));
    _palettes_link  = get_palette("link_types",  get_current_palette("link_types"));
    _palettes_event = get_palette("event_types", get_current_palette("event_types"));

    _mmSettings = new MinimapSettings();
    _exportSettings = new ExportSettings();
}

const QStringList Session::get_recent_files() {
    return S->value(RECENT_FILES).toStringList();
}

void Session::add_recent_file(const QString &filename) {
    QStringList files = S->value(RECENT_FILES).toStringList();

    // We delete if the file was already call in order to be on the top of the list
    files.removeAll(filename);
    files.prepend(filename);
    while (files.size() > _MAX_NB_RECENT_FILES) {
        files.removeLast();
    }
    S->setValue(RECENT_FILES, files);
}

void Session::clear_recent_files() {
    S->remove(RECENT_FILES);
}

bool Session::get_vertical_line_setting(){
    //set 1 as the default value if not set in the file
    return S->value(VERTICAL_LINE,1).toBool();
}

void Session::update_vertical_line_setting(bool b) {
    S->setValue(VERTICAL_LINE, b);
}

bool Session::get_hide_warnings_setting(){
    //set 0 as the default value if not set in the file
    return S->value(HIDE_WARNINGS,0).toBool();
}

void Session::update_hide_warnings_settings(bool b) {
    S->setValue(HIDE_WARNINGS, b);
}

bool Session::get_shaded_states_setting(){
    //set 1 as the default value if not set in the file
    return S->value(SHADED_STATE,1).toBool();
}

void Session::update_shaded_states_setting(bool b) {
    S->setValue(SHADED_STATE, b);
}

bool Session::get_reload_type_setting(){
    //set 1 as the default value if not set in the file
    return S->value(RELOAD_TYPE,0).toBool();
}

void Session::update_reload_type_setting(bool b){
    S->setValue(RELOAD_TYPE, b);
}

/*** Plugins ***/
void Session::load_plugin_directories(QStringList &list) {
    list = S->value(PLUGIN_DIR).toStringList();

    /* We add the $HOME/.vite if not exists as a default path */
    const QString home_dir = QDir::toNativeSeparators(QDir::homePath()+"/.vite");
    if(!list.contains(home_dir)) {
        list.append(home_dir);
    }
}

void Session::save_plugin_directories(const QStringList &list) {
    S->setValue(PLUGIN_DIR, list);
}

/*** States color ***/
void Session::set_use_palette(const std::string &type, bool use) {
    S->setValue(QString::fromStdString(type+"/is_used"), use);
    _use_palettes = use;
}

bool Session::get_use_palette(const std::string &type) {
    //quick way, if we use the palettes, we don't need to check each time that we use them in the _settings file, only the first time
    if(_use_palettes_is_set)
        return _use_palettes;
    else {
        _use_palettes=S->value(QString::fromStdString(type+"/is_used")).toBool();
        _use_palettes_is_set=true;
        return _use_palettes;
    }
}

std::string Session::get_current_palette(const std::string &type) {
    std::string tmp = S->value(QString::fromStdString(type+CUR_PALETTE)).toString().toStdString();
    if(tmp == "")
        tmp = "default";
    return tmp;
}

void Session::set_current_palette(const std::string &type, const std::string &name) {
    S->setValue(QString::fromStdString(type+CUR_PALETTE), QString::fromStdString(name));
}

void Session::get_palettes_name(const std::string &type, QStringList &list) {
    list = S->value(QString::fromStdString(type+PALETTE_NAMES)).toStringList();
    if(!list.contains("default")) {
        list.append("default");
    }
}

Palette *Session::get_palette(const std::string &type, const std::string &palette_name) {
    Palette *p = NULL, **where_from;
    if( type == "palette" ) {
        p = _palettes_state;
        where_from = &_palettes_state;
    }
    else if( type == "link_types" ) {
        p = _palettes_link;
        where_from = &_palettes_link;
    }
    else if( type == "event_types" ) {
        p = _palettes_event;
        where_from = &_palettes_event;
    }

    if(!p || p->get_name() != palette_name) {
        delete p;

        QMap <QString, QVariant> qmap = S->value(QString::fromStdString(type+"/"+palette_name+"/map")).toMap();

        p = new Palette(string(type+"/"+palette_name));
        *where_from = p;
        for(QMap<QString, QVariant>::const_iterator it = qmap.constBegin() ;
            it != qmap.constEnd() ; ++ it) {
            const QColor qc = it.value().value<QColor>();
            Color c = Color(qc.red()/255., qc.green()/255., qc.blue()/255.);
            p->add_state(it.key().toStdString(), c, qc.alpha()==255.);
        }
    }
    return p;
}

void Session::create_palette(const std::string &type, const std::string &name) {
    QStringList list = S->value(QString::fromStdString(type+PALETTE_NAMES)).toStringList();
    list.append(QString::fromStdString(name));
    S->setValue(QString::fromStdString(type+PALETTE_NAMES), list);
}

void Session::remove_palette(const std::string &type, const std::string &name) {
    QStringList list = S->value(QString::fromStdString(type+PALETTE_NAMES)).toStringList();
    list.removeOne(QString::fromStdString(name));
    S->setValue(QString::fromStdString(type+PALETTE_NAMES), list);

    QString _name = QString::fromStdString(type+"/"+name+"/map");
    S->setValue(_name, QMap <QString, QVariant>());
}

void Session::copy_palette(const std::string &type, const std::string &src, const std::string &dest) {
    // Save the palette
    QStringList list = S->value(QString::fromStdString(type+PALETTE_NAMES)).toStringList();
    list.append(QString::fromStdString(dest));
    S->setValue(QString::fromStdString(type+PALETTE_NAMES), list);

    // Copy the states
    QString name_src = QString::fromStdString(type+"/"+src+"/map");
    QString name_dest = QString::fromStdString(type+"/"+dest+"/map");

    QMap <QString, QVariant> qmap = S->value(name_src).toMap();

    S->setValue(name_dest, qmap);
}

void
Session::add_state_to_palette(const std::string &type,
                              const std::string &palette_name,
                              const std::string &state_name,
                              const Color &c, bool visible)
{
    QString name = QString::fromStdString(type+"/"+palette_name+"/map");
    QMap <QString, QVariant> qmap = S->value(name).toMap();
    qmap[QString::fromStdString(state_name)] = QColor( (int)(c.get_red()  *255),
                                                       (int)(c.get_green()*255),
                                                       (int)(c.get_blue() *255),
                                                       visible == true ? 255 : 0 );
    S->setValue(name, qmap);
}

void
Session::remove_state_to_palette(const std::string &type,
                                 const std::string &palette_name,
                                 const std::string &state_name)
{
    QString name = QString::fromStdString(type+"/"+palette_name+"/map");
    QMap <QString, QVariant> qmap = S->value(name).toMap();
    qmap.remove(QString::fromStdString(state_name));
    S->setValue(name, qmap);
}
