module Yael.Eff.Log where

import Yael.Eff
import Control.Monad.IO.Class
import System.IO
import Control.Monad.ST
import Data.STRef

newtype Log m = Log
  { _writeLog :: String -> m ()
  }

writeLog :: String -> () :+ '[Log]
writeLog s = withEffT $ \Log{_writeLog} -> _writeLog s

stdoutLog :: (MonadIO m) => Log m
stdoutLog = handleLog stdout

handleLog :: MonadIO m => Handle -> Log m
handleLog handle = Log $ liftIO . hPutStr handle

noLog :: Monad m => Log m
noLog = Log
  { _writeLog = const $ return ()
  }


withCollectLog :: (forall n . Monad n => Log n -> n a) -> (a, [String])
withCollectLog f = runST $ do
  r <- newSTRef []
  let l = Log
        { _writeLog = \s -> modifySTRef r (s:)
        }
  res <- f l
  logged <- readSTRef r
  return (res, reverse logged)