module Eventloop.System.Setup
    ( setupEventloopSystemConfig
    ) where

import Control.Concurrent
import Control.Concurrent.ExceptionCollection
import Control.Concurrent.MVar
import Control.Concurrent.STM
import Control.Concurrent.Datastructures.BlockingConcurrentQueue

import Eventloop.DefaultConfiguration
import Eventloop.Types.System


setupEventloopSystemConfig :: EventloopSetupConfiguration progstateT
                           -> IO (EventloopSystemConfiguration progstateT)
setupEventloopSystemConfig setupConfig
    = do
        eventloopConfig_ <- setupEventloopConfiguration setupConfig
        moduleConfigurations_ <- mapM setupEventloopModuleConfig (setupModuleConfigurations setupConfig)
        sharedIOConst <- setupSharedIOConstants
        sharedIOState_ <- setupSharedIOState
        sharedIOStateT_ <- newTVarIO sharedIOState_
        systemThreadId_ <- myThreadId
        retrieverThreadsM_ <- newMVar []
        outRouterThreadM_ <- newEmptyMVar
        senderThreadsM_ <- newMVar []
        exceptionCollection <- createExceptionCollection
        isStoppingM_ <- newMVar False

        return ( EventloopSystemConfiguration
                    eventloopConfig_
                    moduleConfigurations_
                    sharedIOConst
                    sharedIOStateT_
                    systemThreadId_
                    retrieverThreadsM_
                    outRouterThreadM_
                    senderThreadsM_
                    exceptionCollection
                    isStoppingM_
               )


setupEventloopConfiguration :: EventloopSetupConfiguration progstateT
                            -> IO (EventloopConfiguration progstateT)
setupEventloopConfiguration setupConfig
    = do
        progStateT_ <- newTVarIO (beginProgstate setupConfig)
        inEventQueue_ <- createBlockingConcurrentQueue
        outEventQueue_ <- createBlockingConcurrentQueue

        return ( EventloopConfiguration
                    progStateT_
                    (eventloopF setupConfig)
                    inEventQueue_
                    outEventQueue_
               )


setupEventloopModuleConfig :: EventloopSetupModuleConfiguration
                           -> IO EventloopModuleConfiguration
setupEventloopModuleConfig setupModuleConfig
    = do
        ioStateT <- newTVarIO NoState
        senderConfig <- setupEventloopModuleSenderConfiguration (eventSenderF setupModuleConfig)

        return ( EventloopModuleConfiguration
                    (moduleIdentifier setupModuleConfig)
                    NoConstants
                    ioStateT
                    (initializerF setupModuleConfig)
                    (eventRetrieverF setupModuleConfig)
                    (preprocessorF setupModuleConfig)
                    (postprocessorF setupModuleConfig)
                    senderConfig
                    (teardownF setupModuleConfig)
               )
    where
        moduleId_ = moduleIdentifier setupModuleConfig



setupEventloopModuleSenderConfiguration :: Maybe EventSender
                                        -> IO (Maybe EventloopModuleSenderConfiguration)
setupEventloopModuleSenderConfiguration Nothing = return Nothing
setupEventloopModuleSenderConfiguration (Just eventSender_)
    = do
        senderEventQueue_ <- createBlockingConcurrentQueue

        return (Just (EventloopModuleSenderConfiguration eventSender_ senderEventQueue_))