{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Run (run) where

import Import

import Sim

import System.IO (openFile)

import CellularFluid.Grid.Types
import CellularFluid.Grid.Parse

-- | RIO top level entry point
run :: RIO App ()
run = do
  app <- ask
  let opt = appOptions app
  when (optionsVerbose opt) outputOptions
  let fpIn = optionsInput opt
      fpOut = optionsOutput opt
  egrid <- loadGrid fpIn
  outHandle <- openOutput fpOut
  sim <- case egrid of
           Right (grid, phys) -> setupSim grid phys outHandle
           Left s -> (logError . fromString $ "Grid parse error: " ++ s) >> exitFailure
  runRIO sim runSim



-- | Logs options when verbose is ON
outputOptions :: (HasOptions env, HasLogFunc env)
              => RIO env ()
outputOptions = do
    env <- ask
    let opt = env ^. optionsL
    logInfo "Verbose flag ON"
    logInfo . fromString $ "INPUT: " ++ optionsInput opt
    logInfo . fromString $ "OUTPUT: " ++ optionsOutput opt


-- | Loads simulation grid
loadGrid :: (HasLogFunc env)
         => FilePath
         -> RIO env (Either String (Grid, PhysCfg))
loadGrid fp = do
    logDebug . fromString $ "Loading grid from: " ++ fp
    txt <- readFileUtf8 fp
    let result = parseGrid txt
    logDebug . fromString $ "Done loading grid from: " ++ fp
    return result


-- | Opens output file
openOutput :: (HasLogFunc env)
           => FilePath
           -> RIO env Handle
openOutput fp = do
    logDebug . fromString $ "Opening output file: " ++ fp
    h <- liftIO $ openFile fp WriteMode
    hSetBuffering h $ BlockBuffering $ Just 268435456 -- 256 MB
    logDebug . fromString $ "Done opening output file: " ++ fp
    return h


-- | Sets up simulation environment
setupSim :: (HasLogFunc env, HasOptions env)
         => Grid
         -> PhysCfg
         -> Handle
         -> RIO env SimApp
setupSim grid phys h = 
    let simCfg = SimulationCFG { cfgTimeStep = 1.0 / 60.0
                               , cfgPhysics = phys
                               }
     in do
         env <- ask
         let opt = env ^. optionsL
         return $ SimApp { simHandle = h
                         , simCfg = simCfg
                         , simGrid = grid
                         , simLogFunc = env ^. logFuncL
                         , simSteps = optionsTimeStep opt
                         }
