{-# LANGUAGE OverloadedStrings #-}
-----------------------------------------------------------------------------
--
-- Module      :  VCSGui.Common.Process
-- Copyright   :  2011 Stephan Fortelny, Harald Jagenteufel
-- License     :  GPL
--
-- Maintainer  :  stephanfortelny at gmail.com, h.jagenteufel at gmail.com
-- Stability   :
-- Portability :
--
-- | Provides facilites to execute an external program.
--
-----------------------------------------------------------------------------

module VCSGui.Common.Process (
    exec
) where

import System.Process
import System.Exit
import System.IO (Handle, hFlush, hClose, hGetContents, hPutStr)
import Control.Concurrent
import Control.Monad.Reader
import qualified Control.Exception as Exc
import Data.Text (Text)
import qualified Data.Text as T (pack, unpack)

-- | Internal function to execute a vcs command
exec :: Maybe FilePath -- ^ working directory or Nothing if not set
     -> Text -- ^ mergetool command, e.g. kdiff3.sh
     -> [Text] -- ^ files, last one is output
     -> IO Bool
exec mcwd cmd opts = do
    (ec, out, err) <- readProc mcwd cmd opts
    case ec of
        ExitSuccess   -> return $ True
        ExitFailure i -> return $ False -- Left $ Exception i out err (cmd : opts)

-- | same as readProcessWithExitCode but having a configurable cwd and env,
readProc :: Maybe FilePath --working directory or Nothing if not set
            -> Text  --command
            -> [Text] -- ^ files, last one is output
            -> IO (ExitCode, Text, Text)
readProc mcwd cmd files = do
    putStrLn $ "Executing process, mcwd: "++show mcwd++"cmd: "++show cmd++",files: "++show files
    (_, Just outh, Just errh, pid) <- createProcess (proc (T.unpack cmd) (map T.unpack files))
                                            { std_out = CreatePipe,
                                              std_err = CreatePipe,
                                              cwd = mcwd
                                              }

    outMVar <- newEmptyMVar

    out <- hGetContents outh
    _ <- forkIO $ Exc.evaluate (length out) >> putMVar outMVar ()

    err <- hGetContents errh
    _ <- forkIO $ Exc.evaluate (length err) >> putMVar outMVar ()

--    hClose inh

    takeMVar outMVar
    takeMVar outMVar
    hClose outh
    hClose errh

    ex <- waitForProcess pid
    return (ex, T.pack out, T.pack err)