module Shaker.Reflexivite (
  RunnableFunction(..)
  -- * Collect module information functions
  ,runFunction
  )
 where

import Control.Exception as C
import Control.Monad.Reader
import Data.Maybe
import DynFlags
import GHC
import GHC.Paths
import Shaker.Action.Compile
import Shaker.GhcInterface
import Shaker.Type
import Unsafe.Coerce

data RunnableFunction = RunnableFunction {
  runnableFunctionModule :: [String]
  ,runnableLibrairies :: [String]
  ,runnableFunctionFunction :: String -- The function name. Should have IO() as signature
}
 deriving Show

-- | Compile, load and run the given function
runFunction :: CompileInput -> RunnableFunction -> Shaker IO()
runFunction cpIn (RunnableFunction importModuleList listLibs fun) = do
  listInstalledPkgId <- fmap catMaybes (mapM searchInstalledPackageId listLibs)
  dynFun <- lift $ runGhc (Just libdir) $ do
         dflags <- getSessionDynFlags
         _ <- setSessionDynFlags (addLibraryToDynFlags listInstalledPkgId (dopt_set dflags Opt_HideAllPackages))
         _ <- ghcCompile cpIn
         configureContext importModuleList
         value <- compileExpr fun
         do let value' = unsafeCoerce value :: a
            return value'
  _ <- lift $ handleActionInterrupt dynFun
  return ()
  where
        genTuple :: ModSummary -> (Module, Maybe (ImportDecl RdrName))
        genTuple modSummary = (ms_mod modSummary, Nothing)
        configureContext [] = do
          modGraph <- getModuleGraph
          setContext [] (map genTuple modGraph)
        configureContext imports = do
          mods <- mapM (\a -> findModule (mkModuleName a) Nothing) imports
          setContext [] $ map (\m -> (m, Nothing) ) mods

handleActionInterrupt :: IO() -> IO()
handleActionInterrupt =  C.handle catchAll
  where catchAll :: C.SomeException -> IO ()
        catchAll e = putStrLn ("Shaker caught " ++ show e ) >>  return ()