{-# LANGUAGE TemplateHaskell #-}
{-|
Module:             IO
Description:        General IO functions specialized for 'Printable' instances.
Copyright:          © 2016 All rights reserved.
License:            GPL-3
Maintainer:         Evan Cofsky <evan@theunixman.com>
Stability:          experimental
Portability:        POSIX
-}

module IO (
    putStr,
    putStrLn,
    managed,
    Managed,
    MonadManaged(..),
    runManaged,
    TempFile,
    tfPath,
    tfHandle,
    tempFile,
    MonadIO,
    liftIO,
    PIO.hSeek,
    PIO.SeekMode(..),
    PIO.IOMode(..),
    file,
    tfile,
    textMode,
    binaryMode,
    hIsEOF,
    hClose,
    doesFileExist,
    removeFile,
    PIO.Handle,
    SIO.stdin,
    SIO.stdout,
    SIO.stderr
    ) where

import Lawless
import Control.Monad.IO.Class
import qualified System.Path.Directory as D
import qualified System.Path.IO as PIO
import qualified Data.Text.IO as T
import Text
import Textual
import Path
import qualified System.Path.PartClass as PC
import Control.Monad.Managed.Safe
import Exception
import qualified System.IO as SIO

-- * Printable I/O to stdio

liftPrintble  (MonadIO m, Printable p)  (Text  IO ())  p  m ()
liftPrintble f p = liftIO $ f (buildText  print $ p)

putStr  (MonadIO m, Printable p)  p  m ()
putStr = liftPrintble T.putStr

putStrLn  (MonadIO m, Printable p)  p  m ()
putStrLn = liftPrintble T.putStrLn

-- * Managed temporary files
data TempFile = TempFile {
    _tfPath  AbsFile,
    _tfHandle  PIO.Handle
    }
makeLenses ''TempFile

tempFile  AbsDir  RelFile  Managed TempFile
tempFile pth tmpl =
    let
        open = do
            (p, h)  liftIO $ PIO.openTempFile pth tmpl
            liftIO $ binaryMode h
            return $ TempFile p h

        close tf = do
            liftIO $ PIO.hClose $ tf ^. tfHandle
            liftIO $ D.removeFile $ tf ^. tfPath
    in
        managed $ bracket open close

-- * Managed files

-- | Binary files, no buffering.
file  PC.AbsRel ar  File ar  PIO.IOMode  Managed PIO.Handle
file pth m = managed $ \fh  do
    liftIO $ PIO.withBinaryFile pth m $ \h  do
        binaryMode h
        fh h

-- | Text files, line-buffered.
tfile  PC.AbsRel ar  File ar  PIO.IOMode  Managed PIO.Handle
tfile pth m =managed $ \fh  do
    liftIO $ PIO.withBinaryFile pth m $ \h  do
        textMode h
        fh h

textMode  MonadIO m  PIO.Handle  m ()
textMode h = liftIO $
    PIO.hSetBuffering h PIO.LineBuffering >>
    PIO.hSetBinaryMode h False

binaryMode  MonadIO m  PIO.Handle  m ()
binaryMode h = liftIO $
    PIO.hSetBuffering h PIO.NoBuffering >>
    PIO.hSetBinaryMode h True

-- * Lifted IO

hIsEOF  MonadIO m  SIO.Handle  m Bool
hIsEOF = liftIO  SIO.hIsEOF

hClose  MonadIO m  SIO.Handle  m ()
hClose = liftIO  SIO.hClose

doesFileExist  (MonadIO m, PC.AbsRel ar)  File ar  m Bool
doesFileExist = liftIO  D.doesFileExist

removeFile  (MonadIO m, PC.AbsRel ar)  File ar  m ()
removeFile = liftIO  D.removeFile