module System.Glib.MainLoop (
  HandlerId,
  timeoutAdd,
  timeoutAddFull,
  timeoutRemove,
  idleAdd,
  idleRemove,
  IOCondition(..),
  inputAdd,
  inputRemove,
  Priority,
  priorityLow,
  priorityDefaultIdle,
  priorityHighIdle,
  priorityDefault,
  priorityHigh,
  MainLoop,
  mainLoopNew,
  mainLoopRun,
  mainLoopQuit,
  mainLoopIsRunning,
  MainContext,
  mainContextNew,
  mainContextDefault,
  mainContextIteration,
  mainContextFindSourceById,
  Source(..),
  sourceAttach,
  sourceSetPriority,
  sourceGetPriority,
  sourceDestroy,
  sourceIsDestroyed
  ) where
import Control.Monad (liftM)
import System.Glib.FFI
import System.Glib.Flags
import System.Glib.GObject (DestroyNotify, destroyFunPtr)
type SourceFunc = FunPtr (((Ptr ()) -> (IO CInt)))
foreign import ccall "wrapper" mkSourceFunc :: (Ptr () -> IO (CInt)) -> IO SourceFunc
type HandlerId = (CUInt)
makeCallback :: IO (CInt) -> IO (SourceFunc, DestroyNotify)
makeCallback fun = do
  funPtr <- mkSourceFunc (const fun)
  return (funPtr, destroyFunPtr)
timeoutAdd :: IO Bool -> Int -> IO HandlerId
timeoutAdd fun msec = timeoutAddFull fun priorityDefault msec
timeoutAddFull :: IO Bool -> Priority -> Int -> IO HandlerId
timeoutAddFull fun pri msec = do
  (funPtr, dPtr) <- makeCallback (liftM fromBool fun)
  g_timeout_add_full
    (fromIntegral pri)
    (fromIntegral msec)
    funPtr
    (castFunPtrToPtr funPtr)
    dPtr
timeoutRemove :: HandlerId -> IO ()
timeoutRemove id = g_source_remove id >> return ()
idleAdd :: IO Bool -> Priority -> IO HandlerId
idleAdd fun pri = do
  (funPtr, dPtr) <- makeCallback (liftM fromBool fun)
  g_idle_add_full (fromIntegral pri) funPtr
    (castFunPtrToPtr funPtr) dPtr
idleRemove :: HandlerId -> IO ()
idleRemove id = g_source_remove id >> return ()
data IOCondition = IOIn
                 | IOOut
                 | IOPri
                 | IOErr
                 | IOHup
                 | IOInvalid
                 deriving (Eq,Bounded)
instance Enum IOCondition where
  fromEnum IOIn = 1
  fromEnum IOOut = 4
  fromEnum IOPri = 2
  fromEnum IOErr = 8
  fromEnum IOHup = 16
  fromEnum IOInvalid = 32
  toEnum 1 = IOIn
  toEnum 4 = IOOut
  toEnum 2 = IOPri
  toEnum 8 = IOErr
  toEnum 16 = IOHup
  toEnum 32 = IOInvalid
  toEnum unmatched = error ("IOCondition.toEnum: Cannot match " ++ show unmatched)
  succ IOIn = IOOut
  succ IOOut = IOPri
  succ IOPri = IOErr
  succ IOErr = IOHup
  succ IOHup = IOInvalid
  succ _ = undefined
  pred IOOut = IOIn
  pred IOPri = IOOut
  pred IOErr = IOPri
  pred IOHup = IOErr
  pred IOInvalid = IOHup
  pred _ = undefined
  enumFromTo x y | fromEnum x == fromEnum y = [ y ]
                 | otherwise = x : enumFromTo (succ x) y
  enumFrom x = enumFromTo x IOInvalid
  enumFromThen _ _ =     error "Enum IOCondition: enumFromThen not implemented"
  enumFromThenTo _ _ _ =     error "Enum IOCondition: enumFromThenTo not implemented"
instance Flags IOCondition
newtype IOChannel = IOChannel (Ptr (IOChannel))
type IOFunc = FunPtr (((Ptr IOChannel) -> (CInt -> ((Ptr ()) -> (IO CInt)))))
foreign import ccall "wrapper" mkIOFunc :: (Ptr IOChannel -> CInt -> Ptr () -> IO (CInt)) -> IO IOFunc
type FD = Int
inputAdd ::
    FD 
 -> [IOCondition] 
 -> Priority 
 -> IO Bool 
                  
                  
 -> IO HandlerId 
inputAdd fd conds pri fun = do
  funPtr <- mkIOFunc (\_ _ _ -> liftM fromBool fun)
  channel <- g_io_channel_unix_new (fromIntegral fd)
  (\(IOChannel arg1) arg2 arg3 arg4 arg5 arg6 -> g_io_add_watch_full arg1 arg2 arg3 arg4 arg5 arg6)
    (IOChannel channel)
    (fromIntegral pri)
    ((fromIntegral . fromFlags) conds)
    funPtr
    (castFunPtrToPtr funPtr)
    destroyFunPtr
inputRemove :: HandlerId -> IO ()
inputRemove id = g_source_remove id >> return ()
type Priority = Int
priorityHigh :: Int
priorityHigh = 100
priorityDefault :: Int
priorityDefault = 0
priorityHighIdle :: Int
priorityHighIdle = 100
priorityDefaultIdle :: Int
priorityDefaultIdle = 200
priorityLow :: Int
priorityLow = 300
newtype MainLoop = MainLoop (ForeignPtr (MainLoop))
newtype MainContext = MainContext (ForeignPtr (MainContext))
mainLoopNew :: Maybe MainContext 
            -> Bool 
            -> IO MainLoop 
mainLoopNew context isRunning =
    do let context' = maybe (MainContext nullForeignPtr) id context
       loopPtr <- (\(MainContext arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->g_main_loop_new argPtr1 arg2) context' $ fromBool isRunning
       liftM MainLoop $ newForeignPtr loopPtr mainLoopFinalizer
foreign import ccall unsafe "&g_main_loop_unref"
    mainLoopFinalizer :: FunPtr (Ptr MainLoop -> IO ())
mainLoopRun :: MainLoop
            -> IO ()
mainLoopRun loop =
    (\(MainLoop arg1) -> withForeignPtr arg1 $ \argPtr1 ->g_main_loop_run argPtr1) loop
mainLoopQuit :: MainLoop
             -> IO ()
mainLoopQuit loop =
    (\(MainLoop arg1) -> withForeignPtr arg1 $ \argPtr1 ->g_main_loop_quit argPtr1) loop
mainLoopIsRunning :: MainLoop
                  -> IO Bool
mainLoopIsRunning loop =
    liftM toBool $ (\(MainLoop arg1) -> withForeignPtr arg1 $ \argPtr1 ->g_main_loop_is_running argPtr1) loop
mainLoopGetContext :: MainLoop
                   -> MainContext
mainLoopGetContext loop =
    MainContext $ unsafePerformIO $
        (\(MainLoop arg1) -> withForeignPtr arg1 $ \argPtr1 ->g_main_loop_get_context argPtr1) loop >>=
            flip newForeignPtr mainContextFinalizer
foreign import ccall unsafe "&g_main_context_unref"
    mainContextFinalizer :: FunPtr (Ptr MainContext -> IO ())
mainContextNew :: IO MainContext
mainContextNew =
    newContextMarshal g_main_context_new
mainContextDefault :: MainContext
mainContextDefault =
    unsafePerformIO $ newContextMarshal g_main_context_default
newContextMarshal action =
    do ptr <- action
       liftM MainContext $ newForeignPtr ptr mainContextFinalizer
mainContextIteration :: MainContext
                     -> Bool
                     -> IO Bool
mainContextIteration context mayBlock =
    liftM toBool $ (\(MainContext arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->g_main_context_iteration argPtr1 arg2) context (fromBool mayBlock)
mainContextFindSourceById :: MainContext
                          -> HandlerId
                          -> IO Source
mainContextFindSourceById context id =
    (\(MainContext arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->g_main_context_find_source_by_id argPtr1 arg2) context (fromIntegral id) >>= newSource . castPtr
newtype Source = Source (ForeignPtr (Source))
newSource :: Ptr Source
          -> IO Source
newSource sourcePtr =
    liftM Source $ newForeignPtr sourcePtr sourceFinalizer
foreign import ccall unsafe "&g_source_unref"
    sourceFinalizer :: FunPtr (Ptr Source -> IO ())
sourceAttach :: Source
             -> MainContext
             -> IO HandlerId
sourceAttach source context =
    liftM fromIntegral $ (\(Source arg1) (MainContext arg2) -> withForeignPtr arg1 $ \argPtr1 ->withForeignPtr arg2 $ \argPtr2 ->g_source_attach argPtr1 argPtr2) source context
sourceSetPriority :: Source
                  -> Priority
                  -> IO ()
sourceSetPriority source priority =
    (\(Source arg1) arg2 -> withForeignPtr arg1 $ \argPtr1 ->g_source_set_priority argPtr1 arg2) source $ fromIntegral priority
sourceGetPriority :: Source
                  -> IO Priority
sourceGetPriority source =
    liftM fromIntegral $ (\(Source arg1) -> withForeignPtr arg1 $ \argPtr1 ->g_source_get_priority argPtr1) source
sourceDestroy :: Source
              -> IO ()
sourceDestroy source =
    (\(Source arg1) -> withForeignPtr arg1 $ \argPtr1 ->g_source_destroy argPtr1) source
sourceIsDestroyed :: Source
                  -> IO Bool
sourceIsDestroyed source =
    liftM toBool $ (\(Source arg1) -> withForeignPtr arg1 $ \argPtr1 ->g_source_is_destroyed argPtr1) source
sourceRemove :: HandlerId
             -> IO Bool
sourceRemove tag =
    liftM toBool $ g_source_remove $ fromIntegral tag
foreign import ccall unsafe "g_timeout_add_full"
  g_timeout_add_full :: (CInt -> (CUInt -> ((FunPtr ((Ptr ()) -> (IO CInt))) -> ((Ptr ()) -> ((FunPtr ((Ptr ()) -> (IO ()))) -> (IO CUInt))))))
foreign import ccall safe "g_source_remove"
  g_source_remove :: (CUInt -> (IO CInt))
foreign import ccall unsafe "g_idle_add_full"
  g_idle_add_full :: (CInt -> ((FunPtr ((Ptr ()) -> (IO CInt))) -> ((Ptr ()) -> ((FunPtr ((Ptr ()) -> (IO ()))) -> (IO CUInt)))))
foreign import ccall unsafe "g_io_channel_unix_new"
  g_io_channel_unix_new :: (CInt -> (IO (Ptr IOChannel)))
foreign import ccall unsafe "g_io_add_watch_full"
  g_io_add_watch_full :: ((Ptr IOChannel) -> (CInt -> (CInt -> ((FunPtr ((Ptr IOChannel) -> (CInt -> ((Ptr ()) -> (IO CInt))))) -> ((Ptr ()) -> ((FunPtr ((Ptr ()) -> (IO ()))) -> (IO CUInt)))))))
foreign import ccall safe "g_main_loop_new"
  g_main_loop_new :: ((Ptr MainContext) -> (CInt -> (IO (Ptr MainLoop))))
foreign import ccall safe "g_main_loop_run"
  g_main_loop_run :: ((Ptr MainLoop) -> (IO ()))
foreign import ccall safe "g_main_loop_quit"
  g_main_loop_quit :: ((Ptr MainLoop) -> (IO ()))
foreign import ccall safe "g_main_loop_is_running"
  g_main_loop_is_running :: ((Ptr MainLoop) -> (IO CInt))
foreign import ccall safe "g_main_loop_get_context"
  g_main_loop_get_context :: ((Ptr MainLoop) -> (IO (Ptr MainContext)))
foreign import ccall safe "g_main_context_new"
  g_main_context_new :: (IO (Ptr MainContext))
foreign import ccall safe "g_main_context_default"
  g_main_context_default :: (IO (Ptr MainContext))
foreign import ccall safe "g_main_context_iteration"
  g_main_context_iteration :: ((Ptr MainContext) -> (CInt -> (IO CInt)))
foreign import ccall safe "g_main_context_find_source_by_id"
  g_main_context_find_source_by_id :: ((Ptr MainContext) -> (CUInt -> (IO (Ptr ()))))
foreign import ccall safe "g_source_attach"
  g_source_attach :: ((Ptr Source) -> ((Ptr MainContext) -> (IO CUInt)))
foreign import ccall safe "g_source_set_priority"
  g_source_set_priority :: ((Ptr Source) -> (CInt -> (IO ())))
foreign import ccall safe "g_source_get_priority"
  g_source_get_priority :: ((Ptr Source) -> (IO CInt))
foreign import ccall safe "g_source_destroy"
  g_source_destroy :: ((Ptr Source) -> (IO ()))
foreign import ccall safe "g_source_is_destroyed"
  g_source_is_destroyed :: ((Ptr Source) -> (IO CInt))