-- | Running actions with explicit input\/output connected to
-- @`stdin`@\/@`stdout`@.
--
-- This module is inspired by the package <http://hackage.haskell.org/package/silently>.

module System.IO.Fake where



import Control.DeepSeq
import Control.Exception
import GHC.IO.Handle
import System.Directory
import System.IO



-- | Perform an action that with access to a temporary file. The file is removed
-- after the action is completed.
withTempFile
    :: FilePath                     -- ^ Path to directory for temporary file
    -> String                       -- ^ Base name for temporary file
    -> ((FilePath,Handle) -> IO a)  -- ^ Action
    -> IO a
withTempFile tmpDir base k = bracket
    (openTempFile tmpDir base)
    (\(file,h) -> hClose h >> removeFile file)
    k

-- | Perform an action with a redirected handle
withRedirect
    :: Handle  -- ^ Shadowing handle
    -> Handle  -- ^ Shadowed handle
    -> IO a    -- ^ Action in which the redirect takes place
    -> IO a
withRedirect new old act = bracket
    (do buffering <- hGetBuffering old
        dupH      <- hDuplicate old
        hDuplicateTo new old
        return (dupH,buffering)
    )
    (\(dupH,buffering) -> do
        hDuplicateTo dupH old
        hSetBuffering old buffering
        hClose dupH
    )
    (\_ -> act)

-- | Perform an action with explicit input\/output connected to
-- @`stdin`@\/@`stdout`@
fakeIO
    :: IO a       -- ^ Action
    -> String     -- ^ Input to send to @stdin@
    -> IO String  -- ^ Result from @stdout@
fakeIO act inp = do
    tmpDir <- getTemporaryDirectory
    withTempFile tmpDir "fakeInput" $ \(inpFile,inpH) ->
      withTempFile tmpDir "fakeOutput" $ \(outFile,outH) -> do
        withRedirect outH stdout $
          withRedirect inpH stdin $ do
            hPutStr inpH inp
            hSeek inpH AbsoluteSeek 0
            act
            hFlush stdout
            hSeek outH AbsoluteSeek 0
            str <- hGetContents outH
            str `deepseq` return str