content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE PatternGuards #-}
  
  import Brillo.Data.Extent
  import Brillo.Data.QuadTree
  import Brillo.Interface.Pure.Game
  import Cell
  import Data
  import Data.Maybe
  import State
  import System.Environment
  import World
  
  
  main :: IO ()
  main =
    do
      args <- getArgs
      case args of
        [fileName] ->
          do
            world <- loadWorld fileName
            mainWithWorld world
        _ -> do
          let world = readWorld worldData
          mainWithWorld world
  
  
  mainWithWorld :: World -> IO ()
  mainWithWorld world =
    play
      ( InWindow
          "Occlusion"
          (windowSizeOfWorld world)
          (10, 10)
      )
      black
      10
      (initState world)
      drawState
      (handleInput world)
      (\_ -> id)
  
  
  -- | Convert the state to a picture.
  drawState :: State -> Picture
  drawState state =
    let world = stateWorld state
  
        -- The ray cast by the user.
        p1 = stateLineStart state
        p2 = stateLineEnd state
        picRay = drawRay world p1 p2
  
        -- The cell hit by the ray (if any)
        mHitCell = castSegIntoWorld world p1 p2
        hitCells = maybeToList mHitCell
        picCellsHit = Pictures $ map (drawHitCell world) hitCells
  
        -- All the cells in the world.
        cellsAll = flattenQuadTree (worldExtent world) (worldTree world)
        picCellsAll = Pictures $ map (uncurry (drawCell False world)) cellsAll
  
        -- The cells visible from the designated point.
        cellsVisible =
          [ (coord, cell)
          | (coord, cell) <- flattenQuadTree (worldExtent world) (worldTree world)
          , cellAtCoordIsVisibleFromPoint world p1 coord
          ]
  
        picCellsVisible = Pictures $ map (uncurry (drawCell True world)) cellsVisible
  
        -- How big to draw the cells.
        scale = fromIntegral $ worldCellSize world
  
        (windowSizeX, windowSizeY) =
          windowSizeOfWorld $
            stateWorld state
  
        -- Shift the cells so they are centered in the window.
        offsetX = -(fromIntegral $ windowSizeX `div` 2)
        offsetY = -(fromIntegral $ windowSizeY `div` 2)
    in  Translate offsetX offsetY $
          Scale scale scale $
            Pictures [picCellsAll, picCellsVisible, picCellsHit, picRay]
  
  
  -- | Draw the cell hit by the ray defined by the user.
  drawHitCell :: World -> (Point, Extent, Cell) -> Picture
  drawHitCell world (pos@(px, py), extent, cell) =
    let (n, s, e, w) = takeExtent extent
        x = w
        y = s
  
        posX = fromIntegral x
        posY = fromIntegral y
    in  Pictures [Color blue $ cellShape 1 posX posY]
  
  
  -- | Draw the ray defined by the user.
  drawRay :: World -> Point -> Point -> Picture
  drawRay world p1@(x, y) p2 =
    Pictures
      [ Color red $ Line [p1, p2]
      , Color cyan $
          Translate x y $
            Pictures
              [ Line [(-0.3, -0.3), (0.3, 0.3)]
              , Line [(-0.3, 0.3), (0.3, -0.3)]
              ]
      ]
  
  
  -- | Draw a cell in the world.
  drawCell :: Bool -> World -> Coord -> Cell -> Picture
  drawCell visible world (x, y) cell =
    let cs = fromIntegral (worldCellSize world)
        -- cp      = fromIntegral (worldCellSpace world)
  
        posX = fromIntegral x
        posY = fromIntegral y
    in  if visible
          then pictureOfCell (worldCellSize world) posX posY cell
          else Color (greyN 0.4) (cellShape cs posX posY)
  