/***************************************************************************
                          ksplanet.h  -  K Desktop Planetarium
                             -------------------
    begin                : Sun Jul 22 2001
    copyright            : (C) 2001 by Jason Harris
    email                : jharris@30doradus.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef KSPLANET_H_
#define KSPLANET_H_

#include <QVector>
#include <QHash>

#include "ksplanetbase.h"
#include "dms.h"

/** @class KSPlanet
 *A subclass of KSPlanetBase for seven of the major planets in the solar system
 *(Earth and Pluto have their own specialized classes derived from KSPlanetBase).
 *@note The Sun is subclassed from KSPlanet.
 *
 *KSPlanet contains internal classes to manage the computations of a planet's position.
 *The position is computed as a series of sinusoidal sums, similar to a Fourier
 *transform.  See "Astronomical Algorithms" by Jean Meeus or the file README.planetmath
 *for details.
 *@short Provides necessary information about objects in the solar system.
 *@author Jason Harris
 *@version 1.0
 */
class KSPlanet : public KSPlanetBase
{
  public:
    /**
         * Constructor.
         * @param s Name of planet
         * @param image_file filename of the planet's image
         * @param c the color for the planet
         * @param pSize physical diameter of the planet, in km
         */
    explicit KSPlanet(const QString &s = "unnamed", const QString &image_file = QString(), const QColor &c = Qt::white,
                      double pSize = 0);

    /**
         * Simplified constructor
         * @param n identifier of the planet to be created
         * @see PLANET enum
         */
    explicit KSPlanet(int n);

    KSPlanet *clone() const Q_DECL_OVERRIDE;
    SkyObject::UID getUID() const Q_DECL_OVERRIDE;

    /**
         * Destructor (empty)
         */
    virtual ~KSPlanet() {}

    /** @short return the untranslated name
         *This is a dirty way to solve a lot of localization-related trouble for the KDE 4.2 release
         *TODO: Change the whole architecture for names later
         */
    QString untranslatedName(void) const;

    /** @short Preload the data used by findPosition.
        	*/
    bool loadData() Q_DECL_OVERRIDE;

    /** Calculate the ecliptic longitude and latitude of the planet for
        	*the given date (expressed in Julian Millenia since J2000).  A reference
        	*to the ecliptic coordinates is returned as the second object.
        	*@param jm Julian Millenia (=jd/1000)
        	*@param ret The ecliptic coordinates are returned by reference through this argument.
        	*/
    virtual void calcEcliptic(double jm, EclipticPosition &ret) const;

  protected:
    bool data_loaded;

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

    /** @class OrbitData
        	*This class contains doubles A,B,C which represent a single term in a planet's
        	*positional expansion sums (each sum-term is A*COS(B+C*T)).
        	*@author Mark Hollomon
        	*@version 1.0
        	*/
    class OrbitData
    {
      public:
        /**
                	*Default constructor
                	*/
        OrbitData() : A(0.), B(0.), C(0.) {}
        /**
                	*Constructor
                	*@param a the A value
                	*@param b the B value
                	*@param c the C value
                	*/
        OrbitData(double a, double b, double c) : A(a), B(b), C(c) {}

        /**
                	*Assignment operator
                	*/
        OrbitData operator=(const OrbitData o) { return o; }

        double A, B, C;
    };

    typedef QVector<OrbitData> OBArray[6];

    /** OrbitDataColl contains three groups of six QVectors.  Each QVector is a
        	*list of OrbitData objects, representing a single sum used in computing
        	*the planet's position.  A set of six of these vectors comprises the large
        	*"meta-sum" which yields the planet's Longitude, Latitude, or Distance value.
        	*@author Mark Hollomon
        	*@version 1.0
        	*/
    class OrbitDataColl
    {
      public:
        /**Constructor*/
        OrbitDataColl();

        OBArray Lon;
        OBArray Lat;
        OBArray Dst;
    };

    /** OrbitDataManager places the OrbitDataColl objects for all planets in a QDict
        	*indexed by the planets' names.  It also loads the positional data of each planet
        	*from disk.
        	*@author Mark Hollomon
        	*@version 1.0
        	*/
    class OrbitDataManager
    {
      public:
        /** Constructor*/
        OrbitDataManager();

        /** Load orbital data for a planet from disk.
                	*The data is stored on disk in a series of files named
                	*"name.[LBR][0...5].vsop", where "L"=Longitude data, "B"=Latitude data,
                	*and R=Radius data.
                	*@param n the name of the planet whose data is to be loaded from disk.
                	*@param odc reference to the OrbitDataColl containing the planet's orbital data.
                	*@return true if data successfully loaded
                	*/
        bool loadData(OrbitDataColl &odc, const QString &n);

      private:
        /** Read a single orbital data file from disk into an OrbitData vector.
                *The data files are named "name.[LBR][0...5].vsop", where
                *"L"=Longitude data, "B"=Latitude data, and R=Radius data.
                *@param fname the filename to be read.
                *@param vector pointer to the OrbitData vector to be filled with these data.
                */
        bool readOrbitData(const QString &fname, QVector<KSPlanet::OrbitData> *vector);

        QHash<QString, OrbitDataColl> hash;
    };

    static OrbitDataManager odm;

  private:
    void findMagnitude(const KSNumbers *) Q_DECL_OVERRIDE;
};

#endif
