{-# LANGUAGE CPP #-}
-- This module is based on code from the "time" package, and is licensed BSD3.
module Network.Tremulous.MicroTime (MicroTime, getMicroTime) where

#ifdef mingw32_HOST_OS
import Data.Word
import System.Win32.Time
#else
import Foreign
import Foreign.C
#endif

type MicroTime = Word64
getMicroTime :: IO MicroTime

#ifdef mingw32_HOST_OS
getMicroTime = do
    FILETIME ft <- System.Win32.Time.getSystemTimeAsFileTime
    return ((ft - win32_epoch_adjust) `quot` 10)

win32_epoch_adjust :: Word64
win32_epoch_adjust = 116444736000000000

#else
data CTimeval = MkCTimeval !CLong !CLong

instance Storable CTimeval where
    sizeOf _    = sizeOf (undefined :: CLong) * 2
    alignment _ = alignment (undefined :: CLong)
    peek p = do
        s   <- peekElemOff (castPtr p) 0
        mus <- peekElemOff (castPtr p) 1
        return (MkCTimeval s mus)
    poke p (MkCTimeval s mus) = do
        pokeElemOff (castPtr p) 0 s
        pokeElemOff (castPtr p) 1 mus

foreign import ccall unsafe "time.h gettimeofday" gettimeofday :: Ptr CTimeval -> Ptr () -> IO CInt

-- | Get the current POSIX time from the system clock.
getMicroTime = with (MkCTimeval 0 0) $ \ptval -> do
    result <- gettimeofday ptval nullPtr
    if result == 0
        then f `fmap` peek ptval
        else fail ("error in gettimeofday: " ++ show result)
    where f (MkCTimeval a b) = fromIntegral a * 1000000 + fromIntegral b
#endif