{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE CPP #-}
module Language.R.Event
  ( forIH
  , forIH_
  , registerREvents
  , eventLoopPoll
  , eventLoopSelect
  , refresh
  ) where
import Control.Applicative
import Control.Monad (forever)
import Control.Monad.R.Class
import Data.Maybe (catMaybes)
import qualified Foreign.R.EventLoop as R
import qualified GHC.Event as Event
import Language.R.Globals (inputHandlers)
import Foreign (FunPtr, Ptr, nullPtr, peek)
import Prelude 
forIH :: Ptr R.InputHandler -> (R.InputHandler -> IO a) -> IO [a]
forIH ihptr f
  | ihptr == nullPtr = return []
  | otherwise = do
    ih <- peek ihptr
    (:) <$> f ih <*> forIH (R.inputHandlerNext ih) f
forIH_ :: Ptr R.InputHandler -> (R.InputHandler -> IO ()) -> IO ()
forIH_ ihptr f
  | ihptr == nullPtr = return ()
  | otherwise = do
    ih <- peek ihptr
    f ih
    forIH_ (R.inputHandlerNext ih) f
foreign import ccall "dynamic" invokeIO :: FunPtr (IO ()) -> IO ()
foreign import ccall "dynamic" invokeCallback :: FunPtr (Ptr () -> IO ()) -> Ptr () -> IO ()
registerREvents
  :: MonadR m
  => Event.EventManager
  -> m ([Event.FdKey], Maybe Event.TimeoutKey)
registerREvents emgr = io $ do
    tmgr <- Event.getSystemTimerManager
    fdkeys <- forIH inputHandlers $ \R.InputHandler{..} -> do
      let action _ _ = invokeCallback inputHandlerCallback inputHandlerUserData
      case 0 < inputHandlerActive of
        True ->
#if MIN_VERSION_base(4,8,1)
          Just <$> Event.registerFd emgr action inputHandlerFD Event.evtRead Event.MultiShot
#elif MIN_VERSION_base(4,8,0)
          fail "registerREvents not implementable in GHC 7.10.1. Use 7.10.2."
#else
          Just <$> Event.registerFd emgr action inputHandlerFD Event.evtRead
#endif
        False -> return Nothing
    usecs <- peek R.pollingPeriod
    gusecs <- peek R.graphicsPollingPeriod
    let eusecs
          | usecs == 0 && gusecs == 0 = 10000
          | usecs == 0 || gusecs == 0 = max usecs gusecs
          | otherwise = min usecs gusecs
    mbtkey <- case 0 < eusecs of
      True -> do
        let action = do
              peek R.polledEvents >>= invokeIO
              peek R.graphicsPolledEvents >>= invokeIO
        Just <$> Event.registerTimeout tmgr (fromIntegral usecs) action
      False -> return Nothing
    return (catMaybes fdkeys, mbtkey)
eventLoopPoll :: MonadR m => m ()
eventLoopPoll = error "Unimplemented."
eventLoopSelect :: MonadR m => m ()
eventLoopSelect =
    io $ forever $ do
      usecs <- peek R.pollingPeriod
      gusecs <- peek R.graphicsPollingPeriod
      let eusecs
            | usecs == 0 && gusecs == 0 = 10000
            | usecs == 0 || gusecs == 0 = max usecs gusecs
            | otherwise = min usecs gusecs
      R.checkActivity eusecs 1 >>=
        R.runHandlers inputHandlers
refresh :: MonadR m => m ()
refresh = io $ R.checkActivity 0 1 >>= R.runHandlers inputHandlers