packages feed

proplang-0.1: PropLang/Event.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Event.hs
-- Copyright   :  (c) Neil Mitchell 2007
-- License     :
--
-- Maintainer  :
-- Stability   :  unstable
-- Portability :  not portable
--
-- PropLang events
--
-----------------------------------------------------------------------------

module PropLang.Event(
    Eventer(..), Event, newEvent, newEventName,
    EventHandle, (+=), remove,
    raise,
    blockEvent, unblockEvent
    ) where

import Control.Monad
import Data.IORef

debug = putStrLn

-- |
class Eventer a where
    event :: a -> Event

instance Eventer Event where
    event = id


-- | Event type. 
data Event = Event
                String --  Event Name
		(IORef Bool) --  Enable flag
                (IORef Integer) --  Next action index
                (IORef [(Integer, IO ())]) --  List of indices and actions

-- | EventHandle type.
--   Stores an Event and action index.
data EventHandle = EventHandle Event Integer


-- | Create a new Event.
newEvent :: IO Event
newEvent = newEventName ""

-- | Create a new Event with a name.
newEventName :: String -> IO Event
newEventName name = do
    debug $ "Creating event: " ++ name
    a <- newIORef True
    n <- newIORef 0
    xs <- newIORef []
    return $ Event name a n xs


-- | Attach an action to an Event.
(+=) :: Eventer a => a -> IO () -> IO EventHandle
(+=) e x = do
    let Event name a n xs = event e
    n2 <- readIORef n
    writeIORef n (n2+1)
    xs2 <- readIORef xs
    writeIORef xs ((n2,x) : xs2)
    debug $ "Added to event, now at " ++ show (length xs2+1) ++ ": " ++ name
    return $ EventHandle (event e) n2

-- | Remove an action from an Event.
remove :: EventHandle -> IO ()
remove (EventHandle e x) = do
    let Event name a n xs = event e
    xs2 <- readIORef xs
    writeIORef xs [(a,b) | (a,b) <- xs2, a /= x]
    debug $ "Removed from event, now at " ++ show (length xs2-1) ++ ": " ++ name


-- | Raise an Event.
raise :: Eventer a => a -> IO ()
raise e = do
    let Event name a n xs = event e
    active <- readIORef a
    if active then do
      xs2 <- readIORef xs
      debug $ "Raising event, " ++ show (length xs2) ++ ": " ++ name
      mapM_ snd xs2
     else 
      debug $ "Not rasing disabled event: " ++ name


-- | Block an Event.
blockEvent :: Event -> IO ()
blockEvent (Event _ a _ _) = writeIORef a False

-- | Unblock an Event.
unblockEvent :: Event -> IO ()
unblockEvent (Event _ a _ _) = writeIORef a True