#ifndef ORIBTMODELOPERATOR_H_
#define ORIBTMODELOPERATOR_H_
#include <QFile>
#include <QDomDocument>
#include <QVector3D>
#include <QDebug>
#include <QList>
#include <Eigen/Core>
#include <Eigen/Dense>
#include "BaseConstVariable.h"

QList<SatellitePos> loadNodesFromXml(const QString& filename);
void  saveNodesToXml(const QString& filename, const QList<SatellitePos>& inposes);



class OrbitModelAbstract {
public:
    OrbitModelAbstract();
    ~OrbitModelAbstract();
public:
   virtual SatellitePos predictNode(double time) ;
};



class OrbitElements  {
public:
    double semiMajorAxis; // 圉酗粣 (a)
    double eccentricity;  // 燭陑薹 (e)
    double inclination;   // ъ訇褒 (i)
    double longitudeOfAscendingNode; // 汔蝠萸喪冪 (次)
    double argumentOfPeriapsis;      // 輪華萸盟褒 (肋)
    double trueAnomaly;              // 淩輪萸褒 (糸)

    OrbitElements();
};

class OrbitEstimator :public OrbitModelAbstract {
public:
    OrbitEstimator();
    void estimateOrbit(const SatellitePos& node);
    void saveToXml(const QString& filename) const;
    bool loadFromXml(const QString& filename);
    SatellitePos calculateNode(double time) const;
    virtual SatellitePos predictNode(double time) override;
private:
    OrbitElements elements;
    OrbitElements estimateKeplerianElements(const SatellitePos& node);
    SatellitePos calculateKeplerianNode(const OrbitElements& elements, double time) const;
    double solveKeplerEquation(double M, double e) const;
};

class PolynomialOrbitModel :public OrbitModelAbstract {
public:
    void fitPolynomial(const QList<SatellitePos>& nodes, int degree=3);
    SatellitePos predictPosition(double time);
    void saveToXml(const QString& filename) const;
    bool loadFromXml(const QString& filename);
    virtual SatellitePos predictNode(double time) override;
private:
    Eigen::VectorXd coefficientsX;
    Eigen::VectorXd coefficientsY;
    Eigen::VectorXd coefficientsZ;
    Eigen::VectorXd coefficientsVx;
    Eigen::VectorXd coefficientsVy;
    Eigen::VectorXd coefficientsVz;

    Eigen::VectorXd leastSquaresFit(const QList<double>& x, const QList<double>& y, int degree);
    void saveCoefficientsToXml(QDomElement& parent, const Eigen::VectorXd& coefficients, const QString& tagName) const;
    bool loadCoefficientsFromXml(const QDomElement& parent, Eigen::VectorXd& coefficients, const QString& tagName);
};




class TwoLineElements :public OrbitModelAbstract {
public:
    TwoLineElements();
    bool loadFromTleFile(const QString& filename);
    SatellitePos calculateNode(double time) const;
    virtual SatellitePos predictNode(double time) override;
private:
    std::string line1;
    std::string line2;

    void parseTleLines();
    double meanMotion() const;
    double semiMajorAxis() const;
    double eccentricity() const;
    double inclination() const;
    double longitudeOfAscendingNode() const;
    double argumentOfPeriapsis() const;
    double meanAnomaly() const;
    double revolutionNumberAtEpoch() const;
    double epochTime() const;
    double solveKeplerEquation(double M, double e) const;
    SatellitePos calculateKeplerianNode(double time) const;
};

#endif