/***************************************************************************
                          ksnumbers.h  -  description
                             -------------------
    begin                : Sun Jan 13 2002
    copyright            : (C) 2002-2005 by Jason Harris
    email                : kstars@30doradus.org
    copyright            : (C) 2004-2005 by Pablo de Vicente
    email                : p.devicente@wanadoo.es
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#pragma once

#include "cachingdms.h"

#if __GNUC__ > 5
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
#if __GNUC__ > 6
#pragma GCC diagnostic ignored "-Wint-in-bool-context"
#endif
#include <Eigen/Core>
#if __GNUC__ > 5
#pragma GCC diagnostic pop
#endif

#define NUTTERMS 63

/** @class KSNumbers
	*
	*There are several time-dependent values used in position calculations,
	*that are not specific to an object.  This class provides
	*storage for these values, and methods for calculating them for a given date.
	*The numbers include solar data like the true/mean solar anomalies
	*and longitudes, the longitude of the Earth's perihelion, the
	*eccentricity of Earth's orbit, the
	*constant of aberration, the obliquity of the Ecliptic, the effects of
	*Nutation (delta Obliquity and delta Ecliptic longitude),
	*the Julian Day/Century/Millenium, and arrays for computing the precession.
	*@short Store several time-dependent astronomical quantities.
	*@author Jason Harris
	*@version 1.0
	*/

class KSNumbers
{
  public:
    /**
     * Constructor.
     * @param jd  Julian Day for which the new instance is initialized
     */
    explicit KSNumbers(long double jd);
    ~KSNumbers() = default;

    /**
     * @return the current Obliquity (the angle of inclination between
     * the celestial equator and the ecliptic)
     */
    inline const CachingDms *obliquity() const { return &Obliquity; }

    /** @return the constant of aberration (20.49 arcsec). */
    inline dms constAberr() const { return K; }

    /** @return the mean solar anomaly. */
    inline dms sunMeanAnomaly() const { return M; }

    /** @return the mean solar longitude. */
    inline dms sunMeanLongitude() const { return L; }

    /** @return the true solar anomaly. */
    inline dms sunTrueAnomaly() const { return M0; }

    /** @return the true solar longitude. */
    inline CachingDms sunTrueLongitude() const { return L0; }

    /** @return the longitude of the Earth's perihelion point. */
    inline CachingDms earthPerihelionLongitude() const { return P; }

    /** @return eccentricity of Earth's orbit.*/
    inline double earthEccentricity() const { return e; }

    /** @return the change in obliquity due to the nutation of
         * Earth's orbit. Value is in degrees */
    inline double dObliq() const { return deltaObliquity; }

    /** @return the change in Ecliptic Longitude due to nutation.
         * Value is in degrees. */
    inline double dEcLong() const { return deltaEcLong; }

    /** @return Julian centuries since J2000*/
    inline double julianCenturies() const { return T; }

    /** @return Julian Day*/
    inline long double julianDay() const { return days; }

    /** @return Julian Millenia since J2000*/
    inline double julianMillenia() const { return jm; }

    /** @return element of P1 precession array at position (i1, i2) */
    inline double p1(int i1, int i2) const { return P1(i1, i2); }

    /** @return element of P2 precession array at position (i1, i2) */
    inline double p2(int i1, int i2) const { return P2(i1, i2); }

    /** @return element of P1B precession array at position (i1, i2) */
    inline double p1b(int i1, int i2) const { return P1B(i1, i2); }

    /** @return element of P2B precession array at position (i1, i2) */
    inline double p2b(int i1, int i2) const { return P2B(i1, i2); }

    /** @return the precession matrix directly **/
    inline const Eigen::Matrix3d &p2() const { return P1; }
    inline const Eigen::Matrix3d &p1() const { return P2; }
    inline const Eigen::Matrix3d &p1b() const { return P1B; }
    inline const Eigen::Matrix3d &p2b() const { return P2B; }

    /**
     * @short compute constant values that need to be computed only once per instance of the application
     */
    void computeConstantValues();

    /**
     * @short update all values for the date given as an argument.
     * @param jd the Julian date for which to compute values
     */
    void updateValues(long double jd);

    /**
     * @return the JD for which these values hold (i.e. the last updated JD)
     */
    inline long double getJD() const { return days; }

    inline double vEarth(int i) const { return vearth[i]; }

  private:
    CachingDms Obliquity, L0, P;
    dms K, L, LM, M, M0, O, D, MM, F;
    dms XP, YP, ZP, XB, YB, ZB;
    double CX, SX, CY, SY, CZ, SZ;
    double CXB, SXB, CYB, SYB, CZB, SZB;
    Eigen::Matrix3d P1, P2, P1B, P2B;
    double deltaObliquity, deltaEcLong;
    double e, T;
    long double days; // JD for which the last update was called
    double jm;
    static const int arguments[NUTTERMS][5];
    static const int amp[NUTTERMS][4];
    double vearth[3];
};
