/*
    SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>

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

#pragma once

#include "ksplanetbase.h"

#include <QDataStream>

class dms;
class KSNumbers;

/** @class KSAsteroid
	*@short A subclass of KSPlanetBase that implements asteroids.
	*
    * All elements are in the heliocentric ecliptic J2000 reference frame.
    *
    * Check here for full description: https://ssd.jpl.nasa.gov/?sb_elem#legend
    *
	*The orbital elements are stored as private member variables, and it
	*provides methods to compute the ecliptic coordinates for any time
	*from the orbital elements.
	*
	*The orbital elements are:
	*@li JD    Epoch of element values
	*@li a     semi-major axis length (AU)
	*@li e     eccentricity of orbit
	*@li i     inclination angle (with respect to J2000.0 ecliptic plane)
	*@li w     argument of perihelion (w.r.t. J2000.0 ecliptic plane)
	*@li N     longitude of ascending node (J2000.0 ecliptic)
	*@li M     mean anomaly at epoch JD
	*@li H     absolute magnitude
	*@li G     slope parameter
	*
	*@author Jason Harris
	*@version 1.0
	*/
class KSAsteroid : public KSPlanetBase
{
    public:
        /** Constructor.
                *@p catN number of asteroid
            	*@p s    the name of the asteroid
            	*@p image_file the filename for an image of the asteroid
            	*@p JD the Julian Day for the orbital elements
            	*@p a the semi-major axis of the asteroid's orbit (AU)
            	*@p e the eccentricity of the asteroid's orbit
            	*@p i the inclination angle of the asteroid's orbit
            	*@p w the argument of the orbit's perihelion
            	*@p N the longitude of the orbit's ascending node
            	*@p M the mean anomaly for the Julian Day
            	*@p H absolute magnitude
                *@p G slope parameter
            	*/
        KSAsteroid(int catN, const QString &s, const QString &image_file, long double JD, double a, double e, dms i, dms w,
                   dms N, dms M, double H, double G);

        KSAsteroid *clone() const override;
        SkyObject::UID getUID() const override;

        static const SkyObject::TYPE TYPE = SkyObject::ASTEROID;

        /** Destructor (empty)*/
        ~KSAsteroid() override = default;

        /** This is inherited from KSPlanetBase.  We don't use it in this class,
            	*so it is empty.
            	*/
        bool loadData() override;

        /** This lets other classes like KSPlanetBase access H and G values
            *Used by KSPlanetBase::FindMagnitude
            */
        double inline getAbsoluteMagnitude() const
        {
            return H;
        }
        double inline getSlopeParameter() const
        {
            return G;
        }

        /**
             *@short Sets the asteroid's perihelion distance
             */
        void setPerihelion(double perihelion);

        /**
             *@return Perihelion distance
             */
        inline double getPerihelion() const
        {
            return q;
        }

        /**
              *@short Sets the asteroid's earth minimum orbit intersection distance
              */
        void setEarthMOID(double earth_moid);

        /**
             *@return the asteroid's earth minimum orbit intersection distance in AU
             */
        inline double getEarthMOID() const
        {
            return EarthMOID;
        }

        /**
             *@short Sets the asteroid's orbit solution ID
             */
        void setOrbitID(QString orbit_id);

        /**
             *@return the asteroid's orbit solution ID
             */
        inline QString getOrbitID() const
        {
            return OrbitID;
        }

        /**
             *@short Sets the asteroid's orbit class
             */
        void setOrbitClass(QString orbit_class);

        /**
             *@return the asteroid's orbit class
             */
        inline QString getOrbitClass() const
        {
            return OrbitClass;
        }

        /**
             *@short Sets if the comet is a near earth object
             */
        void setNEO(bool neo);

        /**
             *@return true if the asteroid is a near earth object
             */
        inline bool isNEO() const
        {
            return NEO;
        }

        /**
             *@short Sets the asteroid's albedo
             */
        void setAlbedo(float albedo);

        /**
             *@return the asteroid's albedo
             */
        inline float getAlbedo() const
        {
            return Albedo;
        }

        /**
             *@short Sets the asteroid's diameter
             */
        void setDiameter(float diam);

        /**
             *@return the asteroid's diameter
             */
        inline float getDiameter() const
        {
            return Diameter;
        }

        /**
             *@short Sets the asteroid's dimensions
             */
        void setDimensions(QString dim);

        /**
             *@return the asteroid's dimensions
             */
        inline QString getDimensions() const
        {
            return Dimensions;
        }

        /**
            *@short Sets the asteroid's rotation period
            */
        void setRotationPeriod(float rot_per);

        /**
             *@return the asteroid's rotation period
             */
        inline float getRotationPeriod() const
        {
            return RotationPeriod;
        }

        /**
            *@short Sets the asteroid's period
            */
        void setPeriod(float per);

        /**
             *@return the asteroid's period
             */
        inline float getPeriod() const
        {
            return Period;
        }

        // TODO: Add top level implementation
        /**
         * @brief toDraw
         * @return whether to draw the asteroid
         *
         * Note that you'd check for other, older filtering methids
         * upn implementing this on other types! (a.k.a find nearest)
         */
        inline bool toDraw()
        {
            return toCalculate();
        }

        /**
         * @brief toCalculate
         * @return whether to calculate the position
         */
        bool toCalculate();

    protected:
        /** Calculate the geocentric RA, Dec coordinates of the Asteroid.
            	*@note reimplemented from KSPlanetBase
            	*@param num time-dependent values for the desired date
            	*@param Earth planet Earth (needed to calculate geocentric coords)
            	*@return true if position was successfully calculated.
            	*/
        bool findGeocentricPosition(const KSNumbers *num, const KSPlanetBase *Earth = nullptr) override;

        //these set functions are needed for the new KSPluto subclass
        void set_a(double newa)
        {
            a = newa;
        }
        void set_e(double newe)
        {
            e = newe;
        }
        void set_P(double newP)
        {
            P = newP;
        }
        void set_i(double newi)
        {
            i.setD(newi);
        }
        void set_w(double neww)
        {
            w.setD(neww);
        }
        void set_M(double newM)
        {
            M.setD(newM);
        }
        void set_N(double newN)
        {
            N.setD(newN);
        }
        void setJD(long double jd)
        {
            JD = jd;
        }


    private:
        /**
         * Serializers
         */
        friend QDataStream &operator<<(QDataStream &out, const KSAsteroid &asteroid);
        friend QDataStream &operator>>(QDataStream &in, KSAsteroid * &asteroid);

        void findMagnitude(const KSNumbers *) override;

        int catN { 0 };
        long double JD { 0 };
        double q { 0 };
        double a { 0 };
        double e { 0 };
        double P { 0 };
        double EarthMOID { 0 };
        float Albedo { 0 };
        float Diameter { 0 };
        float RotationPeriod { 0 };
        float Period { 0 };
        dms i, w, M, N;
        double H { 0 };
        double G { 0 };
        QString OrbitID, OrbitClass, Dimensions;
        bool NEO { false };
};
