content: {-# LANGUAGE PatternGuards #-}
  
  module Draw
          ( drawState
          , drawWorld)
  where
  import State
  import World
  import Graphics.Gloss
  import Graphics.Gloss.Geometry.Line
  import qualified Data.Vector.Unboxed    as V
  import Data.Maybe
  
  
  drawState :: State -> Picture
  drawState state
          | ModeDisplayWorld      <- stateModeDisplay state
          = drawWorldWithViewPos
                  (stateModeOverlay state)
                  (stateViewPos     state)
                  (stateTargetPos   state)
                  (stateWorld       state)
  
          | ModeDisplayNormalised <- stateModeDisplay state
          = drawWorldWithViewPos
                  (stateModeOverlay state)
                  (0, 0)
                  Nothing
                  $ normaliseWorld (stateViewPos state)
                  $ stateWorld state
  
          | otherwise
          = Blank
  
  
  drawWorldWithViewPos :: ModeOverlay -> Point -> Maybe Point -> World -> Picture
  drawWorldWithViewPos
          modeOverlay
          pView@(vx, vy)
          mTarget
          world
   = let
          -- the world
          picWorld        = Color white
                          $ drawWorld world
  
          -- view position indicator
          picView         = Color red
                          $ Translate vx vy
                          $ ThickCircle 2 4
  
          -- target position indicator
          picTargets
                  | Just pTarget@(px, py) <- mTarget
                  = let   picTarget       = Translate px py $ ThickCircle 2 4
  
                          -- line between view and target pos
                          picLine         = Line [pView, pTarget]
  
                          picSegsHit      = Pictures
                                          $ [ Line [p1, p2]
                                                  | (_, p1, p2)   <- V.toList $ worldSegments world
                                                  , isJust $ intersectSegSeg p1 p2 pView pTarget ]
                    in    Color red $ Pictures [picTarget, picLine, picSegsHit]
  
                  | otherwise
                  = blank
  
          -- overlay
          picOverlay
                  | ModeOverlayVisApprox  <- modeOverlay
                  = drawVisGrid 10 pView world
  
                  | otherwise
                  = blank
  
     in   Pictures [picOverlay, picWorld, picView, picTargets]
  
  
  -- | Draw a grid of points showing what is visible from a view position
  drawVisGrid :: Float -> Point -> World -> Picture
  drawVisGrid cellSize pView world
   = let
          visible pTarget = not $ any isJust
                          $ map (\(_, p1, p2) -> intersectSegSeg pView pTarget p1 p2)
                          $ V.toList
                          $ worldSegments world
  
          picGrid         = Pictures
                          $ [ if visible (x, y)
                                  then Color (dim green) $ Translate x y $ rectangleSolid cellSize cellSize
                                  else Color (greyN 0.2) $ Translate x y $ rectangleSolid cellSize cellSize
                                  | x     <- [-400, -400 + cellSize .. 400]
                                  , y     <- [-400, -400 + cellSize .. 400] ]
  
     in   picGrid
  
  
  -- | Draw the segments in the world.
  drawWorld :: World -> Picture
  drawWorld world
          = drawSegments
          $ worldSegments world
  
  
  -- | Draw an array of segments.
  drawSegments :: V.Vector Segment -> Picture
  drawSegments segments
          = Pictures
          $ map drawSegment
          $ V.toList
          $ segments
  
  
  -- | Draw a single segment.
  drawSegment :: Segment -> Picture
  drawSegment (_, (x1, y1), (x2, y2))
          = Line [(f x1, f y1), (f x2, f y2)]
          where   f       = fromRational . toRational
  
  