content: -- |Utilities for working with ROS time values.
  module Ros.Internal.RosTime (ROSTime, ROSDuration, toROSTime, fromROSTime, 
                               diffROSTime, getROSTime, diffSeconds) where
  import Data.Time.Clock (UTCTime, NominalDiffTime)
  import Data.Time.Clock.POSIX
  import Data.Word (Word32)
  import Ros.Internal.RosTypes
  
  toROSTime :: UTCTime -> ROSTime
  toROSTime = aux . properFraction . utcTimeToPOSIXSeconds
    where aux (s,f) = (s, truncate $ f * 1000000)
  
  -- |Class of types that may be derived from a 'ROSTime'.
  class FromROSTime a where
    fromROSTime :: ROSTime -> a
  
  instance FromROSTime UTCTime where
    fromROSTime = posixSecondsToUTCTime . aux . fromROSTime
      where aux = realToFrac :: Double -> NominalDiffTime
  
  -- |Convert a 'ROSTime' to the POSIX number of seconds since epoch.
  instance FromROSTime Double where
    fromROSTime (s,ns) = s' + ns'
      where s' = fromIntegral s             :: Double
            ns' = fromIntegral ns / 1000000 :: Double
  
  -- |@timeDiff t1 t2@ computes the difference @t1 - t2@.
  diffROSTime :: ROSTime -> ROSTime -> ROSDuration
  diffROSTime (s1,ns1) (s2,ns2)
    | dns >= 0 = (fi ds, fi dns)
    | otherwise = (fi $ ds - 1, fi $ 1000000 + dns)
    where dns = fw ns1 - fw ns2
          ds = fw s1 - fw s2
          fw :: Word32 -> Int
          fw = fromIntegral
          fi :: Int -> Word32
          fi = fromIntegral
  
  -- |Get the current POSIX time.
  getROSTime :: IO ROSTime
  getROSTime = fmap (aux . properFraction) getPOSIXTime
    where aux (s,f) = (s, truncate $ f * 1000000)
  
  -- |Compute the difference in seconds between two 'ROSTime'
  -- values. The application @diffSeconds tStop tStart@ computes the
  -- time interval @tStop - tStart@.
  diffSeconds :: ROSTime -> ROSTime -> Double
  diffSeconds t1 t2 = fromROSTime $ diffROSTime t1 t2