/* ============================================================
 *
 * This file is a part of digiKam project
 * https://www.digikam.org
 *
 * Date        : 2023-05-15
 * Description : geolocation engine based on Marble.
 *               (c) 2007-2022 Marble Team
 *               https://invent.kde.org/education/marble/-/raw/master/data/credits_authors.html
 *
 * SPDX-FileCopyrightText: 2023-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 * ============================================================ */

#pragma once

// Local includes

#include "attlib.h"
#include "digikam_export.h"

namespace Marble
{

const int GBL_ECLBUF = 12;          // maximum number of eclipses allowed
const int MAXLUN     = 15;

typedef double PMJD[MAXLUN];        // array of MJD's of the respective phase

class DIGIKAM_EXPORT EclSolar       // Calculate Solar Eclipses
{
public:

    EclSolar();
    ~EclSolar();

public:

    int getYear() const;  // the year currently used by EclSolar
    void putYear(int yr);  // set the year to be used by EclSolar
    int getNumberEclYear();  // get the number of eclipses of the currently selected year
    void setLunarEcl(bool lecl);  // include lunar eclipses
    void setStepWidth(double s);  // set the step width (minutes)
    void setTimezone(double d);  // set timezone for I/O
    void setDeltaTAI_UTC(double d);  // set IERS Parameter TAI - UTC
    void setAutoTAI_UTC();  // IERS Parameter TAI - UTC to auto
    void setLocalPos(double lat, double lng, double hgt); // set local geographic coordinates
    void getLocalDetails(char* otxt);  // provide eclipse details for local position
    void setCurrentMJD(int year, int month, int day, int hour, int min, double sec); // set current time
    void getDatefromMJD(double mjd, int& year, int& month, int& day,
                        int& hour, int& min, double& sec) const; // convert MJD into date and time
    int getLocalVisibility(double& mjd_start, double& mjd_stop);  // local start and stop times for eclipse
    int getLocalTotal(double& mjd_start, double& mjd_stop);  // local start and stop times for totality/annularity
    int getLocalMax(double& mjdmax, double& magmax, double& elmax);  // get local (solar) eclipse maximum
    int getPenumbra(double& mjd_start, double& mjd_stop);  // start and stop times for penumbral eclipse of Moon
    int getPartial(double& mjd_start, double& mjd_stop);  // (global) start and stop times for partial phase
    int getTotal(double& mjd_start, double& mjd_stop);   // (global) start and stop times for totality/annularity
    void getEclYearInfo(char* wbuf);  // list of eclipses of the year
    int getEclYearInfo(int k, int& yr, int& month, int& day,
                       int& hour, int& min, double& sec, double& tzone, double& magn);
    int getEclTxt(int j, char* jtxt);   // get text for j-th eclipse
    void putEclSelect(int es);  // select particular eclipse for details
    void nextEcl();  // select the next eclipse for details
    void previousEcl();  // select the previous eclipse for details
    double getLastMJD() const;  // get the MJD last used in calculations
    void getMaxPos(double& lat, double& lng); // get position of maximum eclipse
    int eclPltCentral(bool firstc, double& lat, double& lng);  // calc central eclipse line
    int GNSBound(bool firstc, bool north, double& lat, double& lng); // northern or southern boundary
    int GRSBound(bool firstc, double& lat1, double& lng1, double& lat2, double& lng2);
    // Rise / Set Boundary
    int centralBound(bool firstc, double& lat1, double& lng1, double& lat2, double& lng2);
    void getShadowCone(double mjd, bool umbra, int numpts, double* lat, double* lng);
    void setPenumbraAngle(double pa, int mode);

private:

    void esinit();                                                                  // initialize EclSolar
    static double atan23(double y, double x);                                       // atan without singularity for x,y=0
    void DefTime();                                                                 // Get System Time and Date
    void calcMaxPos(double& lat, double& lng);                                      // get position of maximum eclipse
    static void GetMonth(int mm, char* mchr);
    static double phmjd(double yearf, double phase, double tdut,
                        int& eph, double& ejd, double& emag);
    void ckphase(double minmjd, double maxmjd, double yr,
                 double deltdut, int& mp, PMJD p, double phase);
    static void dtmstr(double jdmoon, char* dts);
    void moonph();                                                                  // calculate phases of the Moon
    void eclStart();                                                                // initialize detailed calcs for selected eclipse
    static double getlocmag(double jd, double ep2, double phi, double lamda,
                            double height, const Vec3& rs, const Vec3& rm, int& totflg);
    static int iscrs(double vrc0, double vrc1, double dpn,
                     double& vrx0, double& vrx1, double& vrx20, double& vrx21);
    void InitBound();                                                               // initialize boundary calcs
    void InRSBound();                                                               // initialize Sunrise/Sunset boundaries
    static double DegFDms(double h);
    int localStart(int j, double* spt, double* ept, int* spp,
                   int p, char* otxt);
    static double navCourse(double lat1, double lng1, double lat2, double lng2);    // navigation course from p1 to p2
    static void navNewPos(double d, double an, double lat1, double lng1, double& lat2, double& lng2);
    static double sunObscure(double l1, double l2, double m);                       // get the Obscuration of the Sun

private:

    // data fields

    bool eb_start_called    = false;    // true if eclStart() has already been called for eclipse
    bool eb_moonph_called   = false;    // true if moonph has already been called for year
    bool eb_lunecl          = false;    // true if lunar eclipses are to be included
    bool eb_lunactive       = false;    // true if current eclipse is a lunar eclipse
    bool eb_local_called    = false;    // true if local circumstances calculated

    int eb_day              = 0;        // date
    int eb_month            = 0;
    int eb_year             = 0;
    int eb_hour             = 0;
    int eb_minute           = 0;
    int eb_second           = 0;
    double eb_time          = 0.0;
    double eb_tzone         = 0.0;      // timezone in hours
    double eb_del_tdut      = 0.0;      // TDT - UT in sec
    int eb_del_auto         = 0;        // 1 = automatic del_tdut,  0 = manual
    double eb_geolat        = 0.0;      // geographic coordinates (angles in degrees)
    double eb_geolong       = 0.0;
    double eb_geoheight     = 0.0;      // in meters
    int eb_lstcall          = 0;        // 1 = last call moonph; 2 = caldisp; 0 = no call
    int eb_locecl           = 0;        // 1 = local eclipse call; 0 = normal (global) call

    bool eb_finished        = false;    // true if the loop run on consecutive calls is finished
    bool eb_finished2       = false;
    int eb_numecl           = 0;        // number of eclipses of the year;
    int eb_eclselect        = 0;        // eclipse selected for detailed calculation
    int eb_lastyear         = 0;        // last year for which moon phases were calculated
    double eb_lasttz        = 0.0;      // last used timezone
    double eb_lastdlt       = 0.0;      // last delta-t used
    double eb_cstep         = 0.0;      // step width in minutes used for central eclipse output

    double eb_eclmjd [GBL_ECLBUF]       = { 0.0 };   // the MJD's of the middle of the eclipses
    double eb_magnitude [GBL_ECLBUF]    = { 0.0 };   // magnitude of respective eclipse
    int eb_phase [GBL_ECLBUF]           = { 0 };     // phase of the eclipse. 0 if no eclipse,

    // 1 partial Sun, 2 non-central annular, 3 non-central total,
    // 4 annular, 5 total, 6 annual/total  Sun
    // -1 partial penumbral Moon, -2 penumbral Moon,
    // -3 partial Moon, -4 total Moon.
    int eb_nphase           = 0;        // number of phases for eclipse details

    int eb_spp[4]           = { 0 };    // kind of eclipse phase i
    double eb_spt[4]        = { 0.0 };  // start time in MJD for phase i
    double eb_ept[4]        = { 0.0 };  // end time in MJD for phase i
    int eb_lccnt            = 0;        // = 0 not visible, 1,2 = first rise/set; 3,4 second r/s

    double eb_lcb1 = 0.0, eb_lcb2 = 0.0, eb_lce1 = 0.0, eb_lce2 = 0.0;  // rise and set times (up to 2 possible)

    double eb_jdmaxps       = 0.0;      // MJD of maximum phase
    double eb_maxps         = 0.0;      // value of maximum phase
    double eb_maxelv        = 0.0;      // elevation at maximum phase
    double eb_ltotb         = 0.0;      // begin of totality/annularity at local position
    double eb_ltote         = 0.0;      // end of totality/annularity at local position
    int eb_cphs             = 0;        // phase of the central eclipse for center line plotting
    double eb_clat          = 0.0;      // current latitude of center line (in decimal degrees)
    double eb_clng          = 0.0;      // current longitude of center line (in decimal degrees)
    double eb_cmxlat        = 0.0;      // latitude of maximum eclipse (in decimal degrees)
    double eb_cmxlng        = 0.0;      // longitude of maximum eclipse (in decimal degrees)
    double eb_jdstart       = 0.0;      // (global) start jd of eclipse
    double eb_jdstop        = 0.0;      // (global) end jd of eclipse
    double eb_lastjd        = 0.0;      // last used MJD for eclipse calcs
    double eb_dpb           = 0.0;      // Base value for diameter of penumbra
    double eb_dpd           = 0.0;      // delta value for diameter of penumbra
    double eb_penangle      = 0.0;      // factor for multiplying the penumbra angle (1.0 for normal borders)
    int eb_penamode         = 0;        // mode for using eb_penangle

    Vec3 eb_ubm;  // Penumbra (or Umbra or Moon) base vector
    Vec3 eb_ube;  // Shadow base vector for upper boundary
    Vec3 eb_udm;  // Penumbra base delta vector
    Vec3 eb_ude;  // Shadow delta vector for upper boundary
    Vec3 eb_lbe;  // Shadod base vector for lower boundary
    Vec3 eb_lde;  // Shadow delta vector for lower boundary
};

} // namespace Marble
