module Jukebox.ProgressBar(ProgressBar(..), tickOnRead, withProgressBar) where

import System.IO
import Data.IORef
import Data.Word
import qualified Data.ByteString.Lazy as BSL
--import Data.ByteString.Lazy.Progress
import Control.Exception
import Control.Monad
import Prelude hiding (last)

data ProgressBar = ProgressBar { 
  tick :: IO (),
  enter :: String -> IO (),
  leave :: IO ()
  }

data State = State {
  position :: Int,
  enabled :: Bool,
  level :: Int,
  last :: Last
  }
             
-- What happened last.
data Last = Tick | Enter | Leave

tickOnRead :: ProgressBar -> BSL.ByteString -> IO BSL.ByteString
tickOnRead p s = do
  let chunkSize = 1000000 :: Word64
  nextRef <- newIORef chunkSize
  let f _ index = do
        next <- readIORef nextRef
        when (next <= index) $ do
          tick p
          writeIORef nextRef (next + chunkSize)
  -- trackProgress f s
  return s

withProgressBar :: (ProgressBar -> IO a) -> IO a
withProgressBar f = do
  state <- newIORef State { position = 0, enabled = True, level = 0, last = Enter }
  let spinny 0 = ".-\08"
      spinny 1 = "\\\08"
      spinny 2 = "|\08"
      spinny 3 = "/\08"
      put s = hPutStr stderr s >> hFlush stderr
      tick = do
        s <- readIORef state
        pos <-
          case last s of
            Tick -> return (position s)
            Enter -> return 0
            Leave -> put " " >> return 0
        put (spinny pos)
        writeIORef state s{ position = (pos+1) `mod` 4, last = Tick }
      enter msg = do
        s <- readIORef state
        when (level s /= 0) (put " (")
        put (msg ++ "...")
        writeIORef state s{ last = Enter, level = level s + 1 }
      leave = do
        s <- readIORef state
        when (level s /= 1) (put ")")
        writeIORef state s{last = Leave, level = level s - 1 }
  f ProgressBar { tick = tick, enter = enter, leave = leave }
    `finally` put " \n"