module Eventloop.Module.StdIn.StdIn
    ( setupStdInModuleConfiguration
    , stdInModuleIdentifier
    , stdInInitializer
    , stdInEventRetriever
    , stdInEventSender
    ) where

import System.IO
import Data.String
import Control.Concurrent.Datastructures.BlockingConcurrentQueue
import Control.Concurrent.STM

import Eventloop.Module.StdIn.Types
import Eventloop.Types.Common
import Eventloop.Types.Events
import Eventloop.Types.System

setupStdInModuleConfiguration :: EventloopSetupModuleConfiguration
setupStdInModuleConfiguration = ( EventloopSetupModuleConfiguration
                                    stdInModuleIdentifier
                                    (Just stdInInitializer)
                                    (Just stdInEventRetriever)
                                    Nothing
                                    Nothing
                                    (Just stdInEventSender)
                                    Nothing
                                  )


stdInModuleIdentifier :: EventloopModuleIdentifier
stdInModuleIdentifier = "stdin"


stdInInitializer :: Initializer
stdInInitializer sharedConst sharedIO
    = do
        inQueue <- createBlockingConcurrentQueue
        return (sharedConst, sharedIO, StdInConstants inQueue, NoState)


stdInEventRetriever :: EventRetriever
stdInEventRetriever sharedConst sharedIOT ioConst ioStateT
    = do
        inEvents <- takeAllFromBlockingConcurrentQueue inQueue
        return (map InStdIn inEvents)
    where
        inQueue = stdInInQueue ioConst


stdInEventSender :: EventSender
stdInEventSender _ _ _ _ Stop = return ()
stdInEventSender sharedConst sharedIOT ioConst ioStateT (OutStdIn a)
    = do
        inEvents <- stdInEventSender' a
        putAllInBlockingConcurrentQueue inQueue inEvents
    where
        inQueue = stdInInQueue ioConst


stdInEventSender' :: StdInOut -> IO [StdInIn]
stdInEventSender' StdInReceiveContents
    = doStdInGet linedGetContents StdInReceivedContents
    where
        linedGetContents = (getContents >>= (\strContents -> return $ lines strContents))

stdInEventSender' StdInReceiveLine
    = doStdInGet getLine StdInReceivedLine
stdInEventSender' StdInReceiveChar
    = doStdInGet getChar StdInReceivedChar


doStdInGet :: (IO a) -> (a -> StdInIn) -> IO [StdInIn]
doStdInGet source typeEvent
    = do
        content <- source
        return ([typeEvent content])