module Web.Herringbone.Preprocessor.StdIO (
    makeStdIOPP
) where

import Control.Monad.IO.Class
import Data.Monoid
import Data.Text (Text)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C8
import System.Exit (ExitCode(..))
import System.Process.ByteString (readProcessWithExitCode)
import Web.Herringbone

-- | Make a preprocessor which works over standard IO; reading input from
-- stdin, and writing output to stdout.
makeStdIOPP :: Text     -- ^ Name (identifies the preprocessor)
            -> Text     -- ^ Source filename extension (eg "sass")
            -> Text     -- ^ Destination filename extension (eg "css")
            -> String   -- ^ Program name
            -> [String] -- ^ Arguments
            -> PP
makeStdIOPP name consumes produces progname args = PP
    { ppName     = name
    , ppConsumes = consumes
    , ppProduces = produces
    , ppAction   = compile progname args
    }
    
compile :: String
        -> [String]
        -> ByteString
        -> PPM (Either CompileError ByteString)
compile progname args source =
    liftIO $ readAllFromProcess progname args source

-- | Read from a process returning both std err and out.
readAllFromProcess :: String        -- ^ Program
                   -> [String]      -- ^ Args
                   -> ByteString    -- ^ Stdin
                   -> IO (Either ByteString ByteString)
readAllFromProcess program args input = do
    (code,out,err) <- readProcessWithExitCode program args input
    return $ case code of
        ExitFailure 127 -> Left $ "cannot find executable " <> C8.pack program
        ExitFailure _   -> Left $ join (err, out)
        ExitSuccess     -> Right $ join (err, out)
  where
  join (err, out) = if B.null err
                        then out
                        else err <> "\n" <> out