module Utils
    (list
    ,run
    ,trim
    ,splitBy)
    where

import Prelude hiding (catch)
import Control.Exception
import Control.Concurrent
import System.Process
import System.IO
import System.Exit

list :: Eq a => b -> ([a] -> b) -> [a] -> b
list nil cons v = if v == [] then nil else cons v

run :: String -> String -> IO (Either String (String,String))
run cmd input = do
  pipe <- catch (Right `fmap` runInteractiveCommand ("ulimit -t 1 && " ++ cmd))
                (const $ return $ Left "Broken pipe")
  case pipe of
    Right (inp,out,err,pid) -> do
                  catch (do hSetBuffering inp NoBuffering
                            hPutStr inp input 
                            hClose inp
                            errv <- newEmptyMVar
                            outv <- newEmptyMVar
                            output <- hGetContents out
                            errput <- hGetContents err
                            forkIO $ evaluate (length output) >> putMVar outv ()
                            forkIO $ evaluate (length errput) >> putMVar errv ()
                            takeMVar errv
                            takeMVar outv
                            e <- catch (waitForProcess pid)
                                       (const $ return ExitSuccess)
                            return $ Right (errput,output))
                        (const $ return $ Left "Broken pipe")
    _ -> return $ Left "Unable to launch process"

trim :: String -> String
trim = unwords . words

splitBy :: (a -> Bool) -> [a] -> [[a]]
splitBy f = go [] where
    go ac xs = case break f xs of
                 ([],[]) -> reverse ac
                 ([],ys) -> go ac      (skip ys)
                 (xs,ys) -> go (xs:ac) (skip ys)
    skip = dropWhile f