-- Adapted from the Yampa package.
-- Displays a square moving in a circle. To move the position drag it with the
-- mouse.
--
-- Requires the SDL package, assuming streamly has already been built, you can
-- compile it like this:
-- stack ghc --package SDL CirclingSquare.hs

import Data.IORef
import Graphics.UI.SDL as SDL
import Streamly
import Streamly.Prelude as S

------------------------------------------------------------------------------
-- SDL Graphics Init
------------------------------------------------------------------------------

sdlInit :: IO ()
sdlInit = do
  SDL.init [InitVideo]

  let width  = 640
      height = 480
  _ <- SDL.setVideoMode width height 16 [SWSurface]
  SDL.setCaption "Test" ""

------------------------------------------------------------------------------
-- Display a box at a given coordinates
------------------------------------------------------------------------------

display :: (Double, Double) -> IO ()
display (playerX, playerY) = do
  screen <- getVideoSurface

  -- Paint screen green
  let format = surfaceGetPixelFormat screen
  bgColor <- mapRGB format 55 60 64
  _ <- fillRect screen Nothing bgColor

  -- Paint small red square, at an angle 'angle' with respect to the center
  foreC <- mapRGB format 212 108 73
  let side = 20
      x = round playerX
      y = round playerY
  _ <- fillRect screen (Just (Rect x y side side)) foreC

  -- Double buffering
  SDL.flip screen

------------------------------------------------------------------------------
-- Wait and update Controller Position if it changes
------------------------------------------------------------------------------

updateController :: IORef (Double, Double) -> IO ()
updateController ref = do
    e <- pollEvent
    case e of
        MouseMotion x y _ _ -> writeIORef ref (fromIntegral x, fromIntegral y)
        _ -> return ()

------------------------------------------------------------------------------
-- Periodically refresh the output display
------------------------------------------------------------------------------

updateDisplay :: IORef (Double, Double) -> IO ()
updateDisplay cref = do
    time <- SDL.getTicks
    (x, y) <- readIORef cref
    let t = fromIntegral time * speed / 1000
     in display (x + cos t * radius, y + sin t * radius)

    where

    speed  = 6
    radius = 60

main :: IO ()
main = do
    sdlInit
    cref <- newIORef (0,0)
    S.drain $ asyncly $ constRate 40
        $ S.repeatM (updateController cref)
              `parallel` S.repeatM (updateDisplay cref)