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_))