-----------------------------------------------------------------------------
-- |
-- Module      :  Data.SBV.Utils.TDiff
-- Copyright   :  (c) Levent Erkok
-- License     :  BSD3
-- Maintainer  :  erkokl@gmail.com
-- Stability   :  experimental
--
-- Runs an IO computation printing the time it took to run it
-----------------------------------------------------------------------------

module Data.SBV.Utils.TDiff(timeIf) where

import Control.DeepSeq (rnf, NFData(..))
import System.Time     (TimeDiff(..), normalizeTimeDiff, diffClockTimes, getClockTime)
import Numeric         (showFFloat)

showTDiff :: TimeDiff -> String
showTDiff itd = et
  where td = normalizeTimeDiff itd
        vals = dropWhile (\(v, _) -> v == 0) (zip [tdYear td, tdMonth td, tdDay td, tdHour td, tdMin td] "YMDhm")
        sec = ' ' : show (tdSec td) ++ dropWhile (/= '.') pico
        pico = showFFloat (Just 3) (((10**(-12))::Double) * fromIntegral (tdPicosec td)) "s"
        et = concatMap (\(v, c) -> ' ':show v ++ [c]) vals ++ sec

-- | If selected, runs the computation @m@, and prints the time it took
-- to run it. The return type should be an instance of 'NFData' to ensure
-- the correct elapsed time is printed.
timeIf :: NFData a => Bool -> String -> IO a -> IO a
timeIf False _ m = m
timeIf True  w m = do start <- getClockTime
                      r <- m
                      end <- rnf r `seq` getClockTime
                      let elapsed = diffClockTimes end start
                      putStrLn $ "** Elapsed " ++ w ++ " time:" ++ showTDiff elapsed
                      return r