/*
Copyright (c) 2006-2009, Tom Thielicke IT Solutions

SPDX-License-Identifier: GPL-2.0-only
*/

/****************************************************************
**
** Implementation of the MainWindow class
** File name: mainwindow.cpp
**
****************************************************************/

#include <QByteArray>
#include <QCoreApplication>
#include <QDate>
#include <QDesktopServices>
#include <QDir>
#include <QIcon>
#include <QMenuBar>
#include <QMessageBox>
#include <QPoint>
#include <QProcess>
#include <QRect>
#include <QSettings>
#include <QSize>
#include <QSqlQuery>

#include "def/defines.h"
#include "errormessage.h"
#include "mainwindow.h"
#include "settings.h"

MainWindow::MainWindow()
    : trainingStarted(false)
    , selectedLesson(-1)
    , selectedType(-1)
{
    createActions();
    createMenu();

    createWidgets();

    createStart();
    startWidget->fillLessonList(false);

    setMinimumSize(t10::app_width_standard, t10::app_height_standard);

    readSettings();
}

MainWindow::~MainWindow() { writeSettings(); }

void MainWindow::closeEvent(QCloseEvent* event)
{

    if (trainingStarted) {

        // Ask, if training is already started
        switch (QMessageBox::question(this, t10::app_name,
            tr("All results of the current lesson will be discarded!"
               "\n\nDo you really want to exit?\n\n"))) {

        case QMessageBox::Yes:
            // Ok button pushed
            break;
        case QMessageBox::No:
            // Cancel button pushed
            event->ignore();
            break;
        default:
            break;
        }
    }
}

void MainWindow::createMenu()
{
// Mac-Version:
//-----------
#ifdef APP_MAC
    evaluationMenu = menuBar()->addMenu(tr("&Go"));
    evaluationMenu->addAction(exitAction);
    evaluationMenu->addAction(settingsAction);
    evaluationMenu->addAction(aboutAction);
    evaluationMenu->addAction(evalAction);
    evaluationMenu->addAction(gameAction);
    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(helpAction);
    helpMenu->addSeparator();
    helpMenu->addAction(websiteAction);
#else
    // Win/X11-Version:
    // ---------------
    // Menu bar items
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(settingsAction);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAction);
    evaluationMenu = menuBar()->addMenu(tr("&Go"));
    evaluationMenu->addAction(evalAction);
    // evaluationMenu->addSeparator();
    evaluationMenu->addAction(gameAction);
    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(helpAction);
    helpMenu->addAction(websiteAction);
    helpMenu->addSeparator();
    helpMenu->addAction(aboutAction);
#endif
}

void MainWindow::createActions()
{
    settingsAction
        = new QAction(QIcon(":/img/menu_settings.png"), tr("&Settings"), this);
    exitAction = new QAction(tr("E&xit"), this);
    evalAction
        = new QAction(QIcon(":/img/menu_evaluation.png"), tr("&Results"), this);
    helpAction = new QAction(QIcon(":/img/menu_help.png"), tr("&Manual"), this);
    websiteAction = new QAction(QIcon(":/img/menu_website.png"),
        t10::app_name_intern + tr(" on the web"), this);
#ifdef APP_MAC
    aboutAction = new QAction(tr("Info"), this);
#else
    aboutAction = new QAction(tr("&About ") + t10::app_name_intern, this);
#endif
    gameAction
        = new QAction(QIcon(":/img/menu_game.png"), tr("ABC-Game"), this);

    connect(gameAction, &QAction::triggered, this,
        &MainWindow::toggleStartToAbcrain);

    // Connect bar actions
    connect(aboutAction, &QAction::triggered, this, &MainWindow::about);
    connect(exitAction, &QAction::triggered, this, &MainWindow::close);
    connect(
        settingsAction, &QAction::triggered, this, &MainWindow::showSettings);
    connect(evalAction, &QAction::triggered, this,
        &MainWindow::toggleStartToEvaluation);
    connect(websiteAction, &QAction::triggered, this, &MainWindow::openWebsite);
    connect(helpAction, &QAction::triggered, this, &MainWindow::showHelp);
}

void MainWindow::showSettings()
{
    Settings settingsDialog(this);
    settingsDialog.exec();
    // Fill lesson list after changing program settings
    startWidget->fillLessonList(false);
    startWidget->readSettings();
}

void MainWindow::showHelp()
{
    helpBrowser = new HelpBrowser("", nullptr);
    helpBrowser->show();
}

void MainWindow::openWebsite() { QDesktopServices::openUrl(t10::app_url); }

void MainWindow::about()
{

    QSqlQuery query;
    QString dbVersion = "?";
    QString softwareVersion = t10::app_version;
    QString versionText = "";

    // Get database version info
    if (!query.exec("SELECT * FROM db_version ORDER BY version DESC;")) {
        ErrorMessage* errorMessage = new ErrorMessage(this);
        errorMessage->showMessage(Error::db_version_readable,
            ErrorMessage::Type::Warning, ErrorMessage::Cancel::No);
        // return is not necessary here - "about message" anyway
    } else {
        if (query.first()) {
            // One number represents the DB version
            dbVersion = query.value(0).toString();
        }
    }
    // Show about window with image
    versionText = tr("Software Version ") + softwareVersion + "<br>"
        + tr("Database Version ") + dbVersion;
#if APP_PORTABLE
    versionText.append("<br>" + tr("Portable Version"));
#endif

    QString infoHeadline = tr("Intelligent Touch Typing Tutor");
    QString infoSubHeadline = tr("On the web: ") + "<a href=\"" + t10::app_url
        + "\">" + t10::app_url + "</a>";
    QString infoText = tr("TIPP10 is published under the GNU General Public "
                          "License and is available for free. You do not have "
                          "to pay for it wherever you download it!");
    QString licenseHeadline = "GNU General Public License";
    QString licenseSubHeadline = "TIPP10 Version 2, Copyright (c) 2006-2011, "
                                 "Tom Thielicke IT Solutions";
    QString licenseText
        = "TIPP10 comes with ABSOLUTELY NO WARRANTY; This is free software, "
          "and you are welcome to redistribute it under certain conditions.";

    QMessageBox::about(this, QString(tr("About ") + t10::app_name),
        QString::fromLatin1("<center><img src=\":/img/logo.svg\">"
                            "<h3>%1</h3>"
                            "<p>%2</p>"
                            "<p>%3</p></center>"
                            "<p>%4</p>"
                            "<p><b>%5</b><br>"
                            "%6<br>"
                            "%7</p>")
            .arg(infoHeadline)
            .arg(infoSubHeadline)
            .arg(versionText)
            .arg(infoText)
            .arg(licenseHeadline)
            .arg(licenseSubHeadline)
            .arg(licenseText));
}

void MainWindow::createWidgets()
{
    stackedWidget = new QStackedWidget(this);
    setCentralWidget(stackedWidget);
    startWidget = new StartWidget(this);
}

void MainWindow::createStart()
{
    menuBar()->show();
    // setCentralWidget(startWidget);
    stackedWidget->addWidget(startWidget);
    stackedWidget->setCurrentWidget(startWidget);
    connect(startWidget, &StartWidget::trainingClicked, this,
        &MainWindow::toggleStartToTraining);
    if (!isMaximized() && height() < t10::app_height_standard) {
        resize(t10::app_width_standard, t10::app_height_standard);
    }
    setMinimumSize(t10::app_width_standard, t10::app_height_standard);
}

void MainWindow::deleteStart()
{
    stackedWidget->removeWidget(startWidget);
    disconnect(startWidget, &StartWidget::trainingClicked, this,
        &MainWindow::toggleStartToTraining);
    startWidget->writeSettings();
    // delete startWidget;
}

void MainWindow::createTraining(int lesson, int type, QString name)
{
    trainingStarted = true;
    menuBar()->hide();
    trainingWidget = new TrainingWidget(lesson, type, name, this);
    // setCentralWidget(trainingWidget);
    stackedWidget->addWidget(trainingWidget);
    stackedWidget->setCurrentWidget(trainingWidget);
    trainingWidget->tickerBoard->setFocus();
    connect(trainingWidget, &TrainingWidget::lessonReady, this,
        &MainWindow::toggleTrainingToEvaluation);
    connect(trainingWidget, &TrainingWidget::lessonCanceled, this,
        &MainWindow::toggleTrainingToStart);
}

void MainWindow::deleteTraining()
{
    stackedWidget->removeWidget(trainingWidget);
    trainingStarted = false;
    disconnect(trainingWidget, &TrainingWidget::lessonReady, this,
        &MainWindow::toggleTrainingToEvaluation);
    disconnect(trainingWidget, &TrainingWidget::lessonCanceled, this,
        &MainWindow::toggleTrainingToStart);
    delete trainingWidget;
}

void MainWindow::createEvaluation(
    int row, int type, QList<QChar> charList, QList<int> mistakeList)
{
    menuBar()->hide();
    evaluationWidget
        = new EvaluationWidget(row, type, charList, mistakeList, this);
    // setCentralWidget(evaluationWidget);
    stackedWidget->addWidget(evaluationWidget);
    stackedWidget->setCurrentWidget(evaluationWidget);
    connect(evaluationWidget, &EvaluationWidget::readyClicked, this,
        &MainWindow::toggleEvaluationToStart);
    if (!isMaximized() && height() < t10::app_height_standard) {
        resize(t10::app_width_standard, t10::app_height_standard);
    }
    setMinimumSize(t10::app_width_standard, t10::app_height_standard);
}

void MainWindow::deleteEvaluation()
{
    stackedWidget->removeWidget(evaluationWidget);
    disconnect(evaluationWidget, &EvaluationWidget::readyClicked, this,
        &MainWindow::toggleEvaluationToStart);
    delete evaluationWidget;
}

void MainWindow::createAbcrain()
{
    menuBar()->hide();
    abcRainWidget = new AbcRainWidget(this);
    // setCentralWidget(evaluationWidget);
    stackedWidget->addWidget(abcRainWidget);
    stackedWidget->setCurrentWidget(abcRainWidget);
    connect(abcRainWidget, &AbcRainWidget::readyClicked, this,
        &MainWindow::toggleAbcrainToStart);
}

void MainWindow::deleteAbcrain()
{
    stackedWidget->removeWidget(abcRainWidget);
    disconnect(abcRainWidget, &AbcRainWidget::readyClicked, this,
        &MainWindow::toggleAbcrainToStart);
    delete abcRainWidget;
}

void MainWindow::toggleStartToTraining(int lesson, int type, QString name)
{
    selectedLesson = lesson;
    selectedType = type;
    selectedName = name;
    deleteStart();
    startWidget->fillLessonList(false);
    createTraining(lesson, type, name);
}

void MainWindow::toggleTrainingToStart()
{
    deleteTraining();
    createStart();
}

void MainWindow::toggleTrainingToEvaluation(
    int row, int type, QList<QChar> charList, QList<int> mistakeList)
{

    deleteTraining();
    createEvaluation(row, type, charList, mistakeList);
}

void MainWindow::toggleEvaluationToStart()
{
    deleteEvaluation();
    createStart();
    startWidget->fillLessonList(false);
}

void MainWindow::toggleStartToEvaluation()
{
    deleteStart();
    QList<QChar> charList;
    QList<int> mistakeList;
    createEvaluation(0, 0, charList, mistakeList);
}

void MainWindow::toggleAbcrainToStart()
{
    deleteAbcrain();
    createStart();
    startWidget->fillLessonList(false);
}

void MainWindow::toggleStartToAbcrain()
{
    deleteStart();
    createAbcrain();
}

void MainWindow::readSettings()
{
#if APP_PORTABLE
    QSettings settings(
        QCoreApplication::applicationDirPath() + "/portable/settings.ini",
        QSettings::IniFormat);
#else
    QSettings settings;
#endif

    settings.beginGroup("mainwindow");
#ifdef APP_WIN
    QByteArray storedGeometry;
    storedGeometry = settings.value("geometry").toByteArray();
    if (storedGeometry.isEmpty() || storedGeometry.isNull()) {
        resize(QSize(t10::app_width_standard, t10::app_height_standard));
        move(QPoint(100, 100));
    } else {
        restoreGeometry(storedGeometry);
    }
#else
    resize(settings
               .value("size",
                   QSize(t10::app_width_standard, t10::app_height_standard))
               .toSize());
    move(settings.value("pos", QPoint(100, 100)).toPoint());
#endif
    settings.endGroup();
}

void MainWindow::writeSettings()
{
#if APP_PORTABLE
    QSettings settings(
        QCoreApplication::applicationDirPath() + "/portable/settings.ini",
        QSettings::IniFormat);
#else
    QSettings settings;
#endif

    settings.beginGroup("mainwindow");
#ifdef APP_WIN
    settings.setValue("geometry", saveGeometry());
#else
    settings.setValue("size", size());
    settings.setValue("pos", pos());
#endif
    settings.endGroup();
}
