/*
 *     PreviSat, Satellite tracking software
 *     Copyright (C) 2005-2025  Astropedia web: http://previsat.free.fr  -  mailto: previsat.app@gmail.com
 *
 *     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 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * _______________________________________________________________________________________________________
 *
 * Nom du fichier
 * >    phasage.cpp
 *
 * Localisation
 * >    librairies.corps.satellite
 *
 * Auteur
 * >    Astropedia
 *
 * Date de creation
 * >    6 octobre 2016
 *
 * Date de revision
 * >    14 octobre 2025
 *
 */

#include <QtMath>
#include "elementsosculateurs.h"
#include "librairies/corps/satellite/satelliteconst.h"
#include "librairies/corps/terreconst.h"
#include "phasage.h"


/**********
 * PUBLIC *
 **********/

/*
 * Constructeurs
 */
/*
 * Constructeur par defaut
 */
Phasage::Phasage()
{
    /* Declarations des variables locales */

    /* Initialisations */

    /* Corps du constructeur */
    _nbOrb = SATELLITE::ELEMENT_PHASAGE_INDEFINI;
    _ct0 = SATELLITE::ELEMENT_PHASAGE_INDEFINI;
    _dt0 = SATELLITE::ELEMENT_PHASAGE_INDEFINI;
    _nu0 = SATELLITE::ELEMENT_PHASAGE_INDEFINI;

    /* Retour */
    return;
}


/*
 * Methodes publiques
 */
/*
 * Calcul des elements de phasage
 */
void Phasage::Calcul(const ElementsOsculateurs &elements,
                     const double n0)
{
    /* Declarations des variables locales */

    /* Initialisations */
    bool atrouve = false;
    double nt0 = 0.;
    double precessionNoeud = 0.;
    double v = 0.;

    /* Corps de la methode */
    if (fabs(elements.demiGrandAxe()) > MATHS::EPSDBL100) {

        const double cosincl = cos(elements.inclinaison());
        const double cosincl2 = cosincl * cosincl;
        const double rsa = TERRE::RAYON_TERRESTRE / elements.demiGrandAxe();
        const double rsa2 = rsa * rsa;
        const double moyenMouvement = sqrt(TERRE::GE / (elements.demiGrandAxe() * elements.demiGrandAxe() * elements.demiGrandAxe()));
        const double aper = DATE::NB_MIN_PAR_JOUR / n0;
        const double gamma = 1. - elements.excentricite() * elements.excentricite();
        const double gamma2 = gamma * gamma;

        precessionNoeud = MATHS::RAD2DEG * DATE::NB_SEC_PAR_JOUR * (-1.5 * TERRE::J2 * rsa2 * cosincl * moyenMouvement / gamma2);
        const double precessionPerigee = MATHS::RAD2DEG * DATE::NB_SEC_PAR_JOUR * 0.75 * TERRE::J2 * rsa2 * (5. * cosincl2 - 1.) * moyenMouvement / gamma2;
        const double dper = aper / (1. + precessionPerigee * MATHS::DEG2RAD * DATE::NB_JOUR_PAR_SEC / moyenMouvement);
        const double nd = n0 * MATHS::T360 + precessionPerigee;
        const double k = nd / (TERRE::OMEGA0 * MATHS::T360 - precessionNoeud);
        _nu0 = static_cast<int> (qRound(floor(10. * k) * 0.1));
        v = n0 * aper / dper;

        int iter;
        const double pas = 1.e-6;
        double spec = 0.01;

        while (!atrouve && (spec <= 0.05)) {

            iter = 1;
            while (!atrouve && (iter <= 38)) {

                nt0 = iter * v;
                if (fabs(nt0 - qRound(nt0)) < spec) {
                    _ct0 = iter;
                    atrouve = true;
                }

                iter++;
            }

            spec += pas;
        }
    }

    if (atrouve) {

        if ((precessionNoeud < 0.975) || (precessionNoeud > 0.995)) {
            _dt0 = static_cast<int> (qRound(nt0 - _nu0 * _ct0));
        } else {
            _dt0 = static_cast<int> (qRound((v - _nu0) * _ct0));
        }

        _nbOrb = static_cast<int> (qRound(nt0));

    } else {
        _nbOrb = SATELLITE::ELEMENT_PHASAGE_INDEFINI;
        _ct0 = SATELLITE::ELEMENT_PHASAGE_INDEFINI;
        _dt0 = SATELLITE::ELEMENT_PHASAGE_INDEFINI;
        _nu0 = SATELLITE::ELEMENT_PHASAGE_INDEFINI;
    }

    /* Retour */
    return;
}


/*
 * Accesseurs
 */
int Phasage::nu0() const
{
    return _nu0;
}

int Phasage::dt0() const
{
    return _dt0;
}

int Phasage::ct0() const
{
    return _ct0;
}

int Phasage::nbOrb() const
{
    return _nbOrb;
}


/*************
 * PROTECTED *
 *************/

/*
 * Methodes protegees
 */


/***********
 * PRIVATE *
 ***********/

/*
 * Methodes privees
 */

