{-# LANGUAGE TypeFamilies, GADTs, FlexibleInstances, ForeignFunctionInterface,
             CPP #-}
-- | Event handlers for Haste.App. If you're using Haste.App, you should use
--   the functions provided by this module rather than the ones from
--   Haste.Callback.
module Haste.App.Events (
    ClientCallback, CB.Event (..),
    onEvent, setTimeout, CB.evtName
  ) where
import qualified Haste.Callback as CB
import Haste.App.Client
import Haste.Concurrent
import Haste.DOM

-- | Bake a value of type a -> ... -> Client b into a -> ... -> IO b
class ClientCallback a where
  type T a
  cbify :: ClientState -> a -> T a

instance ClientCallback (Client ()) where
  type T (Client ()) = IO ()
  cbify cs = concurrent . runClientCIO cs

instance ClientCallback b => ClientCallback (a -> b) where
  type T (a -> b) = a -> T b
  cbify cs f = \x -> cbify cs (f x)

-- | Set a handler for a given event.
onEvent :: ClientCallback a => Elem -> CB.Event Client a -> a -> Client ()
onEvent e evt f = do
    cs <- get id
    _ <- liftIO . CB.jsSetCB e (CB.evtName evt) . CB.mkCallback $! cbify cs f
    return ()

-- | Wrapper for window.setTimeout; execute the given computation after a delay
--   given in milliseconds.
setTimeout :: Int -> Client () -> Client ()
setTimeout delay cb = do
  cs <- get id
  liftIO $ CB.jsSetTimeout delay (CB.mkCallback $! cbify cs cb)