#include <QApplication>
#include <QQmlApplicationEngine>
#include <QSqlDatabase>
#include <QSqlError>
#include <QtQml>
#include <QTranslator>
#include <unistd.h>         // Pour usleep(), msleep() et sleep()

#include "backend.h"
#include "bdd.h"
#include "shipheart.h"
#include "systeme.h"
#include "tb_mesures.h"
#include "_version.h"

    // Variables globales :
uint8_t etat_connexion_bdd;
QString TypeInstallation;
QString TailleEcran;
QString AdresseShipBase;
QTranslator translator;     // En le déclarant ici, permet d'y accéder dans les fonctions de slot ('backend()' notamment...)


//===================================================================================================
// Fonction : Connexion à la base de données
//===================================================================================================
static void connectToDatabase()
{
QString adresse_host;

    QSqlDatabase database = QSqlDatabase::database();
    if (!database.isValid()) {
        database = QSqlDatabase::addDatabase("QMYSQL");
        if (!database.isValid())
            qFatal("Cannot add database: %s", qPrintable(database.lastError().text()));
    }

    // Choix de l'adresse de la BDD :
    switch (TypeInstallation.toInt())                   // Renvoi 0 si la conversion échoue (ce qui est le cas si aucun paramètre n'est passé au démarrage, comme c'est le cas sur ShipBase)
    {
        default:
        case 0:                                         // Si on est sur ShipBase, on va se connecter sur 'localhost'
            adresse_host = BDD_HOST_NAME;
            break;
        case 1:                                         // Si on est sur un écran déporté, on va se connecter sur l'adresse de ShipBase reçue au lancement.
            // SDIR #320 :
            if (AdresseShipBase == "192.168.4.1") AdresseShipBase = "192.168.1.1";
            adresse_host = AdresseShipBase;
            // Fin de SDIR #320
        break;
    }

    database.setHostName(adresse_host);
    database.setUserName(BDD_USER_NAME);
    database.setPassword(BDD_USER_PWD);
    database.setDatabaseName(BDD_BASE_NAME);

    int16_t nb_essais;
    int16_t max_nb_essais = 20;
    etat_connexion_bdd = 0;             // Valeur par défaut (déconnecté)

    // En pratique, la tentative de connexion qui échoue dure environ 2s. Donc, avec une tempo de 1s d'attente, on fait uen tentative en 3s.
    // Exemple : avec un max = 30, le passage à l'écran de défaut de connexion sur ShipRS se fait au bout de 1min 35s après le lancement de Qt.
    for (nb_essais = 0; nb_essais < max_nb_essais; nb_essais ++)
    {
        if (!database.open())
        {
            qDebug("Erreur : impossible de se connecter à la base de données [%s]", qPrintable(database.lastError().text()));
            sleep(1);
        }
        else
        {
            etat_connexion_bdd = 1;
            qDebug() << "Connection à la base de données à l'adresse " << adresse_host << ", après essai n° " << nb_essais;
            break;
        }
    }
}


//===================================================================================================
// Fonction : Fourni à QML des valeurs accessibles en C via un singleton intégré à
//            "qt.koriolan.shipheart" (cf 'main' ci-dessous)
//===================================================================================================
static QJSValue appVersionSingletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)

    QJSValue appInfo = scriptEngine->newObject();
    appInfo.setProperty("adresse_shipbase", AdresseShipBase);
    appInfo.setProperty("etat_connexion_bdd", etat_connexion_bdd);
    appInfo.setProperty("version", VERSION);                            // Fourni la version récupérée depuis le fichier .pro afin de la rendre disponible en QML
    appInfo.setProperty("type_installation", TypeInstallation);
    appInfo.setProperty("taille_ecran", TailleEcran);
    return appInfo;
}



//===================================================================================================
// Fonction : Main
//===================================================================================================
int main(int argc, char *argv[])
{
    qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
    qputenv("QT_VIRTUALKEYBOARD_LAYOUT_PATH", ":/virtualkeyboard_layouts_koriolan/layouts");        // Ajout en V3.0.17 pour accéder aux layouts personnalisés

    #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif

    //-------------------------------------------------------------
    // Création de l'application :
    QApplication app(argc, argv);
    app.setOverrideCursor(Qt::BlankCursor);

    QApplication::setApplicationName("ShipHeart_Qt");       // Nom de l'appli si invoqué avec '-v'
    QApplication::setApplicationVersion(VERSION);           // Version de l'appli si invoqué avec '-v'

    //-------------------------------------------------------------
    // Parser de ligne de commande :
    QCommandLineParser parser;
    parser.addHelpOption();                                             // Autorise l'invocation avec '-h' ou '--help'
    parser.addVersionOption();                                          // Autorise l'invocation avec 'v' ou '--version'

    // An option with a value :
    QCommandLineOption type_installation(QStringList() << "i" << "installation",
            QApplication::translate("main", "Type d'installation :\n0 : ShipBase standard, \n1 : écran déporté"),
            QApplication::translate("main", "valeur"));
    parser.addOption(type_installation);

    QCommandLineOption adresse_shipbase(QStringList() << "a" << "adresse",
            QApplication::translate("main", "Adresse IPv4 de ShipBase dans le cas d'une installation déportée"),
            QApplication::translate("main", "xxx:xxx:xxx:xxx"));
    parser.addOption(adresse_shipbase);

    QCommandLineOption taille_ecran(QStringList() << "t" << "taille",
            QApplication::translate("main", "Taille de l'écran en pouces : \n7,\n10 (ShipBase standard),\n22"),
            QApplication::translate("main", "valeur"));
    parser.addOption(taille_ecran);

    // Process the actual command line arguments given by the user :
    parser.process(app);

    TypeInstallation = parser.value(type_installation);
    TailleEcran = parser.value(taille_ecran);
    AdresseShipBase = parser.value(adresse_shipbase);

qDebug() << "Type d'installation : " << TypeInstallation << ", adresse ShipBase : " << AdresseShipBase << ", taille d'écran : " << TailleEcran << " pouces";

    // Fin du parser de commande.
    //------------------------------------------------------------


    qmlRegisterType<Bdd>("qt.koriolan.shipheart", 1, 0, "Bdd");
    qmlRegisterType<TbMesuresModel> ("qt.koriolan.shipheart", 1, 0, "TbMesuresModel");
    qmlRegisterType<Systeme>("qt.koriolan.shipheart", 1, 0, "Systeme");
    qmlRegisterSingletonType("qt.koriolan.shipheart", 1, 0, "AppInfo", appVersionSingletonProvider);

    connectToDatabase();

    auto engine = new QQmlApplicationEngine(&app);                      // Ce type de déclaration est un peu inhabituel mais solution trouvée pour remonter à cette variable depuis l'app (nécessaire pour gérer la mise à jour de la langue dans le backend)
    engine->setObjectName("currentEngine");

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl)
    {
        if (!obj && url == objUrl) QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);

    Backend backend;
    engine->rootContext()->setContextProperty("backend", &backend);

    engine->load(url);

    if (translator.load(":/shipheart_fr_FR.qm"))                    // Par défaut, on charge le fichier FR
    {
//        qDebug() << "Chargement de shipheart_fr_FR.qm par défaut";
    }
    app.installTranslator(&translator);                             // ... et on l'installe (il sera éventuellement supprimé si la langue stockée dans la BDD est différente)

    return app.exec();
}
