content: -- | Compile with: fay examples/canvaswater.hs
  
  {-# LANGUAGE EmptyDataDecls    #-}
  
  
  -- | A demonstration of Fay using the canvas element to display a
  -- simple effect.
  
  module CanvasWater (main) where
  
  import           FFI
  import           Prelude
  
  -- | Main entry point.
  main :: Fay ()
  main = do
    img <- newImage
    addEventListener img "load" (start img) False
    setSrc img "haskell.png"
  
  -- | Start the animation.
  start :: Image -> Fay ()
  start img = do
    canvas <- getElementById "can"
    context <- getContext canvas "2d"
    drawImage context img 0 0
    step <- newRef (0 :: Double)
    setInterval (animate context img step) 30
  
  -- | Animate the water effect.
  animate :: Context -> Image -> Ref Double -> Fay ()
  animate context img step = do
    stepn <- readRef step
    setFillStyle context "rgb(255,255,255)"
    forM_ [0..imgHeight] $ \i ->
      drawImageSpecific context img
                        0 0
                        imgWidth imgHeight
                        (sin(3*(stepn+i/20.0))*(i/2.0)) (140+i)
                        imgWidth imgHeight
    writeRef step (stepn + 0.05)
  
  imgHeight = 140
  imgWidth = 200
  
  --------------------------------------------------------------------------------
  -- Elements
  
  class Eventable a
  
  -- | A DOM element.
  data Element
  instance Eventable Element
  
  -- | Add an event listener to an element.
  addEventListener :: (Eventable a) => a -> String -> Fay () -> Bool -> Fay ()
  addEventListener = ffi "%1['addEventListener'](%2,%3,%4)"
  
  -- | Get an element by its ID.
  getElementById :: String -> Fay Element
  getElementById = ffi "document['getElementById'](%1)"
  
  --------------------------------------------------------------------------------
  -- Images
  
  data Image
  instance Eventable Image
  
  -- | Make a new image.
  newImage :: Fay Image
  newImage = ffi "new Image()"
  
  -- | Make a new image.
  setSrc :: Image -> String -> Fay ()
  setSrc = ffi "%1['src'] = %2"
  
  --------------------------------------------------------------------------------
  -- Canvas
  
  -- | A canvas context.
  data Context
  
  -- | Get an element by its ID.
  getContext :: Element -> String -> Fay Context
  getContext = ffi "%1['getContext'](%2)"
  
  -- | Draw an image onto a canvas rendering context.
  drawImage :: Context -> Image -> Double -> Double -> Fay ()
  drawImage = ffi "%1['drawImage'](%2,%3,%4)"
  
  -- | Draw an image onto a canvas rendering context.
  --
  --   Nine arguments: the element, source (x,y) coordinates, source width and
  --   height (for cropping), destination (x,y) coordinates, and destination width
  --   and height (resize).
  --
  --   context.drawImage(img_elem, sx, sy, sw, sh, dx, dy, dw, dh);
  drawImageSpecific :: Context -> Image
                    -> Double -> Double -> Double -> Double -> Double -> Double -> Double -> Double
                    -> Fay ()
  drawImageSpecific = ffi "%1['drawImage'](%2,%3,%4,%5,%6,%7,%8,%9,%10)"
  
  -- | Set the fill style.
  setFillStyle :: Context -> String -> Fay ()
  setFillStyle = ffi "%1['fillStyle']=%2"
  
  -- | Set the fill style.
  setFillRect :: Context -> Double -> Double -> Double -> Double -> Fay ()
  setFillRect = ffi "%1['fillRect'](%2,%3,%4,%5)"
  
  --------------------------------------------------------------------------------
  -- Ref
  
  -- | A mutable reference like IORef.
  data Ref a
  
  -- | Make a new mutable reference.
  newRef :: a -> Fay (Ref a)
  newRef = ffi "new Fay$$Ref(%1)"
  
  -- | Replace the value in the mutable reference.
  writeRef :: Ref a -> a -> Fay ()
  writeRef = ffi "Fay$$writeRef(%1,%2)"
  
  -- | Get the referred value from the mutable value.
  readRef :: Ref a -> Fay a
  readRef = ffi "Fay$$readRef(%1)"
  
  --------------------------------------------------------------------------------
  -- Misc
  
  -- | Alert using window.alert.
  alert :: a -> Fay ()
  alert = ffi "window['alert'](%1)"
  
  -- | Alert using window.alert.
  print :: Double -> Fay ()
  print = ffi "console['log'](%1)"
  
  -- | Alert using window.alert.
  log :: String -> Fay ()
  log = ffi "console['log'](%1)"
  
  -- | Alert using window.alert.
  setInterval :: Fay () -> Double -> Fay ()
  setInterval = ffi "window['setInterval'](%1,%2)"
  