/// <summary>
    /// Calculates the horizontal coordinates of the moon
    /// Source: https://github.com/mourner/suncalc/blob/master/suncalc.js
    /// </summary>
    /// <returns>The horizontal coordinatesof the moon</returns>
    /// <param name="_longitude">User longitude in degree</param>
    /// <param name="_latitude">User latitude in degree</param>
    public static HorizontalCoordinates CalculateHorizontalCoordinatesMoon(DateTime time, double _longitude, double _latitude)
    {
        //Convert the latitude to radians
        _latitude *= Mathf.Deg2Rad;

        double   lw      = Mathf.Deg2Rad * _longitude * -1;
        DateTime epoch   = new DateTime(2000, 1, 1, 12, 0, 0);
        TimeSpan j2000TS = time - epoch;
        double   j2000   = j2000TS.TotalDays;

        double L = Mathf.Deg2Rad * (218.316f + 13.176396f * j2000), // ecliptic longitude
               M = Mathf.Deg2Rad * (134.963f + 13.064993f * j2000), // mean anomaly
               F = Mathf.Deg2Rad * (93.272f + 13.229350f * j2000),  // mean distance

               l  = L + Mathf.Deg2Rad * 6.289f * Math.Sin(M),       // longitude
               b  = Mathf.Deg2Rad * 5.128f * Math.Sin(F),           // latitude
               dt = 385001f - 20905f * Math.Cos(M);                 // distance to the moon in km

        //Calculate the Right ascension and declinaison of the moon
        double e   = Mathf.Deg2Rad * 23.4397f;
        double ra  = Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l));
        double dec = Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));

        //Sidereal time
        double HA = (Mathf.Deg2Rad * (280.16f + 360.9856235f * j2000) - lw) - ra;

        //Compute Altitude and Azimuth (RAD)
        double altitude = Math.Asin(Math.Sin(dec) * Math.Sin(_latitude) + Math.Cos(dec) * Math.Cos(_latitude) * Math.Cos(HA));
        double azimuth  = Math.Acos((Math.Sin(dec) - Math.Sin(altitude) * Math.Sin(_latitude)) / (Math.Cos(altitude) * Math.Cos(_latitude)));

        //Convert both to degree
        altitude *= Mathf.Rad2Deg;
        azimuth  *= Mathf.Rad2Deg;

        if (Math.Sin(HA) > 0f)
        {
            azimuth = 360f - azimuth;
        }

        HorizontalCoordinates coordinates = new HorizontalCoordinates()
        {
            azimuth  = azimuth,
            altitude = altitude,
            distance = dt
        };

        return(coordinates);
    }
    /// <summary>
    /// Calculate the Horizontal Coordinates from a star's Celestial Coordinates.
    /// Take into account user time + date + location
    /// </summary>
    /// <returns>The altitude and azimuth (in degree) of where the star is located</returns>
    /// <param name="_longitude">User longitude in degree</param>
    /// <param name="_latitude">User latitude in degree</param>
    /// <param name="_ra">Right Ascension (in degree)</param>
    /// <param name="_dec">Declinaison (in degree)</param>
    public static HorizontalCoordinates CalculateHorizontalCoordinatesStar(DateTime time, double _longitude, double _latitude, float _ra, float _dec)
    {
        //Convert the latitude to radians
        _latitude *= Mathf.Deg2Rad;

        //The right ascension is already in degree in database
        //the declinaison not so convert it to degree as well
        double ra  = _ra;
        double dec = _dec;

        //1. Days elapsed since J2000 (1st january 2000 at 12:00)
        DateTime epoch   = new DateTime(2000, 1, 1, 12, 0, 0);
        TimeSpan j2000TS = time - epoch;
        double   j2000   = j2000TS.TotalDays;

        //2. UT to Decimals
        //Note: time values has to be sent from telescope
        double curTimeUTC = time.TimeOfDay.TotalHours;

        //3. Get Long East = + / West = -
        double longitude = _longitude;
        double latitude  = _latitude;

        //4. Local Sidereal Time (LST)
        //The sidereal time is measured by the rotation of the Earth, with respect to the stars (rather than relative to the Sun).
        //Local sidereal time is the right ascension (RA, an equatorial coordinate) of a star on the observers meridian.
        //In other words, he sidereal time is a direct indication of whether a celestial object of known right ascension is observable at that instant.
        double LST = 100.46f + 0.985647f * j2000 + longitude + curTimeUTC * 15.0f;

        //4a. As RA and DEC are in degree, we convert this one in degrees as well
        int modulo = (int)Math.Floor(LST) / 360;

        LST = (LST - (360 * modulo)) / 15.0f;

        //5. Local Hour Angle
        //If negative, add 360
        double HA = LST - ra;

        if (HA < 0.0f)
        {
            HA += 360.0f;
        }
        HA *= Math.PI / 12.0f;

        //7. Calculate Altitute
        double altitude    = Math.Asin(Math.Sin(dec) * Math.Sin(latitude) + Math.Cos(dec) * Math.Cos(latitude) * Math.Cos(HA));
        double altitudeDeg = altitude * Mathf.Rad2Deg;

        //8. Calculate Azimuth
        double azimuth    = Math.Acos((Math.Sin(dec) - Math.Sin(altitude) * Math.Sin(latitude)) / (Math.Cos(altitude) * Math.Cos(latitude)));
        double azimuthDeg = azimuth * Mathf.Rad2Deg;


        if (Math.Sin(HA) > 0.0f)
        {
            azimuthDeg = 360.0f - azimuthDeg;
        }

        HorizontalCoordinates coordinates = new HorizontalCoordinates()
        {
            azimuth  = azimuthDeg,
            altitude = altitudeDeg,
            distance = double.PositiveInfinity
        };

        return(coordinates);
    }
    /// <summary>
    /// Calculate the altitude and azimuth of all planets of our solar system / including sun.
    /// Source: http://www.abecedarical.com/javascript/script_planet_orbits.html
    /// </summary>
    /// <returns>The altitude azimuth (in degree) as well as the distance of where the star is located</returns>
    /// <param name="_longitude">User longitude in degree</param>
    /// <param name="_latitude">User latitude in degree</param>
    /// <param name="_name">The planet's name</param>
    public static HorizontalCoordinates CalculateHorizontalCoordinatesPlanets(DateTime time, double _longitude, double _latitude, string _name)
    {
        //Convert the latitude to radians
        _latitude *= Mathf.Deg2Rad;

        //1. Days elapsed since J2000 (1st january 2000 at 12:00)
        DateTime epoch   = new DateTime(2000, 1, 1, 12, 0, 0);
        TimeSpan j2000TS = time - epoch;
        double   j2000   = j2000TS.TotalDays;

        //2. Centuries since J2000
        double cJ2000 = j2000 / 36525.0f;

        //3. Depending on the planet, sets its parameters that we use later to calculate Alt + Az
        double inclination  = 0f;   //angle between the plane of the ecliptic (the plane of Earth's orbit about the Sun) and the plane of the planets orbit
        double longNode     = 0f;   //longitude of ascending node (degrees), the position in the orbit where the elliptical path of the planet passes through the plane of the ecliptic, from below the plane to above the plane
        double longPeri     = 0f;   //longitude of perihelion (degrees), the position in the orbit where the planet is closest to the Sun
        double meanDist     = 0f;   //mean distance (AU), the value of the semi-major axis of the orbit (AU - Astronomical Unit - average Sun to Earth distance)
        double eccentricity = 0f;   //eccentricity of the ellipse which describes the orbit (dimensionless)
        double meanLong     = 0f;   //mean longitude (degrees), the position of the planet in the orbit

        //In all cases save these variable for the Earth as well...which uses the same equation as the Sun!
        double inclinationE   = (0.00005f - 46.94f * cJ2000 / 3600.0f) * Mathf.Deg2Rad;;
        double longNodeE      = (-11.26064f - 18228.25f * cJ2000 / 3600.0f) * Mathf.Deg2Rad;;
        double longPeriE      = (102.94719f + 1198.28f * cJ2000 / 3600.0f) * Mathf.Deg2Rad;
        double meanDistE      = 1.00000011f - 0.00000005f * cJ2000;
        double eccenctricityE = 0.01671022f - 0.00003804f * cJ2000;
        double meanLongE      = Mod2Pi((100.46435f + 129597740.63f * cJ2000 / 3600.0f) * Mathf.Deg2Rad);

        switch (_name)
        {
        case "Sun":
            inclination  = inclinationE;
            longNode     = longNodeE;
            longPeri     = longPeriE;
            meanDist     = meanDistE;
            eccentricity = eccenctricityE;
            meanLong     = meanLongE;
            break;

        case "Mercury":
            inclination  = (7.00487f - 23.51f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longNode     = (48.33167f - 446.30f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (77.45645f + 573.57f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 0.38709893f + 0.00000066f * cJ2000;
            eccentricity = 0.20563069f + 0.00002527f * cJ2000;
            meanLong     = Mod2Pi((252.25084f + 538101628.29f * cJ2000 / 3600.0f) * Mathf.Deg2Rad);
            break;

        case "Venus":
            inclination  = (3.39471f - 2.86f * cJ2000 / 3600.0f) * Mathf.Deg2Rad;
            longNode     = (76.68069f - 996.89f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (131.53298f - 108.80f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 0.72333199f + 0.00000092f * cJ2000;
            eccentricity = 0.00677323f - 0.00004938f * cJ2000;
            meanLong     = Mod2Pi((181.97973f + 210664136.06f * cJ2000 / 3600f) * Mathf.Deg2Rad);
            break;

        case "Mars":
            inclination  = (1.85061f - 25.47f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longNode     = (49.57854f - 1020.19f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (336.04084f + 1560.78f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 1.52366231f - 0.00007221f * cJ2000;
            eccentricity = 0.09341233f + 0.00011902f * cJ2000;
            meanLong     = Mod2Pi((355.45332f + 68905103.78f * cJ2000 / 3600f) * Mathf.Deg2Rad);
            break;

        case "Jupiter":
            inclination  = (1.30530f - 4.15f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longNode     = (100.55615f + 1217.17f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (14.75385f + 839.93f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 5.20336301f + 0.00060737f * cJ2000;
            eccentricity = 0.04839266f - 0.00012880f * cJ2000;
            meanLong     = Mod2Pi((34.40438f + 10925078.35f * cJ2000 / 3600f) * Mathf.Deg2Rad);
            break;

        case "Saturn":
            inclination  = (2.48446f + 6.11f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longNode     = (113.71504f - 1591.05f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (92.43194f - 1948.89f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 9.53707032f - 0.00301530f * cJ2000;
            eccentricity = 0.05415060f - 0.00036762f * cJ2000;
            meanLong     = Mod2Pi((49.94432f + 4401052.95f * cJ2000 / 3600f) * Mathf.Deg2Rad);
            break;

        case "Uranus":
            inclination  = (0.76986f - 2.09f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longNode     = (74.22988f - 1681.40f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (170.96424f + 1312.56f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 19.19126393f + 0.00152025f * cJ2000;
            eccentricity = 0.04716771f - 0.00019150f * cJ2000;
            meanLong     = Mod2Pi((313.23218f + 1542547.79f * cJ2000 / 3600f) * Mathf.Deg2Rad);
            break;

        case "Neptune":
            inclination  = (1.76917f - 3.64f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longNode     = (131.72169f - 151.25f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (44.97135f - 844.43f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 30.06896348f - 0.00125196f * cJ2000;
            eccentricity = 0.00858587f + 0.00002510f * cJ2000;
            meanLong     = Mod2Pi((304.88003f + 786449.21f * cJ2000 / 3600f) * Mathf.Deg2Rad);
            break;

        case "Pluto":
            inclination  = (17.14175f + 11.07f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longNode     = (110.30347f - 37.33f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            longPeri     = (224.06676f - 132.25f * cJ2000 / 3600f) * Mathf.Deg2Rad;
            meanDist     = 39.48168677f - 0.00076912f * cJ2000;
            eccentricity = 0.24880766f + 0.00006465f * cJ2000;
            meanLong     = Mod2Pi((238.92881f + 522747.90f * cJ2000 / 3600f) * Mathf.Deg2Rad);
            break;
        }

        //Position of Earth in its orbit
        double me          = Mod2Pi(meanLongE - longPeriE);
        double ve          = TrueAnomaly(me, eccenctricityE);
        double pEarthOrbit = meanDistE * (1 - eccenctricityE * eccenctricityE) / (1 + eccenctricityE * Math.Cos(ve));

        //Heliocentric rectangular coordinates of Earth
        double xe = pEarthOrbit * Math.Cos(ve + longPeriE);
        double ye = pEarthOrbit * Math.Sin(ve + longPeriE);
        double ze = 0.0f;

        //Position of planet in its orbit
        double mp           = Mod2Pi(meanLong - longPeri);
        double vp           = TrueAnomaly(mp, eccentricity);
        double pPlanetOrbit = meanDist * (1 - eccentricity * eccentricity) / (1 + eccentricity * Math.Cos(vp));

        //Heliocentric rectangular coordinates of planets
        double xh = pPlanetOrbit * (Math.Cos(longNode) * Math.Cos(vp + longPeri - longNode) - Math.Sin(longNode) * Math.Sin(vp + longPeri - longNode) * Math.Cos(inclination));
        double yh = pPlanetOrbit * (Math.Sin(longNode) * Math.Cos(vp + longPeri - longNode) + Math.Cos(longNode) * Math.Sin(vp + longPeri - longNode) * Math.Cos(inclination));
        double zh = pPlanetOrbit * (Math.Sin(vp + longPeri - longNode) * Math.Sin(inclination));

        //If Sun set the coordinates to 0
        if (_name == "Sun")
        {
            xh = 0f;
            yh = 0f;
            zh = 0f;
        }

        //Convert to geocentric rectangular coordinates
        double xg = xh - xe;
        double yg = yh - ye;
        double zg = zh - ze;

        // rotate around x axis from ecliptic to equatorial coords
        double ecl = 23.439281f * Mathf.Deg2Rad;
        double xeq = xg;
        double yeq = yg * Math.Cos(ecl) - zg * Math.Sin(ecl);
        double zeq = yg * Math.Sin(ecl) + zg * Math.Cos(ecl);

        // find the RA and DEC from the rectangular equatorial coords
        double ra       = Mod2Pi(Math.Atan2(yeq, xeq)) * Mathf.Rad2Deg;
        double dec      = Math.Atan(zeq / Math.Sqrt(xeq * xeq + yeq * yeq)) * Mathf.Rad2Deg;
        double distance = Math.Sqrt(xeq * xeq + yeq * yeq + zeq * zeq);


        //Now that we have the Right Ascension and the Declinaison of the planet, we can get the Altitude and Azimuth!
        //compute hour angle in degrees
        // mean sidereal time
        double MST = 280.46061837f + 360.98564736629f * j2000 + 0.000387933f * cJ2000 * cJ2000 - cJ2000 * cJ2000 * cJ2000 / 38710000f + _longitude;

        if (MST > 0.0f)
        {
            while (MST > 360.0f)
            {
                MST -= 360.0f;
            }
        }
        else
        {
            while (MST < 0.0f)
            {
                MST = MST + 360.0;
            }
        }

        //Compute hour angle in degrees
        double HA = MST - ra;

        if (HA < 0)
        {
            HA = HA + 360;
        }

        //Convert everything to radians
        HA  *= Mathf.Deg2Rad;
        dec *= Mathf.Deg2Rad;
        //_latitude *= Mathf.Deg2Rad;

        //Compute Altitude and Azimuth (RAD)
        double altitude = Math.Asin(Math.Sin(dec) * Math.Sin(_latitude) + Math.Cos(dec) * Math.Cos(_latitude) * Math.Cos(HA));
        double azimuth  = Math.Acos((Math.Sin(dec) - Math.Sin(altitude) * Math.Sin(_latitude)) / (Math.Cos(altitude) * Math.Cos(_latitude)));

        //Convert both to degree
        altitude *= Mathf.Rad2Deg;
        azimuth  *= Mathf.Rad2Deg;

        if (Math.Sin(HA) > 0f)
        {
            azimuth = 360f - azimuth;
        }

        HorizontalCoordinates coordinates = new HorizontalCoordinates()
        {
            azimuth  = azimuth,
            altitude = altitude,
            distance = distance
        };

        return(coordinates);
    }