-- | Progress Bar API
module Language.Fixpoint.Utils.Progress (
      withProgress
    , progressInit
    , progressTick
    , progressClose
    ) where

import           Control.Monad                    (when)
import           System.IO.Unsafe                 (unsafePerformIO)
import           System.Console.CmdArgs.Verbosity (isNormal, getVerbosity, Verbosity(..))
import           Data.IORef
import           System.Console.AsciiProgress
-- import           Language.Fixpoint.Misc (traceShow)

{-# NOINLINE pbRef #-}
pbRef :: IORef (Maybe ProgressBar)
pbRef = unsafePerformIO (newIORef Nothing)

withProgress :: Int -> IO a -> IO a
withProgress n act = do
  showBar <- ((/=) Quiet) <$> getVerbosity
  case showBar of
    False -> act
    True  -> displayConsoleRegions $ do
      -- putStrLn $ "withProgress: " ++ show n
      progressInit n
      r <- act
      progressClose
      return r

progressInit :: Int -> IO ()
progressInit n = do
  normal <- isNormal
  when normal $ do
    pr <- mkPB n
    writeIORef pbRef (Just pr)

mkPB   :: Int -> IO ProgressBar
mkPB n = newProgressBar def
  { pgWidth       = 80
  , pgTotal       = {- traceShow "MAKE-PROGRESS" -} (toInteger n)
  , pgFormat      = "Working :percent [:bar]"
  , pgPendingChar = '.'
  , pgOnCompletion = Nothing
  }

progressTick :: IO ()
progressTick    = go =<< readIORef pbRef
  where
   go (Just pr) = incTick pr
   go _         = return ()

incTick :: ProgressBar -> IO ()
incTick pb = do
  st <- getProgressStats pb
  when (incomplete st) (tick pb)
    -- then tick pb -- putStrLn (show (stPercent st, stTotal st, stCompleted st)) >> (tick pb)
    -- else return () 

incomplete :: Stats -> Bool
incomplete st = {- traceShow "INCOMPLETE" -} (stRemaining st) > 0
-- incomplete st = stPercent st < 100


progressClose :: IO ()
progressClose = go =<< readIORef pbRef
  where
    go (Just p) = complete p
    go _        = return ()