/*!
 * Types for the Time module.
 */

use std::fmt;

use serde::{Deserialize, Serialize};

/// Enumeration of different time systems.
///
/// A time system is a recognized time standard for representing instants in time
/// along a consistent, continuous scale. Because all current time systems utilize
/// the same definition of a second, the spacing between instants in time is the
/// same across all time scales. This leaves the only difference between them being
/// offsets between them.
///
/// The currently supposed time systems are:
/// - GPS: Global Positioning System. GPS is a time scale used defined by the GPS navigation system control segment.
///   GPS time was aligned with UTC at system inception (January 6, 1980 0h), but
///   does not include leap seconds since it is an atomic time scale.
/// - TAI: Temps Atomique International. TAI is an atomic time scale, which represents
///   passage of time on Earth's geoid.
/// - TT: Terrestrial Time. TT is a theoretical time standard primarily used for astronomy.
///   TT is offset from TAI by a fixed number of seconds at TAI's inception. This number has not
///   been officially updated, however reprocessing of data from the ensemble of atomic clocks
///   that define TAI could lead to a difference. For exact applications that require precise corrections
///   updated yearly BIPM provides these offsets.
/// - UTC: Universal Coordinated Time. UTC is an atomic time scale steered to remain within
///   +/- 0.9 seconds of solar time. Since the rotation of the Earth is continuously changing,
///   UTC periodically incorporates leap seconds to ensure that the difference between
///   UTC and UT1 remains within the expeccted bounds.
/// - UT1: Universal Time 1. UT1 is a solar time that is conceptually the mean time at 0 degrees
///   longitude. UT1 is the same everywhere on Earth simultaneously and represents the rotation of the
///   Earth with respect to the ICRF inertial reference frame.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum TimeSystem {
    /// Global Positioning System time. Atomic time scale aligned with UTC at inception
    /// (January 6, 1980), but does not include leap seconds. Used by GPS navigation systems.
    GPS,
    /// International Atomic Time (Temps Atomique International). Continuous atomic time scale
    /// representing passage of time on Earth's geoid. Does not include leap seconds.
    TAI,
    /// Terrestrial Time. Theoretical atomic time standard used primarily for astronomy.
    /// Offset from TAI by exactly 32.184 seconds (TT = TAI + 32.184s).
    TT,
    /// Coordinated Universal Time. Atomic time scale steered to remain within ±0.9 seconds
    /// of UT1 by incorporating leap seconds. Standard for civil timekeeping worldwide.
    UTC,
    /// Universal Time 1. Solar time representing Earth's rotation relative to the ICRF
    /// inertial frame. Mean solar time at 0° longitude, varies irregularly due to Earth's rotation.
    UT1,
    /// Barycentric Dynamical Time. Time scale for solar system barycentric ephemerides.
    /// Differs from TT by small periodic terms (< 1.7 ms) due to relativistic effects
    /// of Earth's orbital motion. Computed via Kaplan (2005:15) / Vallado Eq. 3-53.
    TDB,
    /// Geocentric Coordinate Time. Coordinate time for geocentric reference systems.
    /// Differs from TT by a secular drift (~0.7 s/year) due to Earth's gravitational
    /// time dilation. Computed via Vallado Eq. 3-56.
    TCG,
    /// Barycentric Coordinate Time. Coordinate time for the solar system barycenter.
    /// Differs from TDB by a secular drift due to relativistic effects.
    /// Computed via Vallado Eq. 3-52.
    TCB,
    /// BeiDou Navigation Satellite System Time. Atomic time scale aligned with UTC
    /// at inception (January 1, 2006). Fixed offset from TAI of 33 seconds (BDT = TAI - 33s).
    BDT,
    /// Galileo System Time. Atomic time scale for the Galileo navigation system.
    /// Steered to GPS time, sharing the same fixed offset from TAI of 19 seconds (GST = TAI - 19s).
    GST,
}

impl fmt::Display for TimeSystem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            TimeSystem::GPS => write!(f, "GPS"),
            TimeSystem::TAI => write!(f, "TAI"),
            TimeSystem::TT => write!(f, "TT"),
            TimeSystem::UTC => write!(f, "UTC"),
            TimeSystem::UT1 => write!(f, "UT1"),
            TimeSystem::TDB => write!(f, "TDB"),
            TimeSystem::TCG => write!(f, "TCG"),
            TimeSystem::TCB => write!(f, "TCB"),
            TimeSystem::BDT => write!(f, "BDT"),
            TimeSystem::GST => write!(f, "GST"),
        }
    }
}

#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
    use super::*;

    #[test]
    fn test_time_system_display() {
        assert_eq!(format!("{}", TimeSystem::GPS), "GPS");
        assert_eq!(format!("{}", TimeSystem::TAI), "TAI");
        assert_eq!(format!("{}", TimeSystem::TT), "TT");
        assert_eq!(format!("{}", TimeSystem::UTC), "UTC");
        assert_eq!(format!("{}", TimeSystem::UT1), "UT1");
        assert_eq!(format!("{}", TimeSystem::TDB), "TDB");
        assert_eq!(format!("{}", TimeSystem::TCG), "TCG");
        assert_eq!(format!("{}", TimeSystem::TCB), "TCB");
        assert_eq!(format!("{}", TimeSystem::BDT), "BDT");
        assert_eq!(format!("{}", TimeSystem::GST), "GST");
    }
}
