#include <QCoreApplication>
#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QFileInfo>

#ifdef __linux__
#include <stdlib.h> // system()
#endif

#include "message_handler.h"
#include "plugins/interfaces.h"

#include <unistd.h>
#include <memory>
#include <QSharedMemory>
#include <QRunnable>
#include <QThreadPool>
#include <QDir>
#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QMainWindow>

#include "update.h"
#include "git/git_client.h"
#include "ismas/ismas_client.h"
#include "worker_thread.h"
#include "worker.h"
#include "mainwindow.h"
#include "utils.h"

#include <QThread>
#include <QtWidgets>

#ifdef PTU5
#define SERIAL_PORT "ttymxc2"
#else
#define SERIAL_PORT "ttyUSB0"
#endif

#if 0
static QGraphicsProxyWidget *createItem(const QSizeF &minimum = QSizeF(100.0, 100.0),
                                        const QSizeF &preferred = QSize(150.0, 100.0),
                                        const QSizeF &maximum = QSizeF(200.0, 100.0),
                                        const QString &name = "0")
{
    QGraphicsProxyWidget *w = new QGraphicsProxyWidget;
    w->setWidget(new QPushButton(name));
    w->setData(0, name);
    w->setMinimumSize(minimum);
    w->setPreferredSize(preferred);
    w->setMaximumSize(maximum);

    w->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    return w;
}

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    QGraphicsScene scene;
    scene.setSceneRect(0, 0, 800, 480);

    QSizeF minSize(30, 100);
    QSizeF prefSize(210, 100);
    QSizeF maxSize(300, 100);

    QGraphicsProxyWidget *a = createItem(minSize, prefSize, maxSize, "A");
    QGraphicsProxyWidget *b = createItem(minSize, prefSize, maxSize, "B");
    QGraphicsProxyWidget *c = createItem(minSize, prefSize, maxSize, "C");
    QGraphicsProxyWidget *d = createItem(minSize, prefSize, maxSize, "D");
    QGraphicsProxyWidget *e = createItem(minSize, prefSize, maxSize, "E");
    QGraphicsProxyWidget *f = createItem(QSizeF(30, 50), QSizeF(150, 50), maxSize, "F (overflow)");
    QGraphicsProxyWidget *g = createItem(QSizeF(30, 50), QSizeF(30, 100), maxSize, "G (overflow)");

    QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout;
    l->setSpacing(0);

    QGraphicsWidget *w = new QGraphicsWidget(0, Qt::Window);
    w->setPos(20, 20);
    w->setLayout(l);

    // vertical
    l->addAnchor(a, Qt::AnchorTop, l, Qt::AnchorTop);
    l->addAnchor(b, Qt::AnchorTop, l, Qt::AnchorTop);

    l->addAnchor(c, Qt::AnchorTop, a, Qt::AnchorBottom);
    l->addAnchor(c, Qt::AnchorTop, b, Qt::AnchorBottom);
    l->addAnchor(c, Qt::AnchorBottom, d, Qt::AnchorTop);
    l->addAnchor(c, Qt::AnchorBottom, e, Qt::AnchorTop);

    l->addAnchor(d, Qt::AnchorBottom, l, Qt::AnchorBottom);
    l->addAnchor(e, Qt::AnchorBottom, l, Qt::AnchorBottom);

    l->addAnchor(c, Qt::AnchorTop, f, Qt::AnchorTop);
    l->addAnchor(c, Qt::AnchorVerticalCenter, f, Qt::AnchorBottom);
    l->addAnchor(f, Qt::AnchorBottom, g, Qt::AnchorTop);
    l->addAnchor(c, Qt::AnchorBottom, g, Qt::AnchorBottom);

    // horizontal
    l->addAnchor(l, Qt::AnchorLeft, a, Qt::AnchorLeft);
    l->addAnchor(l, Qt::AnchorLeft, d, Qt::AnchorLeft);
    l->addAnchor(a, Qt::AnchorRight, b, Qt::AnchorLeft);

    l->addAnchor(a, Qt::AnchorRight, c, Qt::AnchorLeft);
    l->addAnchor(c, Qt::AnchorRight, e, Qt::AnchorLeft);

    l->addAnchor(b, Qt::AnchorRight, l, Qt::AnchorRight);
    l->addAnchor(e, Qt::AnchorRight, l, Qt::AnchorRight);
    l->addAnchor(d, Qt::AnchorRight, e, Qt::AnchorLeft);

    l->addAnchor(l, Qt::AnchorLeft, f, Qt::AnchorLeft);
    l->addAnchor(l, Qt::AnchorLeft, g, Qt::AnchorLeft);
    l->addAnchor(f, Qt::AnchorRight, g, Qt::AnchorRight);


    scene.addItem(w);
    scene.setBackgroundBrush(Qt::darkGreen);
    QGraphicsView view(&scene);

    view.show();

    return app.exec();
}
#endif

// argv[1]: file to send to dc
int main(int argc, char *argv[]) {
    QByteArray const value = qgetenv("LC_ALL");
    if (value != "C") {
        qputenv("LC_ALL", "C");
    }
    // qputenv("XDG_RUNTIME_DIR", "/run/user/0");

    openlog("ATB-UPDATE", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);

    QApplication a(argc, argv);
    QApplication::setApplicationName("ATBUpdateTool");
    QApplication::setApplicationVersion(APP_VERSION);

#if 0
    // vorbereitend
    QGraphicsScene scene;
    scene.setSceneRect(0, 0, 800, 480);

    QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout;
    l->setSpacing(0);

    QGraphicsWidget *w = new QGraphicsWidget(0, Qt::Window);
    w->setPos(20, 20);
    w->setLayout(l);

    QGraphicsView view(&scene);
    // view.show();
#endif

    if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
        atbInstallMessageHandler(atbDebugOutput);
        setDebugLevel(LOG_NOTICE);
    }

    QCommandLineParser parser;
    parser.setApplicationDescription("Download tool for downloading device controller firmware, printer json-files and executing opkg-commands.");
    parser.addHelpOption();
    parser.addVersionOption();

    QCommandLineOption pluginDirectoryOption(QStringList() << "plugin-directory" << "plugin-directory",
        QCoreApplication::translate("main", "Where to find dc-plugin."),
        QCoreApplication::translate("main", "directory"));
    QString const pluginDefault = "/usr/lib";
    pluginDirectoryOption.setDefaultValue(pluginDefault);
    parser.addOption(pluginDirectoryOption);

    QCommandLineOption pluginNameOption(QStringList() << "plugin-name" << "plugin-name",
        QCoreApplication::translate("main", "Name of dc-plugin."),
        QCoreApplication::translate("main", "directory"));
    QString const pluginNameDefault = "libCAmaster.so";
    pluginNameOption.setDefaultValue(pluginNameDefault);
    parser.addOption(pluginNameOption);

    QCommandLineOption workingDirectoryOption(QStringList() << "working-directory" << "working-directory",
        QCoreApplication::translate("main", "working directory of update-script."),
        QCoreApplication::translate("main", "directory"));
    QString const workingDirectoryDefault = "/opt/app/tools/atbupdate";
    workingDirectoryOption.setDefaultValue(workingDirectoryDefault);
    parser.addOption(workingDirectoryOption);

    QCommandLineOption dryRunOption(QStringList() << "d" << "dry-run",
        QCoreApplication::translate("main", "Start ATBUpdateTool in dry-run-mode. No actual actions."));
    parser.addOption(dryRunOption);

    // Process the actual command line arguments given by the user
    parser.process(a);
    QString plugInDir = parser.value(pluginDirectoryOption);
    QString plugInName = parser.value(pluginNameOption);
    QString workingDir = parser.value(workingDirectoryOption);
    bool dryRun = parser.isSet(dryRunOption);
    QString const rtPath = QCoreApplication::applicationDirPath();

    if (!QDir(plugInDir).exists()) {
        qCritical() << plugInDir
                    << "does not exists, but has to contain dc-library";
        exit(-1);
    }

    qInfo() << "pwd ..............." << rtPath;
    qInfo() << "plugInDir ........." << plugInDir;
    qInfo() << "plugInName ........" << plugInName;
    qInfo() << "workingDir ........" << workingDir;
    qInfo() << "dryRun ............" << dryRun;

    // before loading the library, delete all possible shared memory segments
#if defined Q_OS_LINUX || defined Q_OS_UNIX
    // system("rm -rf /tmp/qipc*");
#else
#error "Only tested under UNIX/LINUX"
#endif

    hwinf *hw = Update::loadDCPlugin(QDir(plugInDir), plugInName);
    // hw->dc_autoRequest(false);

    int machineNr = Utils::read1stLineOfFile("/etc/machine_nr");
    int customerNr = Utils::read1stLineOfFile("/etc/cust_nr");
    int zoneNr = Utils::read1stLineOfFile("/etc/zone_nr");
    QString const branchName = (zoneNr != 0)
            ? QString("zg1/zone%1").arg(zoneNr) : "master";

    QThread::currentThread()->setObjectName("main thread");
    qInfo() << "Main thread" << QThread::currentThreadId();

    Worker worker(hw,
                  customerNr,
                  machineNr,
                  zoneNr,
                  branchName,
                  workingDir,
                  dryRun);

    MainWindow mw(&worker);
    worker.setMainWindow(&mw);

    mw.setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
    mw.setWindowState(Qt::WindowFullScreen);
    mw.show();

    return a.exec();
}
