/*
    SPDX-FileCopyrightText: 2003 Jason Harris <kstars@30doradus.org>

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

#pragma once

#include "skypoint.h"

#include <QImage>
#include <QList>
#include <QString>
#include <QtDBus/QDBusArgument>

class QPainter;

/**
 * @class FOV
 * A simple class encapsulating a Field-of-View symbol
 *
 * The FOV size, shape, name, and color can be customized. The rotation is by default 0 degrees East Of North.
 * @author Jason Harris
 * @author Jasem Mutlaq
 * @version 1.1
 */
class FOV : public QObject
{
  Q_OBJECT
  Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.fov")

  Q_PROPERTY(QString name MEMBER m_name)
  Q_PROPERTY(FOV::Shape shape MEMBER m_shape)
  Q_PROPERTY(float sizeX MEMBER m_sizeX)
  Q_PROPERTY(float sizeY MEMBER m_sizeY)
  Q_PROPERTY(float offsetX MEMBER m_offsetX)
  Q_PROPERTY(float offsetY MEMBER m_offsetY)
  Q_PROPERTY(float PA MEMBER m_PA)
  Q_PROPERTY(QString color MEMBER m_color)
  Q_PROPERTY(bool cpLock MEMBER m_lockCelestialPole)

  public:
    enum Shape
    {
        SQUARE,
        CIRCLE,
        CROSSHAIRS,
        BULLSEYE,
        SOLIDCIRCLE,
        UNKNOWN
    };

    /** Default constructor */
    FOV();
    FOV(const QString &name, float a, float b = -1, float xoffset = 0, float yoffset = 0, float rot = 0,
        Shape shape = SQUARE, const QString &color = "#FFFFFF", bool useLockedCP = false);
    FOV(const FOV &other);

    void sync(const FOV &other);

    inline Q_SCRIPTABLE QString name() const { return m_name; }
    void setName(const QString &n) { m_name = n; }

    inline FOV::Shape shape() const { return m_shape; }
    void setShape(FOV::Shape s) { m_shape = s; }
    //void setShape(int s);

    /** Sizes are in arcminutes */
    inline float sizeX() const { return m_sizeX; }
    inline float sizeY() const { return m_sizeY; }
    void setSize(float s) { m_sizeX = m_sizeY = s; }
    void setSize(float sx, float sy)
    {
        m_sizeX = sx;
        m_sizeY = sy;
    }

    void setOffset(float fx, float fy)
    {
        m_offsetX = fx;
        m_offsetY = fy;
    }
    inline float offsetX() const { return m_offsetX; }
    inline float offsetY() const { return m_offsetY; }

    // Position Angle
    void setPA(float rt) { m_PA = rt; }
    inline float PA() const { return m_PA; }

    inline QString color() const { return m_color; }
    void setColor(const QString &c) { m_color = c; }

    /**
     * @short draw the FOV symbol on a QPainter
     * @param p reference to the target QPainter. The painter should already be started.
     * @param zoomFactor is zoom factor as in SkyMap.
     */
    void draw(QPainter &p, float zoomFactor);

    /**
     * @short draw FOV symbol so it will be inside a rectangle
     * @param p reference to the target QPainter. The painter should already be started.
     * @param x is X size of rectangle
     * @param y is Y size of rectangle
     */
    void draw(QPainter &p, float x, float y);

    SkyPoint center() const;
    void setCenter(const SkyPoint &center);

    float northPA() const;
    void setNorthPA(float northPA);

    void setImage(const QImage &image);

    void setImageDisplay(bool value);

    bool lockCelestialPole() const;
    void setLockCelestialPole(bool lockCelestialPole);

private:
    QString m_name, m_color;
    FOV::Shape m_shape;
    float m_sizeX { 0 }, m_sizeY { 0 };
    float m_offsetX { 0 }, m_offsetY { 0 };
    float m_PA { 0 };
    float m_northPA { 0 };
    SkyPoint m_center;
    QImage m_image;
    bool m_imageDisplay { false };
    bool m_lockCelestialPole { false };

    static int getID() { return m_ID++; }
    static int m_ID;
};

/**
 * @class FOVManager
 * A simple class handling FOVs.
 * @note Should migrate this from file (fov.dat) to using the user sqlite database
 * @author Jasem Mutlaq
 * @version 1.0
 */
class FOVManager
{
  public:
    /** @short Read list of FOVs from "fov.dat" */
    static const QList<FOV *> &readFOVs();
    /** @short Release the FOV cache */
    static void releaseCache();
    static void addFOV(FOV *newFOV)
    {
        Q_ASSERT(newFOV);
        m_FOVs.append(newFOV);
    }
    static void removeFOV(FOV *fov)
    {
        Q_ASSERT(fov);
        m_FOVs.removeOne(fov);
    }
    static const QList<FOV *> &getFOVs() { return m_FOVs; }

    /** @short Write list of FOVs to "fov.dat" */
    static bool save();

  private:
    FOVManager() = default;
    ~FOVManager();

    /** @short Fill list with default FOVs*/
    static QList<FOV *> defaults();

    static QList<FOV *> m_FOVs;
};

// Shape
Q_DECLARE_METATYPE(FOV::Shape)
QDBusArgument &operator<<(QDBusArgument &argument, const FOV::Shape& source);
const QDBusArgument &operator>>(const QDBusArgument &argument, FOV::Shape &dest);
