{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies     #-}

module Apecs.Gloss
  ( module Apecs.Gloss
  , module G
  ) where

import           Data.Semigroup                   (Semigroup (..))
import           Graphics.Gloss.Interface.IO.Game as G
import           Linear.V2
import           Linear.Vector

import           Apecs

data Camera = Camera
  { camOffset :: V2 Float
  , camScale  :: Float
  } deriving (Eq, Show, Read)

instance Semigroup Camera where
  Camera x1 r1 <> Camera x2 r2 = Camera (x1 + x2) (r1 * r2)
instance Monoid Camera where
  mempty = Camera 0 1
  mappend = (<>)

-- | Apply a camera transformation to a picture
cameraTransform :: Camera -> Picture -> Picture
cameraTransform (Camera (V2 cx cy) cs) =
    Scale cs cs .  Translate (-cx) (-cy)

windowToWorld :: Camera -> (Float,Float) -> V2 Float
windowToWorld (Camera cx cs) (x,y) = V2 x y ^/ cs + cx

instance Component Camera where
  type Storage Camera = Global Camera

play
  :: (Has w IO Camera)
  => Display            -- ^ Display mode
  -> Color              -- ^ Background color
  -> Int                  -- ^ Desired FPS
  -> System w Picture -- ^ Drawing function
  -> (Event -> System w ()) -- ^ Event handling function
  -> (Float  -> System w ()) -- ^ Stepping function, with a time delta argument.
  -> System w ()
play disp col fps draw handle step = do
  w <- ask
  liftIO$ playIO disp col fps w draw' handle' step'
    where
      handle' event = runSystem $ handle event >> ask
      step'   dT    = runSystem $ step dT >> ask
      draw'         = runSystem $ do
        cam <- get global
        cameraTransform cam <$> draw

-- | Renders a picture given a component rendering function.
foldDraw :: (Get w IO c, Members w IO c)
         => (c -> Picture) -- ^ Component render function.
         -> System w Picture
foldDraw fn = cfold (\pic -> mappend pic . fn) mempty

-- | Monadically renders a picture given a component rendering function.
foldDrawM :: (Get w IO c, Members w IO c)
          => (c -> System w Picture) -- ^ Component render function.
          -> System w Picture
foldDrawM fn = cfoldM (\pic -> fmap (mappend pic) . fn) mempty