{-|
Module: Data.Astro.Time
Description: Time
Copyright: Alexander Ignatyev, 2016

Root Time module
-}


module Data.Astro.Time
(
  utToLST
  , lctToLST
  , lstToLCT
)

where

import Data.Astro.Types (DecimalDegrees)
import Data.Astro.Time.JulianDate (JulianDate(..), LocalCivilTime(..), LocalCivilDate(..), splitToDayAndTime, addHours)
import Data.Astro.Time.Sidereal (LocalSiderealTime, utToGST, gstToUT, gstToLST, lstToGST, lstToGSTwDC)


-- | Universal Time to Local Sidereal Time.

-- It takes longitude in decimal degrees and local civil time

utToLST :: DecimalDegrees -> JulianDate -> LocalSiderealTime
utToLST :: DecimalDegrees -> JulianDate -> LocalSiderealTime
utToLST DecimalDegrees
longitude JulianDate
ut = DecimalDegrees -> GreenwichSiderealTime -> LocalSiderealTime
gstToLST DecimalDegrees
longitude (GreenwichSiderealTime -> LocalSiderealTime)
-> GreenwichSiderealTime -> LocalSiderealTime
forall a b. (a -> b) -> a -> b
$ JulianDate -> GreenwichSiderealTime
utToGST JulianDate
ut


-- | Local Civil Time to Local Sidereal Time.

-- It takes longitude in decimal degrees and local civil time

lctToLST :: DecimalDegrees -> LocalCivilTime -> LocalSiderealTime
lctToLST :: DecimalDegrees -> LocalCivilTime -> LocalSiderealTime
lctToLST DecimalDegrees
longitude LocalCivilTime
lct = DecimalDegrees -> JulianDate -> LocalSiderealTime
utToLST DecimalDegrees
longitude (JulianDate -> LocalSiderealTime)
-> JulianDate -> LocalSiderealTime
forall a b. (a -> b) -> a -> b
$ LocalCivilTime -> JulianDate
lctUniversalTime LocalCivilTime
lct


-- | Local Sidereal Time to Local Civil Time.

-- It takes longitude in decimal degrees, local civil date and local sidereal time

lstToLCT :: DecimalDegrees -> LocalCivilDate -> LocalSiderealTime -> LocalCivilTime
lstToLCT :: DecimalDegrees
-> LocalCivilDate -> LocalSiderealTime -> LocalCivilTime
lstToLCT DecimalDegrees
longitude LocalCivilDate
lcd LocalSiderealTime
lst =
  let gst :: GreenwichSiderealTime
gst = DecimalDegrees -> LocalSiderealTime -> GreenwichSiderealTime
lstToGST DecimalDegrees
longitude LocalSiderealTime
lst
      ut :: JulianDate
ut = JulianDate -> GreenwichSiderealTime -> JulianDate
gstToUT (LocalCivilDate -> JulianDate
lcdDate LocalCivilDate
lcd) GreenwichSiderealTime
gst
      lct :: LocalCivilTime
lct = DecimalHours -> JulianDate -> LocalCivilTime
LCT (LocalCivilDate -> DecimalHours
lcdTimeZone LocalCivilDate
lcd) JulianDate
ut
  in if LocalCivilDate -> LocalCivilTime -> Bool
sameDay LocalCivilDate
lcd LocalCivilTime
lct
     then LocalCivilTime
lct -- lstToLCTwDC longitude timeZone jd lst

     else DecimalDegrees
-> LocalCivilDate -> LocalSiderealTime -> LocalCivilTime
lstToLCTwDC DecimalDegrees
longitude LocalCivilDate
lcd LocalSiderealTime
lst


lstToLCTwDC :: DecimalDegrees -> LocalCivilDate -> LocalSiderealTime -> LocalCivilTime
lstToLCTwDC :: DecimalDegrees
-> LocalCivilDate -> LocalSiderealTime -> LocalCivilTime
lstToLCTwDC DecimalDegrees
longitude LocalCivilDate
lcd LocalSiderealTime
lst =
  let gst :: GreenwichSiderealTime
gst = DecimalDegrees -> LocalSiderealTime -> GreenwichSiderealTime
lstToGSTwDC DecimalDegrees
longitude LocalSiderealTime
lst
      ut :: JulianDate
ut = JulianDate -> GreenwichSiderealTime -> JulianDate
gstToUT (LocalCivilDate -> JulianDate
lcdDate LocalCivilDate
lcd) GreenwichSiderealTime
gst
      lct :: LocalCivilTime
lct = DecimalHours -> JulianDate -> LocalCivilTime
LCT (LocalCivilDate -> DecimalHours
lcdTimeZone LocalCivilDate
lcd) JulianDate
ut
  in LocalCivilTime
lct


-- | Returns True if both JulianDates hve the same day

sameDay :: LocalCivilDate -> LocalCivilTime -> Bool
sameDay :: LocalCivilDate -> LocalCivilTime -> Bool
sameDay (LCD DecimalHours
_ (JD TimeBaseType
d1)) (LCT DecimalHours
tz JulianDate
jd2) =
  let (JD TimeBaseType
d2, JulianDate
_) = JulianDate -> (JulianDate, JulianDate)
splitToDayAndTime (JulianDate -> (JulianDate, JulianDate))
-> JulianDate -> (JulianDate, JulianDate)
forall a b. (a -> b) -> a -> b
$ DecimalHours -> JulianDate -> JulianDate
addHours DecimalHours
tz JulianDate
jd2
  in TimeBaseType -> TimeBaseType
forall a. Num a => a -> a
abs (TimeBaseType
d1 TimeBaseType -> TimeBaseType -> TimeBaseType
forall a. Num a => a -> a -> a
- TimeBaseType
d2) TimeBaseType -> TimeBaseType -> Bool
forall a. Ord a => a -> a -> Bool
< TimeBaseType
0.000001