module RunCommand (runCommandStrWait) where
import System.Process
import System.Exit
import System.IO
import Control.Concurrent
import Control.Concurrent.Chan
import Data.Either

type Pipe = Chan (Either Char ())

pipeGetContents :: Pipe -> IO String
pipeGetContents p = 
    do
    s <- getChanContents p
    return $ map fromLeft $ takeWhile isLeft s

pipeWrite :: Pipe -> String -> IO ()
pipeWrite p s = writeList2Chan p (map Left s)

-- close the pipe for writing
pipeClose :: Pipe -> IO ()
pipeClose p = writeChan p (Right ())


--
-- * Either utilities
--

isLeft :: Either a b -> Bool
isLeft = either (const True) (const False)

fromLeft :: Either a b -> a
fromLeft =  either id (error "fromLeft: Right")

--
-- * Various versions of runCommand
--

runCommandChan :: String -- ^ command
	      -> IO (Pipe,Pipe,Pipe,ProcessHandle) -- ^ stdin, stdout, stderr, process
runCommandChan c = 
    do
    inC  <- newChan
    outC <- newChan
    errC <- newChan
    (pin,pout,perr,p) <- runInteractiveCommand c
    forkIO (pipeGetContents inC >>= hPutStr pin >> hClose pin)
    forkIO (hGetContents pout >>= pipeWrite outC >> pipeClose outC)
    forkIO (hGetContents perr >>= pipeWrite errC >> pipeClose errC)
    return (inC,outC,errC,p)

runCommandStr :: String -- ^ command
	      -> String -- ^ stdin data
	      -> IO (String,String,ProcessHandle) -- ^ stdout, stderr, process
runCommandStr c inStr = 
    do
    (inC,outC,errC,p) <- runCommandChan c
    forkIO (pipeWrite inC inStr >> pipeClose inC) 
    out <- pipeGetContents outC
    err <- pipeGetContents errC
    return (out,err,p)

runCommandStrWait :: String -- ^ command
		  -> String -- ^ stdin data
		  -> IO (String,String,ExitCode) -- ^ stdout, stderr, process exit status
runCommandStrWait c inStr =
    do
    (out,err,p) <- runCommandStr c inStr
    s <- waitForProcess p
    return (out,err,s)
