module YJTools.Tribial (
  ghcMake
, updateFile
) where

import System.IO              (openFile, hClose, IOMode(WriteMode), hGetLine,
                               IOMode(ReadMode), withFile)
import System.IO.Unsafe       (unsafeInterleaveIO)
import System.Process         (runProcess, waitForProcess)
import System.Exit            (ExitCode(ExitSuccess))
import System.Directory       (doesFileExist)
import System.Directory.Tools (maybeGetModificationTime)
import Control.Exception      (bracket)
import Control.Monad.Tools    (ifM)
import Control.Applicative    (liftA2, (<$>))
import Data.Function          (on)
import Text.RegexPR           (matchRegexPR)

ghcMake :: String -> FilePath -> IO ExitCode
ghcMake exe dir = do
  let errFile = dir ++ "/" ++ exe ++ ".error"
  ret <- bracket (openFile errFile WriteMode) hClose $ \errH ->
           runProcess "ghc" [ "--make", exe ] (Just dir)
                      Nothing Nothing Nothing (Just errH) >>= waitForProcess
  case ret of
       ExitSuccess -> return ()
       _           -> readFile errFile >>= putStr
  return ret

updateFile :: (String, String) -> FilePath -> FilePath -> IO Bool
updateFile (cmtB, cmtE) src dst = do
  let cmtOut  = (cmtB ++) . ( ++ cmtE ++ "\n")
      cmtIn   = (>>= lookup 1) . fmap snd . matchRegexPR (cmtB ++ "(\\S+)" ++ cmtE)
  updateFile_ cmtIn cmtOut src dst

updateFile_ :: (String -> Maybe String) -> (FilePath -> String) -> FilePath -> FilePath -> IO Bool
updateFile_ gtSrc hdr src dst
  = ifM ( not <$> doesFileExist dst
          `orIO`
          (/= Just src) . gtSrc <$> withFile dst ReadMode (hGetLine)
          `orIO`
          doesNotExistOrOldThan dst src )
      (readFile src >>= writeFile dst . ( (hdr src ++ "\n") ++ ) >> return True )
      (                                                             return False)
  where
  infixr 2 `orIO`
  orIO p1 p2     = do { b1 <- p1; b2 <- unsafeInterleaveIO p2; return $ b1 || b2 }

doesNotExistOrOldThan :: FilePath -> FilePath -> IO Bool
doesNotExistOrOldThan dfn sfn
  = on (liftA2 (<)) maybeGetModificationTime dfn sfn