module Eventloop.System.TeardownThread
    ( startTeardowning
    ) where

import Control.Exception
import Control.Concurrent.ExceptionCollection
import Control.Concurrent.STM

import Eventloop.Types.Exception
import Eventloop.Types.System


startTeardowning :: EventloopSystemConfiguration progstateT
                 -> IO ()
startTeardowning systemConfig
    = do
        sharedIO <- readTVarIO sharedIOStateT_
        sharedIO' <- teardownModules sharedConst sharedIO systemConfig moduleConfigs_
        atomically $ writeTVar sharedIOStateT_ sharedIO'
    where
        sharedConst = sharedIOConstants systemConfig
        sharedIOStateT_ = sharedIOStateT systemConfig
        moduleConfigs_ = moduleConfigs systemConfig


teardownModules :: SharedIOConstants
                -> SharedIOState
                -> EventloopSystemConfiguration progstateT
                -> [EventloopModuleConfiguration]
                -> IO SharedIOState
teardownModules _ sharedIO _ [] = return sharedIO
teardownModules sharedConst sharedIO systemConfig (moduleConfig:configs)
    = do
        sharedIO' <- teardownModule sharedConst sharedIO systemConfig moduleConfig
        teardownModules sharedConst sharedIO' systemConfig configs


teardownModule :: SharedIOConstants
               -> SharedIOState
               -> EventloopSystemConfiguration progstateT
               -> EventloopModuleConfiguration
               -> IO SharedIOState
teardownModule sharedConst sharedIO systemConfig moduleConfig
    = case (teardownM moduleConfig) of
        Nothing         -> return (sharedIO)
        (Just teardown) -> handle
                ( \exception -> do
                    logException (exceptions systemConfig) (toException $ TeardownException moduleId_ exception)
                    return sharedIO
                )
               ( do
                    ioState <- readTVarIO ioStateT_
                    teardown sharedConst sharedIO ioConst ioState
               )
    where
        moduleId_ = moduleId moduleConfig
        ioConst = ioConstants moduleConfig
        ioStateT_ = ioStateT moduleConfig