//Static methods
//Tangible Process Only End


    ////////////////////////////////// Implementation /////////////////////////////

    public static CAABinaryStarDetails Calculate(double t, double P, double T, double e, double a, double i, double omega, double w)
    {
        double n = 360 / P;
        double M = CT.M360(n * (t - T));
        double E = CAAKepler.Calculate(M, e);

        E     = CT.D2R(E);
        i     = CT.D2R(i);
        w     = CT.D2R(w);
        omega = CT.D2R(omega);

        CAABinaryStarDetails details = new CAABinaryStarDetails();

        details.r = a * (1 - e * Math.Cos(E));

        double v = Math.Atan(Math.Sqrt((1 + e) / (1 - e)) * Math.Tan(E / 2)) * 2;

        details.Theta = Math.Atan2(Math.Sin(v + w) * Math.Cos(i), Math.Cos(v + w)) + omega;
        details.Theta = CT.M360(CT.R2D(details.Theta));

        double sinvw = Math.Sin(v + w);
        double cosvw = Math.Cos(v + w);
        double cosi  = Math.Cos(i);

        details.Rho = details.r * Math.Sqrt((sinvw * sinvw * cosi * cosi) + (cosvw * cosvw));

        return(details);
    }
//Static methods
//Tangible Process Only End


    ////////////////////////////////// Implementation /////////////////////////////

    public static CAABinaryStarDetails Calculate(double t, double P, double T, double e, double a, double i, double omega, double w)
    {
        double n = 360 / P;
        double M = CAACoordinateTransformation.MapTo0To360Range(n * (t - T));
        double E = CAAKepler.Calculate(M, e);

        E     = CAACoordinateTransformation.DegreesToRadians(E);
        i     = CAACoordinateTransformation.DegreesToRadians(i);
        w     = CAACoordinateTransformation.DegreesToRadians(w);
        omega = CAACoordinateTransformation.DegreesToRadians(omega);

        CAABinaryStarDetails details = new CAABinaryStarDetails();

        details.r = a * (1 - e * Math.Cos(E));

        double v = Math.Atan(Math.Sqrt((1 + e) / (1 - e)) * Math.Tan(E / 2)) * 2;

        details.Theta = Math.Atan2(Math.Sin(v + w) * Math.Cos(i), Math.Cos(v + w)) + omega;
        details.Theta = CAACoordinateTransformation.MapTo0To360Range(CAACoordinateTransformation.RadiansToDegrees(details.Theta));

        double sinvw = Math.Sin(v + w);
        double cosvw = Math.Cos(v + w);
        double cosi  = Math.Cos(i);

        details.Rho = details.r * Math.Sqrt((sinvw * sinvw * cosi * cosi) + (cosvw * cosvw));

        return(details);
    }
    public static Vector3d CalculateRectangular(double JD, CAAEllipticalObjectElements elements, out double meanAnomoly)
    {
        Vector3d position;
        double   JD0 = JD;

        double omega = CAACoordinateTransformation.DegreesToRadians(elements.omega);
        double w     = CAACoordinateTransformation.DegreesToRadians(elements.w);
        double i     = CAACoordinateTransformation.DegreesToRadians(elements.i);

        double sinEpsilon = 0;
        double cosEpsilon = 1;
        double sinOmega   = Math.Sin(omega);
        double cosOmega   = Math.Cos(omega);
        double cosi       = Math.Cos(i);
        double sini       = Math.Sin(i);

        double F = cosOmega;
        double G = sinOmega * cosEpsilon;
        double H = sinOmega * sinEpsilon;
        double P = -sinOmega * cosi;
        double Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
        double R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
        double a = Math.Sqrt(F * F + P * P);
        double b = Math.Sqrt(G * G + Q * Q);
        double c = Math.Sqrt(H * H + R * R);
        double A = Math.Atan2(F, P);
        double B = Math.Atan2(G, Q);
        double C = Math.Atan2(H, R);
        //double n = CAAElliptical.MeanMotionFromSemiMajorAxis(elements.a);
        // double n = ;


        double M = elements.n * (JD0 - elements.T);

        meanAnomoly = M;
        double E = CAAKepler.Calculate(M, elements.e);

        E = CAACoordinateTransformation.DegreesToRadians(E);
        double v = 2 * Math.Atan(Math.Sqrt((1 + elements.e) / (1 - elements.e)) * Math.Tan(E / 2));
        double r = elements.a * (1 - elements.e * Math.Cos(E));
        double x = r * a * Math.Sin(A + w + v);
        double y = r * b * Math.Sin(B + w + v);
        double z = r * c * Math.Sin(C + w + v);


        position.X = x;
        position.Y = z;
        position.Z = y;

        return(position);
    }
    public static Vector3d CalculateRectangularJD(double JD, EOE elements)
    {
        double JD0 = JD;

        double omega = CT.D2R(elements.omega);
        double w     = CT.D2R(elements.w);
        double i     = CT.D2R(elements.i);

        double sinEpsilon = 0;
        double cosEpsilon = 1;
        double sinOmega   = Math.Sin(omega);
        double cosOmega   = Math.Cos(omega);
        double cosi       = Math.Cos(i);
        double sini       = Math.Sin(i);

        double F = cosOmega;
        double G = sinOmega * cosEpsilon;
        double H = sinOmega * sinEpsilon;
        double P = -sinOmega * cosi;
        double Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
        double R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
        double a = Math.Sqrt(F * F + P * P);
        double b = Math.Sqrt(G * G + Q * Q);
        double c = Math.Sqrt(H * H + R * R);
        double A = Math.Atan2(F, P);
        double B = Math.Atan2(G, Q);
        double C = Math.Atan2(H, R);
        //double n = CAAElliptical.MeanMotionFromSemiMajorAxis(elements.a);
        // double n = ;


        double M = elements.n * (JD0 - elements.T);

        elements.meanAnnomolyOut = M;
        double E = CAAKepler.Calculate(M, elements.e);

        E = CT.D2R(E);
        double v = 2 * Math.Atan(Math.Sqrt((1 + elements.e) / (1 - elements.e)) * Math.Tan(E / 2));
        double r = elements.a * (1 - elements.e * Math.Cos(E));
        double x = r * a * Math.Sin(A + w + v);
        double y = r * b * Math.Sin(B + w + v);
        double z = r * c * Math.Sin(C + w + v);

        //elements.meanAnnomolyOut contains the mean annomoly
        return(Vector3d.Create(x, y, z));
    }
    public static Vector3d CalculateRectangular(EOE elements, double meanAnomoly)
    {
//      double JD0 = JD;

        double omega = CT.D2R(elements.omega);
        double w     = CT.D2R(elements.w);
        double i     = CT.D2R(elements.i);

        double sinEpsilon = 0;
        double cosEpsilon = 1;
        double sinOmega   = Math.Sin(omega);
        double cosOmega   = Math.Cos(omega);
        double cosi       = Math.Cos(i);
        double sini       = Math.Sin(i);

        double F = cosOmega;
        double G = sinOmega * cosEpsilon;
        double H = sinOmega * sinEpsilon;
        double P = -sinOmega * cosi;
        double Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
        double R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
        double a = Math.Sqrt(F * F + P * P);
        double b = Math.Sqrt(G * G + Q * Q);
        double c = Math.Sqrt(H * H + R * R);
        double A = Math.Atan2(F, P);
        double B = Math.Atan2(G, Q);
        double C = Math.Atan2(H, R);
        double n = elements.n;


        double M = meanAnomoly;
        double E = CAAKepler.Calculate(M, elements.e);

        E = CT.D2R(E);
        double v = 2 * Math.Atan(Math.Sqrt((1 + elements.e) / (1 - elements.e)) * Math.Tan(E / 2));
        double r = elements.a * (1 - elements.e * Math.Cos(E));
        double x = r * a * Math.Sin(A + w + v);
        double y = r * b * Math.Sin(B + w + v);
        double z = r * c * Math.Sin(C + w + v);

        return(Vector3d.Create(x, y, z));
    }
    public static EOD CalculateElements(double JD, EOE elements)
    {
        double Epsilon = CAANutation.MeanObliquityOfEcliptic(elements.JDEquinox);

        double JD0 = JD;

        //What will be the return value
        EOD details = new EOD();

        Epsilon = CT.D2R(Epsilon);
        double omega = CT.D2R(elements.omega);
        double w     = CT.D2R(elements.w);
        double i     = CT.D2R(elements.i);

        double sinEpsilon = Math.Sin(Epsilon);
        double cosEpsilon = Math.Cos(Epsilon);
        double sinOmega   = Math.Sin(omega);
        double cosOmega   = Math.Cos(omega);
        double cosi       = Math.Cos(i);
        double sini       = Math.Sin(i);

        double F = cosOmega;
        double G = sinOmega * cosEpsilon;
        double H = sinOmega * sinEpsilon;
        double P = -sinOmega * cosi;
        double Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
        double R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
        double a = Math.Sqrt(F * F + P * P);
        double b = Math.Sqrt(G * G + Q * Q);
        double c = Math.Sqrt(H * H + R * R);
        double A = Math.Atan2(F, P);
        double B = Math.Atan2(G, Q);
        double C = Math.Atan2(H, R);
        double n = ELL.MeanMotionFromSemiMajorAxis(elements.a);

        C3D SunCoord = CAASun.EquatorialRectangularCoordinatesAnyEquinox(JD, elements.JDEquinox);

        for (int j = 0; j < 2; j++)
        {
            double M = n * (JD0 - elements.T);
            double E = CAAKepler.Calculate(M, elements.e);
            E = CT.D2R(E);
            double v = 2 * Math.Atan(Math.Sqrt((1 + elements.e) / (1 - elements.e)) * Math.Tan(E / 2));
            double r = elements.a * (1 - elements.e * Math.Cos(E));
            double x = r * a * Math.Sin(A + w + v);
            double y = r * b * Math.Sin(B + w + v);
            double z = r * c * Math.Sin(C + w + v);

            if (j == 0)
            {
                details.HeliocentricRectangularEquatorial.X = x;
                details.HeliocentricRectangularEquatorial.Y = y;
                details.HeliocentricRectangularEquatorial.Z = z;

                //Calculate the heliocentric ecliptic coordinates also
                double u    = omega + v;
                double cosu = Math.Cos(u);
                double sinu = Math.Sin(u);

                details.HeliocentricRectangularEcliptical.X = r * (cosOmega * cosu - sinOmega * sinu * cosi);
                details.HeliocentricRectangularEcliptical.Y = r * (sinOmega * cosu + cosOmega * sinu * cosi);
                details.HeliocentricRectangularEcliptical.Z = r * sini * sinu;

                details.HeliocentricEclipticLongitude = Math.Atan2(y, x);
                details.HeliocentricEclipticLongitude = CT.M24(CT.R2D(details.HeliocentricEclipticLongitude) / 15);
                details.HeliocentricEclipticLatitude  = Math.Asin(z / r);
                details.HeliocentricEclipticLatitude  = CT.R2D(details.HeliocentricEclipticLatitude);
            }

            double psi   = SunCoord.X + x;
            double nu    = SunCoord.Y + y;
            double sigma = SunCoord.Z + z;

            double Alpha = Math.Atan2(nu, psi);
            Alpha = CT.R2D(Alpha);
            double Delta = Math.Atan2(sigma, Math.Sqrt(psi * psi + nu * nu));
            Delta = CT.R2D(Delta);
            double Distance = Math.Sqrt(psi * psi + nu * nu + sigma * sigma);

            if (j == 0)
            {
                details.TrueGeocentricRA          = CT.M24(Alpha / 15);
                details.TrueGeocentricDeclination = Delta;
                details.TrueGeocentricDistance    = Distance;
                details.TrueGeocentricLightTime   = DistanceToLightTime(Distance);
            }
            else
            {
                details.AstrometricGeocenticRA           = CT.M24(Alpha / 15);
                details.AstrometricGeocentricDeclination = Delta;
                details.AstrometricGeocentricDistance    = Distance;
                details.AstrometricGeocentricLightTime   = DistanceToLightTime(Distance);

                double RES = Math.Sqrt(SunCoord.X * SunCoord.X + SunCoord.Y * SunCoord.Y + SunCoord.Z * SunCoord.Z);

                details.Elongation = Math.Acos((RES * RES + Distance * Distance - r * r) / (2 * RES * Distance));
                details.Elongation = CT.R2D(details.Elongation);

                details.PhaseAngle = Math.Acos((r * r + Distance * Distance - RES * RES) / (2 * r * Distance));
                details.PhaseAngle = CT.R2D(details.PhaseAngle);
            }

            if (j == 0) //Prepare for the next loop around
            {
                JD0 = JD - details.TrueGeocentricLightTime;
            }
        }

        return(details);
    }