// SPDX-License-Identifier: LGPL-2.1-or-later
//
// SPDX-FileCopyrightText: 2014 Dennis Nienhüser <nienhueser@kde.org>
// SPDX-FileCopyrightText: 2014 Abhinav Gangwar <abhgang@gmail.com>
//

// Self
#include "GameMainWindow.h"
#include "ClickOnThat.h"
#include "CountryByFlag.h"
#include "CountryByShape.h"

#include "ui_game.h"

// Qt
#include <QDebug>
#include <QFileInfo>
#include <QList>
#include <QQuickItem>
#include <QQuickView>
#include <QResizeEvent>
#include <QSettings>
#include <QSize>
#include <QString>
#include <QUrl>
#include <QVBoxLayout>

// Marble
#include <marble/GeoDataTreeModel.h>
#include <marble/MarbleDirs.h>
#include <marble/MarbleMap.h>
#include <marble/MarbleModel.h>
#include <marble/MarblePlacemarkModel.h>
#include <marble/MarbleWidget.h>
#include <marble/RenderPlugin.h>

#include <marble/GeoDataDocument.h>
#include <marble/GeoDataGeometry.h>
#include <marble/GeoDataLatLonAltBox.h>
#include <marble/GeoDataLinearRing.h>
#include <marble/GeoDataMultiGeometry.h>
#include <marble/GeoDataPlacemark.h>
#include <marble/GeoDataPoint.h>
#include <marble/GeoDataPolygon.h>

namespace Marble
{

class Private : public Ui_MainWindow
{
public:
    Private(QWidget *parent = nullptr);

    MarbleWidget *m_marbleWidget;
    QWidget *m_parent;
    QQuickView m_view;
    CountryByShape *m_countryByShape;
    CountryByFlag *m_countryByFlag;
    ClickOnThat *m_clickOnThat;

    QString readMarbleDataPath() const;
    void setupMarbleWidget();
    void setupGameSignals();
};

Private::Private(QWidget *parent)
    : m_marbleWidget(new MarbleWidget(parent))
    , m_parent(parent)
    , m_view()
    , m_countryByShape(new CountryByShape(m_marbleWidget))
    , m_countryByFlag(new CountryByFlag(m_marbleWidget))
    , m_clickOnThat(new ClickOnThat(m_marbleWidget))
{
    // nothing to do
}

QString Private::readMarbleDataPath() const
{
    return QSettings().value(QStringLiteral("MarbleWidget/marbleDataPath"), QString()).toString();
}

void Private::setupMarbleWidget()
{
    m_marbleWidget->setMapThemeId(QStringLiteral("earth/political/political.dgml"));

    const auto plugins = m_marbleWidget->renderPlugins();
    for (RenderPlugin *renderPlugin : plugins) {
        if (renderPlugin->nameId() == QLatin1StringView("stars") || renderPlugin->nameId() == QLatin1StringView("overviewmap")
            || renderPlugin->nameId() == QLatin1StringView("compass") || renderPlugin->nameId() == QLatin1StringView("scalebar")
            || renderPlugin->nameId() == QLatin1StringView("navigation")) {
            renderPlugin->setVisible(false);
        }
    }

    m_marbleWidget->centerOn(23.0, 42.0);
    m_marbleWidget->setDistance(7500);

    m_parent->connect(m_parent,
                      SIGNAL(announceHighlight(qreal, qreal, GeoDataCoordinates::Unit)),
                      m_marbleWidget,
                      SIGNAL(highlightedPlacemarksChanged(qreal, qreal, GeoDataCoordinates::Unit)));
}

void Private::setupGameSignals()
{
    QObject *root = m_view.rootObject();
    if (root) {
        m_parent->connect(root, SIGNAL(browseMapButtonClicked()), m_parent, SLOT(browseMapButtonClicked()));
        QObject *gameOptions = root->findChild<QObject *>(QStringLiteral("gameOptions"));

        m_parent->connect(gameOptions, SIGNAL(nextButtonClicked()), m_parent, SLOT(createQuestion()));
        m_parent->connect(gameOptions, SIGNAL(gameClosed()), m_parent, SLOT(disableGames()));

        // For "Identify the highlighted country" game
        m_parent->connect(gameOptions, SIGNAL(countryByShapeGameRequested()), m_parent, SLOT(enableCountryShapeGame()));
        m_parent->connect(m_countryByShape, SIGNAL(gameInitialized()), m_parent, SLOT(createQuestion()));

        // For "Identify the flag" game
        m_parent->connect(gameOptions, SIGNAL(countryByFlagGameRequested()), m_parent, SLOT(enableCountryFlagGame()));
        m_parent->connect(m_countryByFlag, SIGNAL(gameInitialized()), m_parent, SLOT(createQuestion()));

        // For "Click on that country" game
        m_parent->connect(gameOptions, SIGNAL(clickOnThatGameRequested()), m_parent, SLOT(enableClickOnThatGame()));
        m_parent->connect(m_clickOnThat, SIGNAL(gameInitialized()), m_parent, SLOT(createQuestion()));
        m_parent->connect(gameOptions, SIGNAL(answerDisplayButtonClicked()), m_clickOnThat, SLOT(highlightCorrectAnswer()));
    }
}

MainWindow::MainWindow(const QString &marbleDataPath, QWidget *parent)
    : QMainWindow(parent)
    , d(new Private(this))
{
    d->setupUi(this);
    QString const dataPath = marbleDataPath.isEmpty() ? d->readMarbleDataPath() : marbleDataPath;
    if (!dataPath.isEmpty()) {
        MarbleDirs::setMarbleDataPath(dataPath);
    }

    d->setupMarbleWidget();
    setCentralWidget(d->m_marbleWidget);

    d->m_view.setSource(QUrl(QStringLiteral("qrc:/Window.qml")));

    QWidget *leftPanel = QWidget::createWindowContainer(&d->m_view, d->dockWidgetContents);
    QVBoxLayout *layout = new QVBoxLayout(d->dockWidgetContents);
    layout->addWidget(leftPanel);
    d->dockWidgetContents->setLayout(layout);

    d->setupGameSignals();
}

MainWindow::~MainWindow()
{
    delete d;
}

MarbleWidget *MainWindow::marbleWidget()
{
    return d->m_marbleWidget;
}

void MainWindow::createQuestion()
{
    QObject *gameObject = d->m_view.rootObject()->findChild<QObject *>(QStringLiteral("gameOptions"));
    if (gameObject) {
        emit postQuestion(gameObject);
    }
}

void MainWindow::browseMapButtonClicked()
{
    d->m_marbleWidget->setMapThemeId(QStringLiteral("earth/political/political.dgml"));

    /**
     * Now display the country names which
     * were removed to initiate the game
     */
    const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel();
    for (int i = 0; i < treeModel->rowCount(); ++i) {
        QVariant const data = treeModel->data(treeModel->index(i, 0), MarblePlacemarkModel::ObjectPointerRole);
        GeoDataObject *object = qvariant_cast<GeoDataObject *>(data);
        Q_ASSERT_X(object, "MainWindow::browseMapButtonClicked", "failed to get valid data from treeModel for GeoDataObject");
        if (auto doc = geodata_cast<GeoDataDocument>(object)) {
            QFileInfo fileInfo(doc->fileName());
            QString fileName = fileInfo.fileName();
            if (fileName == QLatin1StringView("boundaryplacemarks.cache")) {
                doc->setVisible(true);
                d->m_marbleWidget->model()->treeModel()->updateFeature(doc);
                d->m_marbleWidget->setHighlightEnabled(true);
                break;
            }
        }
    }
}

void MainWindow::disableGames()
{
    disconnect(this, SIGNAL(postQuestion(QObject *)), d->m_countryByShape, SLOT(postQuestion(QObject *)));

    disconnect(this, SIGNAL(postQuestion(QObject *)), d->m_countryByFlag, SLOT(postQuestion(QObject *)));

    disconnect(this, SIGNAL(postQuestion(QObject *)), d->m_clickOnThat, SLOT(postQuestion(QObject *)));
    disconnect(d->m_clickOnThat, SIGNAL(updateResult(bool)), this, SLOT(displayResult(bool)));
    disconnect(d->m_marbleWidget,
               SIGNAL(highlightedPlacemarksChanged(qreal, qreal, GeoDataCoordinates::Unit)),
               d->m_clickOnThat,
               SLOT(determineResult(qreal, qreal, GeoDataCoordinates::Unit)));
    d->m_clickOnThat->disablePinDocument();

    // Reset the map view
    d->m_marbleWidget->centerOn(23.0, 42.0);
    d->m_marbleWidget->setDistance(7500);
}

void MainWindow::enableCountryShapeGame()
{
    connect(this, SIGNAL(postQuestion(QObject *)), d->m_countryByShape, SLOT(postQuestion(QObject *)));

    d->m_countryByShape->initiateGame();
}

void MainWindow::enableCountryFlagGame()
{
    connect(this, SIGNAL(postQuestion(QObject *)), d->m_countryByFlag, SLOT(postQuestion(QObject *)));

    d->m_countryByFlag->initiateGame();
}

void MainWindow::enableClickOnThatGame()
{
    connect(this, SIGNAL(postQuestion(QObject *)), d->m_clickOnThat, SLOT(postQuestion(QObject *)));
    connect(d->m_clickOnThat, SIGNAL(updateResult(bool)), this, SLOT(displayResult(bool)));
    d->m_clickOnThat->initiateGame();
}

void MainWindow::displayResult(bool result)
{
    QObject *gameObject = d->m_view.rootObject()->findChild<QObject *>(QStringLiteral("gameOptions"));
    if (gameObject) {
        QMetaObject::invokeMethod(gameObject, "displayResult", Q_ARG(QVariant, QVariant(result)));
    }
}

/*
 * As the height of main window is changed, update the
 * height ( leftPanelHeight ) in window.qml
 */
void MainWindow::resizeEvent(QResizeEvent *event)
{
    const QSize size = event->size();

    QObject *root = d->m_view.rootObject();

    if (root) {
        QMetaObject::invokeMethod(root, "resizeWindow", Q_ARG(QVariant, QVariant(size.height() * 9 / 10)));
    }
}

} // namespace Marble

#include "moc_GameMainWindow.cpp"
