{-# LINE 1 "System/Libnotify/Internal.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "System/Libnotify/Internal.hsc" #-}
-- | System.Libnotify.Internal module is low level c-bindings to Libnotify.
-- No API stability is guaranteed.
{-# OPTIONS_HADDOCK hide #-}


{-# LINE 7 "System/Libnotify/Internal.hsc" #-}

module System.Libnotify.Internal
  ( Notification
  , initNotify, uninitNotify, isInitted
  , newNotify, updateNotify, showNotify
  , setTimeout, setCategory, setUrgency
  , setIconFromPixbuf, setImageFromPixbuf
  , setHintInt32, setHintDouble, setHintString, setHintByte, setHintByteArray, clearHints
  , addAction, clearActions, closeNotify
  ) where

import Control.Exception (throw)
import Foreign
import Foreign.C
import Graphics.UI.Gtk.Gdk.Pixbuf
import System.Glib.GError (GError)
import Unsafe.Coerce
import qualified Data.ByteString as BS

import System.Libnotify.Types

-- | Notification session pointer
newtype Notification = Notification (Ptr Notification)

initNotify :: String -> IO Bool
initNotify appName =
  withCString appName $ \p_appName ->
  notify_init p_appName

foreign import ccall unsafe "libnotify/notify.h notify_init"
  notify_init :: CString -> IO Bool

uninitNotify :: IO ()
uninitNotify = notify_uninit

foreign import ccall unsafe "libnotify/notify.h notify_uninit"
  notify_uninit :: IO ()

isInitted :: IO Bool
isInitted = notify_is_initted

foreign import ccall unsafe "libnotify/notify.h notify_is_initted"
  notify_is_initted :: IO Bool

type ActionCallback a = Notification -> CString -> Ptr a -> IO ()
type FreeFunc a = Ptr a -> IO ()

newNotify :: String -> Maybe String -> Maybe String -> IO Notification
newNotify summary body icon =
  withCString summary        $ \p_summary ->
  maybeWith withCString body $ \p_body ->
  maybeWith withCString icon $ \p_icon ->
  notify_notification_new p_summary p_body p_icon

foreign import ccall unsafe "libnotify/notify.h notify_notification_new"
  notify_notification_new :: CString
                          -> CString
                          -> CString
                          -> IO Notification

updateNotify :: Notification -> String -> Maybe String -> Maybe String -> IO Bool
updateNotify notify summary body icon =
  withCString summary        $ \p_summary ->
  maybeWith withCString body $ \p_body ->
  maybeWith withCString icon $ \p_icon ->
  notify_notification_update notify p_summary p_body p_icon

foreign import ccall unsafe "libnotify/notify.h notify_notification_update"
  notify_notification_update :: Notification
                             -> CString
                             -> CString
                             -> CString -> IO Bool

showNotify :: Notification -> IO Bool
showNotify notify =
  alloca $ \pp_error -> do
  poke pp_error nullPtr
  result <- notify_notification_show notify pp_error
  p_error <- peek pp_error
  if p_error == nullPtr
    then return result
    else do gerror <- peek p_error
            g_error_free p_error
            throw gerror

foreign import ccall unsafe "libnotify/notify.h notify_notification_show"
  notify_notification_show :: Notification -> Ptr (Ptr GError) -> IO Bool

foreign import ccall unsafe "glib-object.h g_error_free"
  g_error_free :: Ptr GError -> IO ()

setTimeout :: Timeout -> Notification -> IO ()
setTimeout timeout notify =
  notify_notification_set_timeout notify (getTimeout timeout)
  where getTimeout :: Timeout -> CInt
        getTimeout Default    = -1
{-# LINE 103 "System/Libnotify/Internal.hsc" #-}
        getTimeout Infinite   = 0
{-# LINE 104 "System/Libnotify/Internal.hsc" #-}
        getTimeout (Custom t) = fromIntegral t

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_timeout"
  notify_notification_set_timeout :: Notification -> CInt -> IO ()

setCategory :: Category -> Notification -> IO ()
setCategory category notify =
  withCString category $ \p_category ->
  notify_notification_set_category notify p_category

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_category"
  notify_notification_set_category :: Notification -> CString -> IO ()

setUrgency :: Urgency -> Notification -> IO ()
setUrgency urgency notify =
  notify_notification_set_urgency notify (getUrgency urgency)
  where getUrgency :: Urgency -> CInt
        getUrgency Low      = 0
{-# LINE 122 "System/Libnotify/Internal.hsc" #-}
        getUrgency Normal   = 1
{-# LINE 123 "System/Libnotify/Internal.hsc" #-}
        getUrgency Critical = 2
{-# LINE 124 "System/Libnotify/Internal.hsc" #-}

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_urgency"
  notify_notification_set_urgency :: Notification -> CInt -> IO ()

setIconFromPixbuf :: Pixbuf -> Notification -> IO ()
setIconFromPixbuf pixbuf notify =
  withForeignPtr (unsafeCoerce pixbuf) $ \p_pixbuf ->
  notify_notification_set_icon_from_pixbuf notify p_pixbuf

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_icon_from_pixbuf"
  notify_notification_set_icon_from_pixbuf :: Notification
                                           -> Ptr Pixbuf
                                           -> IO ()

setImageFromPixbuf :: Pixbuf -> Notification -> IO ()
setImageFromPixbuf pixbuf notify =
  withForeignPtr (unsafeCoerce pixbuf) $ \p_pixbuf ->
  notify_notification_set_image_from_pixbuf notify p_pixbuf

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_image_from_pixbuf"
  notify_notification_set_image_from_pixbuf :: Notification
                                            -> Ptr Pixbuf
                                            -> IO ()

setHintInt32 :: String -> Int32 -> Notification -> IO ()
setHintInt32 key value notify =
  withCString key $ \p_key ->
  notify_notification_set_hint_int32 notify p_key (fromIntegral value)

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_hint_int32"
  notify_notification_set_hint_int32 :: Notification
                                     -> CString
                                     -> CInt
                                     -> IO ()

setHintDouble :: String -> Double -> Notification -> IO ()
setHintDouble key value notify =
  withCString key $ \p_key ->
  notify_notification_set_hint_double notify p_key (realToFrac value)

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_hint_double"
  notify_notification_set_hint_double :: Notification
                                      -> CString
                                      -> CDouble
                                      -> IO ()

setHintString :: String -> String -> Notification -> IO ()
setHintString key value notify =
  withCString key   $ \p_key ->
  withCString value $ \p_value ->
  notify_notification_set_hint_string notify p_key p_value

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_hint_string"
  notify_notification_set_hint_string :: Notification
                                      -> CString
                                      -> CString
                                      -> IO ()

setHintByte :: String -> Word8 -> Notification -> IO ()
setHintByte key value notify =
  withCString key $ \p_key ->
  notify_notification_set_hint_byte notify p_key (fromIntegral value)

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_hint_byte"
  notify_notification_set_hint_byte :: Notification
                                    -> CString
                                    -> CUChar
                                    -> IO ()

setHintByteArray :: String -> BS.ByteString -> Notification -> IO ()
setHintByteArray key value notify =
  withCString key $ \p_key ->
  withArrayLen (BS.foldr' step [] value) $ \len p_bs ->
  notify_notification_set_hint_byte_array notify p_key p_bs (fromIntegral len)
    where
      step x xs = fromIntegral x:xs

foreign import ccall unsafe "libnotify/notify.h notify_notification_set_hint_byte_array"
  notify_notification_set_hint_byte_array :: Notification
                                          -> CString
                                          -> Ptr CUChar
                                          -> CSize
                                          -> IO ()

clearHints :: Notification -> IO ()
clearHints = notify_notification_clear_hints

foreign import ccall unsafe "libnotify/notify.h notify_notification_clear_hints"
  notify_notification_clear_hints :: Notification -> IO ()

addAction
  :: String
  -> String
  -> (Notification -> String -> IO ())
  -> Notification
  -> IO ()
addAction action label callback notify =
  withCString action $ \p_action ->
  withCString label  $ \p_label -> do
    p_callback <- wrapActionCallback $ makeCallback callback
    notify_notification_add_action notify
                                   p_action
                                   p_label
                                   p_callback
                                   nullPtr
                                   nullFunPtr
  where
    makeCallback callback = \notify p_action _ -> do
      action <- peekCString p_action
      callback notify action

foreign import ccall "wrapper"
  wrapActionCallback :: (ActionCallback a) -> IO (FunPtr (ActionCallback a))

foreign import ccall "wrapper"
  wrapFreeFunc :: (FreeFunc a) -> IO (FunPtr (FreeFunc a))

foreign import ccall unsafe "libnotify/notify.h notify_notification_add_action"
  notify_notification_add_action :: Notification
                                 -> CString
                                 -> CString
                                 -> FunPtr (ActionCallback a)
                                 -> Ptr a
                                 -> FunPtr (FreeFunc a)
                                 -> IO ()

clearActions :: Notification -> IO ()
clearActions = notify_notification_clear_actions

foreign import ccall unsafe "libnotify/notify.h notify_notification_clear_actions"
  notify_notification_clear_actions :: Notification -> IO ()

closeNotify :: Notification -> IO Bool
closeNotify notify =
  alloca $ \pp_error -> do
  poke pp_error nullPtr
  result <- notify_notification_close notify pp_error
  p_error <- peek pp_error
  if p_error == nullPtr
    then return result
    else do gerror <- peek p_error
            g_error_free p_error
            throw gerror

foreign import ccall unsafe "libnotify/notify.h notify_notification_close"
  notify_notification_close :: Notification -> Ptr (Ptr GError) -> IO Bool