-----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.HGL.Internals.Draw
-- Copyright   :  (c) Alastair Reid, 1999-2003
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  internal
-- Portability :  non-portable (requires concurrency)
--
-- Drawing in a simple graphics library.
--
-----------------------------------------------------------------------------

-- #hide
module Graphics.HGL.Internals.Draw
	( Graphic	-- = Draw ()
	, Draw
	, ioToDraw	-- :: IO a -> Draw a

	, bracket	-- :: Draw a -> (a -> Draw b) -> (a -> Draw c) -> Draw c
	, bracket_	-- :: Draw a -> (a -> Draw b) -> Draw c -> Draw c

	, unDraw	-- :: Draw a -> (DC -> IO a)
	, mkDraw 	-- :: (DC -> IO a) -> Draw a
	) where

#if !X_DISPLAY_MISSING
import Graphics.HGL.X11.Types(DC)
#else
import Graphics.HGL.Win32.Types(DC)
#endif
import qualified Graphics.HGL.Internals.Utilities as Utils (bracket, bracket_)
import Control.Monad (liftM)

----------------------------------------------------------------
-- Graphics
----------------------------------------------------------------

-- | An abstract representation of an image.
type Graphic = Draw ()

-- | Monad for sequential construction of images.
newtype Draw a = MkDraw (DC -> IO a)

unDraw :: Draw a -> (DC -> IO a)
unDraw (MkDraw m) = m

-- | Embed an 'IO' action in a drawing action.
ioToDraw :: IO a -> Draw a
ioToDraw m = MkDraw (\ _ -> m)

mkDraw :: (DC -> IO a) -> Draw a
mkDraw = MkDraw

-- a standard reader monad
instance Monad Draw where
  return a = MkDraw (\ hdc -> return a)
  m >>= k  = MkDraw (\ hdc -> do { a <- unDraw m hdc; unDraw (k a) hdc })
  m >>  k  = MkDraw (\ dc -> do { unDraw m dc; unDraw k dc })

instance Functor Draw where fmap = liftM

-- | Wrap a drawing action in initialization and finalization actions.
bracket
  :: Draw a		-- ^ a pre-operation, whose value is passed to the
			-- other two components.
  -> (a -> Draw b)	-- ^ a post-operation, to be performed on exit from
			-- the bracket, whether normal or by an exception.
  -> (a -> Draw c)	-- ^ the drawing action inside the bracket.
  -> Draw c
bracket left right m = MkDraw (\ hdc ->
  Utils.bracket (unDraw left hdc) 
                (\ a -> unDraw (right a) hdc)
                (\ a -> unDraw (m a) hdc))

-- | A variant of 'bracket' in which the inner drawing action does not
-- use the result of the pre-operation.
bracket_
  :: Draw a		-- ^ a pre-operation, whose value is passed to the
			-- other two components.
  -> (a -> Draw b)	-- ^ a post-operation, to be performed on exit from
			-- the bracket, whether normal or by an exception.
  -> Draw c		-- ^ the drawing action inside the bracket.
  -> Draw c
bracket_ left right m = MkDraw (\ hdc ->
  Utils.bracket_ (unDraw left hdc) 
                 (\ a -> unDraw (right a) hdc)
                 (unDraw m hdc))

----------------------------------------------------------------