content: {-# LANGUAGE RecordWildCards, DeriveDataTypeable #-}
  
  module Development.Bake.Core.Run(
      runInit, runUpdate, runTest, runExtra
      ) where
  
  import Development.Bake.Core.Type hiding (Client)
  import Development.Bake.Core.Message
  import Development.Shake.Command
  import Control.Exception.Extra
  import General.BigString
  import General.Extra
  import System.Time.Extra
  import Control.DeepSeq
  import Control.Concurrent.Extra
  import System.IO.Unsafe
  import Data.Tuple.Extra
  import System.IO.Extra
  import System.Environment.Extra
  import System.FilePath
  import Data.Maybe
  import System.Exit
  import Safe
  import qualified Data.Text as T
  import qualified Data.Text.Lazy as TL
  
  
  {-# NOINLINE running #-}
  running :: Var Int
  running = unsafePerformIO $ newVar 0
  
  
  state x = "--state=" ++ fromState x
  patch x = "--patch=" ++ fromPatch x
  test  x = "--test="  ++ fromTest  x
  
  runInit :: IO (Maybe State, Answer)
  runInit = runAll "init" [] [] toState
  
  runUpdate :: State -> [Patch] -> IO (Maybe State, Answer)
  runUpdate s ps = runAll "update" (state s : map patch ps) [] toState
  
  runTest :: State -> [Patch] -> Maybe Test -> IO Answer
  runTest s ps t = do
      (ex, ans) <- runAll "test" (state s : map patch ps) (map test $ maybeToList t) (map toTest . readNote "runTest")
      return $ maybe ans (\ex -> ans{aTests=ex}) (if t == Nothing then ex else Nothing)
  
  runExtra :: State -> Maybe Patch -> IO (Maybe (T.Text, TL.Text), Answer)
  runExtra s ps = runAll "extra" (state s : map patch (maybeToList ps)) [] ((T.pack *** TL.pack) . readNote "runExtra")
  
  
  runAll :: NFData a => String -> [String] -> [String] -> (String -> a) -> IO (Maybe a, Answer)
  runAll name args1 args2 parse = do
      exe <- getExecutablePath
      dir <- createDir ("bake-" ++ name) args1
  
      (time, res) <- duration $ try_ $ do
          exe <- getExecutablePath
          (out, exit) <- bigStringFromFile $ \file -> do
              res <- bracket_ (modifyVar_ running $ return . succ) (modifyVar_ running $ return . pred) $ do
                  v <- readVar running
                  print $ "RUNNING = " ++ show v
                  cmd [Cwd dir, FileStdout file, FileStderr file] exe ("run" ++ name) args1 args2
              v <- readVar running
              print $ "RUNNING = " ++ show v
              return res
          ex <- if exit /= ExitSuccess then return Nothing else do
              ans <- fmap parse $ readFile' $ dir </> ".bake.result"
              evaluate $ rnf ans
              return $ Just ans
          return (ex, Answer out (Just 0) [] (exit == ExitSuccess))
      case res of
          Left e -> do
              e <- showException e
              return (Nothing, Answer (bigStringFromString e) (Just time) [] False)
          Right (ex,ans) -> return (ex, ans{aDuration=Just time})
  