/*
    SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#pragma once

#include "config-kstars.h"

//Needed for Projection enum
#include "projections/projector.h"

#include <QQuickWindow>
#include <QPalette>
#include <QString>
#include <QtQml/QQmlApplicationEngine>

#include <memory>

// forward declaration is enough. We only need pointers
class KStarsData;
class SkyMapLite;
class SkyPoint;
class GeoLocation;
class ImageProvider;

class FindDialogLite;
class DetailDialogLite;
class LocationDialogLite;

class ClientManagerLite;

class QQuickItem;

/**
 * @class KStarsLite
 * @short This class loads QML files and connects SkyMapLite and KStarsData
 * Unlike KStars class it is not a main window (see KStarsLite::m_Engine) but a root object that contains the program clock and
 * holds pointers to SkyMapLite and KStarsData objects.
 * KStarsLite is a singleton, use KStarsLite::createInstance() to create an instance and KStarsLite::Instance() to get a pointer to the instance
 *
 * @author Artem Fedoskin
 * @version 1.0
 */
class KStarsLite : public QObject
{
        Q_OBJECT
        //runTutorial is a wrapper for Options::RunStartupWizard()
        Q_PROPERTY(bool runTutorial WRITE setRunTutorial READ getRunTutorial NOTIFY runTutorialChanged)
    private:

        /**
         * @short Constructor.
         * @param doSplash should the splash panel be displayed during initialization.
         * @param startClockRunning should the clock be running on startup?
         * @param startDateString date (in string representation) to start running from.
         */
        explicit KStarsLite(bool doSplash, bool startClockRunning = true, const QString &startDateString = QString());
        virtual ~KStarsLite();

        static KStarsLite *pinstance; // Pointer to an instance of KStarsLite

    public:
        /**
         * @short Create an instance of this class. Destroy any previous instance
         * @param doSplash
         * @param clockrunning
         * @param startDateString
         * @note See KStarsLite::KStarsLite for details on parameters
         * @return a pointer to the instance
         */
        static KStarsLite *createInstance(bool doSplash, bool clockrunning = true,
                                          const QString &startDateString = QString());

        /** @return a pointer to the instance of this class */
        inline static KStarsLite *Instance()
        {
            return pinstance;
        }

        /** @return pointer to SkyMapLite object which draws SkyMap. */
        inline SkyMapLite *map() const
        {
            return m_SkyMapLite;
        }

        /** @return pointer to the main window. */
        QQuickWindow *getMainWindow();

        /** @return pointer to KStarsData object which contains application data. */
        inline KStarsData *data() const
        {
            return m_KStarsData;
        }

        /** @return pointer to ImageProvider that is used in QML to display image fetched from CCD **/
        inline ImageProvider *imageProvider() const
        {
            return m_imgProvider.get();
        }

        /** @return pointer to QQmlApplicationEngine that runs QML **/
        inline QQmlApplicationEngine *qmlEngine()
        {
            return &m_Engine;
        }

        /** @short used from QML to update positions of sky objects and update SkyMapLite */
        Q_INVOKABLE void fullUpdate();

        /** @short currently sets color scheme from config **/
        Q_INVOKABLE void applyConfig(bool doApplyFocus = true);

        /** @short set whether tutorial should be shown on next startup **/
        void setRunTutorial(bool runTutorial);

        /** @return true if tutorial should be shown **/
        bool getRunTutorial();

        /** @return pointer to KStarsData object which handles connection to INDI server. */
        inline ClientManagerLite *clientManagerLite() const
        {
            return m_clientManager;
        }

        /**
         * @defgroup kconfigwrappers QML wrappers around KConfig
         * @{
         */
        enum class ObjectsToToggle
        {
            Stars,
            DeepSky,
            Planets,
            CLines,
            CBounds,
            ConstellationArt,
            MilkyWay,
            CNames,
            EquatorialGrid,
            HorizontalGrid,
            Ground,
            Flags,
            Satellites,
            Supernovae
        };

        Q_ENUMS(ObjectsToToggle)

        /** setProjection calls Options::setProjection(proj) and updates SkyMapLite */
        // Having projection as uint is not good but it will go away once KConfig is fixed
        // The reason for this is that you can't use Enums of another in class in Q_INVOKABLE function
        Q_INVOKABLE void setProjection(uint proj);

        // These functions are just convenient getters to access internals of KStars from QML

        /**
         * @short returns color with key name from current color scheme
         * @param name the key name of the color to be retrieved from current color scheme
         * @return color from name
         */
        Q_INVOKABLE QColor getColor(QString name);

        Q_INVOKABLE QString getConfigCScheme();

        /**
         * @short toggles on/off objects of group toToggle
         * @see ObjectsToToggle
         */
        Q_INVOKABLE void toggleObjects(ObjectsToToggle toToggle, bool toggle);

        /** @return true if objects from group toToggle are currently toggled on **/
        Q_INVOKABLE bool isToggled(ObjectsToToggle toToggle);

        /** @} */ // end of kconfigwrappers group

    Q_SIGNALS:
        /** Sent when KStarsData finishes loading data */
        void dataLoadFinished();

        /** Makes splash (Splash.qml) visible on startup */
        void showSplash();

        /** Emitted whenever TimeSpinBox in QML changes the scale **/
        void scaleChanged(float);

        void runTutorialChanged();

        /**
         * Once this signal is emitted, notification with text msg will appear on the screen.
         * Use this signal to output messages to user (warnings, info etc.)
         */
        void notificationMessage(QString msg);

    public Q_SLOTS:
        /**
         * Update time-dependent data and (possibly) repaint the sky map.
         * @param automaticDSTchange change DST status automatically?
         */
        void updateTime(const bool automaticDSTchange = true);

        /** Write current settings to config file. Used to save config file upon exit */
        bool writeConfig();

        /**
         * Load a color scheme.
         * @param name the name of the color scheme to load (e.g., "Moonless Night")
         */
        void loadColorScheme(const QString &name);

        /** sets time and date according to parameter time*/
        void slotSetTime(QDateTime time);

        /** action slot: toggle whether kstars clock is running or not */
        void slotToggleTimer();

        /** action slot: advance one step forward in time */
        void slotStepForward();

        /** action slot: advance one step backward in time */
        void slotStepBackward();

        /** start tracking clickedPoint or stop tracking if we are already tracking some object **/
        void slotTrack();

    private Q_SLOTS:
        /** finish setting up after the KStarsData has finished */
        void datainitFinished();

        /** Save data to config file before exiting.*/
        void handleStateChange(Qt::ApplicationState state);

    private:
        /** Initialize focus position */
        void initFocus();

        QQmlApplicationEngine m_Engine;
        SkyMapLite *m_SkyMapLite { nullptr };
        QPalette OriginalPalette, DarkPalette;

        QObject *m_RootObject { nullptr };
        bool StartClockRunning { false };

        KStarsData *m_KStarsData { nullptr };
        std::unique_ptr<ImageProvider> m_imgProvider;

        //Dialogs
        FindDialogLite *m_findDialogLite { nullptr };
        DetailDialogLite *m_detailDialogLite { nullptr };
        LocationDialogLite *m_locationDialogLite { nullptr };

        ClientManagerLite *m_clientManager { nullptr };
};
