content: module Rain.Rain
      (updateRain,
       drawRain,
       rainRect,
       rainPoly) where
  
  import System.Random
  import Graphics.Rendering.OpenGL
  import World.World
  import Panels.MainPanel
  import Nxt.Types
  import Items.Items
  import Level.Level
  import Settings.RainSettings as RainSettings
  import Settings.WorldSettings as WorldSettings
  import Nxt.Graphics
  
  -- updateRain
  updateRain :: WorldState -> IO [Vector2d]
  updateRain worldState = do
      let rain = raindrops (mainPanel worldState)
          (cameraX, cameraY) = cameraPos (mainPanel worldState)
  
      let fallenRain = fallRain rain cameraY
  
      let spawnList = [(1.0 - cameraX)..(maxWorldX - cameraX)]
      let xPos = [x::Double | x <- spawnList, ceiling x `mod` rainSpacing == 0]
  
      gen <- newStdGen
  
      let lvlHeight = fromIntegral(levelHeight $ curLevel worldState)::Double
      let yPos = randomRs (lvlHeight - rainHeight - cameraY, lvlHeight - cameraY) gen
  
      let rainPositions = zip xPos yPos
  
      newRainSeq <- mapM createNewRain rainPositions
      let newRain = concat newRainSeq
  
      let totalRain = newRain ++ fallenRain
      let rainPolyCol = collideRainPoly totalRain (polySurfaces (mainPanel worldState))
      let rectSurfaces' = map itemRect (tarpList (mainPanel worldState))
                          ++
                          map itemRect (corkList (mainPanel worldState))
                          ++
                          rectSurfaces (mainPanel worldState)
      let rainRectCol = collideRainRect rainPolyCol rectSurfaces'
  
      return rainRectCol
  
  -- createNewRain
  createNewRain :: Vector2d -> IO [Vector2d]
  createNewRain rainPos = do
      raindropDiceRoll <- getStdRandom $ randomR (0::Int, rainSpawnChance)
  
      return [rainPos | raindropDiceRoll == 0]
  
  -- fallRain
  fallRain :: [Vector2d] -> Double -> [Vector2d]
  fallRain [] _ = []
  fallRain ((raindropX, raindropY) : rain) cameraY
      | raindropY > (-cameraY) = (raindropX, raindropY - rainFallSpeed) : fallRain rain cameraY
      | otherwise           = fallRain rain cameraY
  
  -- drawRain
  drawRain :: [Vector2d] -> IO ()
  drawRain [] = return ()
  drawRain ((raindropX, raindropY) : rain) = do
      renderPrimitive Quads $ do
          mapM_ color rainColor
          mapM_ vertex (raindropVertices raindropX raindropY)
      drawRain rain
  
  -- raindropVertices
  raindropVertices :: Double -> Double -> [Vertex3 GLdouble]
  raindropVertices x y =
      [Vertex3 x' y' 0.0,
       Vertex3 (x' + rainWidth') y' 0.0,
       Vertex3 (x' + rainWidth') (y' + rainHeight') 0.0,
       Vertex3 x' (y' + rainHeight') 0.0]
       where x' = toGLdouble x
             y' = toGLdouble y
             rainWidth' = toGLdouble rainWidth
             rainHeight' = toGLdouble rainHeight
  
  -- rainPoly
  rainPoly :: Vector2d -> Nxt.Types.Poly
  rainPoly (raindropX, raindropY) =
      Poly 3 [(raindropX,raindropY),
              (raindropX+RainSettings.rainWidth,raindropY),
              (raindropX+RainSettings.rainWidth,raindropY+RainSettings.rainHeight)]
  
  -- collideRainPoly
  collideRainPoly :: [Vector2d] -> [Nxt.Types.Poly] -> [Vector2d]
  collideRainPoly [] _ = []
  collideRainPoly (raindrop:rain) polys =
      if foldr (\poly -> (polyIntersect poly (rainPoly raindrop) ||)) False polys
         then
         collideRainPoly rain polys
         else
         raindrop : collideRainPoly rain polys
  
  -- rainRect
  rainRect :: Vector2d -> Nxt.Types.Rect
  rainRect (raindropX, raindropY) =
      Rect raindropX raindropY RainSettings.rainWidth RainSettings.rainHeight
  
  -- collideRainRect
  collideRainRect :: [Vector2d] -> [Nxt.Types.Rect] -> [Vector2d]
  collideRainRect [] _ = []
  collideRainRect (raindrop:rain) rects =
      if foldr ((||) . rectIntersect (rainRect raindrop)) False rects
         then
         collideRainRect rain rects
         else
         raindrop : collideRainRect rain rects
  
  