content: module World.World
      (WorldState(WorldState),
       gameState,
       keysStateRef,
       mousePosRef,
       curLevel,
       mainPanel,
       itemPanel,
       messagePanel,
       menuTextures,
       updateMessagePanel,
       updateItem,
       loadLevel,
       loadLevelBackgrounds) where
  
  import qualified Graphics.UI.GLUT as Glut
  import Data.IORef
  import Input.InputState as InputState
  import Panels.MainPanel hiding (itemList)
  import Panels.ItemPanel
  import Panels.MessagePanel
  import Items.Items
  import Level.Level
  import Level.FireHydrant
  import Level.EndMarker
  import Game.GameState
  import Nxt.Types
  import Cat.Cat
  import Nxt.Graphics
  import Settings.Path
  
  data WorldState = WorldState
      {
          gameState       :: GameState,
          keysStateRef    :: IORef InputState.KeysState,
          mousePosRef     :: IORef InputState.MousePos,
          curLevel        :: Level,
          mainPanel       :: MainPanel,
          itemPanel       :: ItemPanel,
          messagePanel    :: MessagePanel,
          menuTextures    :: (Nxt.Types.Texture, Nxt.Types.Texture)
      }
  
  -- updateMessagePanel
  updateMessagePanel :: WorldState -> IO MessagePanel
  updateMessagePanel worldState = do
      mousePos <- readIORef (mousePosRef worldState)
      Glut.Size winW winH <- Glut.get Glut.windowSize
      let (mousex, mousey) = translateMousePos mousePos winW winH
      let mousePos' = MousePos (floor mousex) (floor mousey)
      let itemList = itemButtonList (itemPanel worldState)
  
      let messageDisplay' = foldr (\item str -> if mouseOverItemBut mousePos' item then itemButDesc item else str) "" itemList
  
      return (MessagePanel messageDisplay')
  
  -- updateItem
  updateItem :: WorldState -> IO Item
  updateItem worldState = do
      mousePos <- readIORef (mousePosRef worldState)
      Glut.Size winW winH <- Glut.get Glut.windowSize
      let (mousex, mousey) = translateMousePos mousePos winW winH
      let mousePos' = MousePos (floor mousex) (floor mousey)
      let itemList = itemButtonList (itemPanel worldState)
      let cItem = curItem (mainPanel worldState)
      let newitem = foldr (\itemB r -> if mouseOverItemBut mousePos' itemB then itemButItem itemB else r) cItem itemList
      return newitem
  
  -- updateItemCounts
  updateItemCounts :: [ItemButton] -> [Int] -> [ItemButton]
  updateItemCounts itemBtnList itemCounts =
      map (\(itemBut, count) -> itemBut {itemButCount = count}) (zip (init itemBtnList) itemCounts)
      ++
      [last itemBtnList]
  
  -- loadLevel
  loadLevel :: WorldState -> String -> IO WorldState
  loadLevel worldState levelPath = do
      lvl <- openLevel levelPath
      let lvlData = levelData lvl
          lvlRect = levelRects lvlData
          lvlPoly = levelPolys lvlData
          lvlPuddles = levelPuddles lvlData
          lvlEndRect = levelEnd lvlData
          lvlFireHydrantsL = levelFireHydrantsL lvlData
          lvlFireHydrantsR = levelFireHydrantsR lvlData
          lvlItemCounts = levelItemCounts lvl
          catStartRect = levelCat lvlData
          catStart = (rectX catStartRect, rectY catStartRect)
      lvlFireHydrants <- sequence $ map (\fhRect -> initFireHydrant (rectX fhRect, rectY fhRect) DirLeft) lvlFireHydrantsL
                                    ++
                                    map (\fhRect -> initFireHydrant (rectX fhRect, rectY fhRect) DirRight) lvlFireHydrantsR
      levelend <- initEndMarker (rectX lvlEndRect, rectY lvlEndRect)
  
      let cat' = (cat $ mainPanel worldState) {catPos = catStart}
  
      let initCameraPos = (0, 0)
          item = itemButItem $ last $ itemButtonList $ itemPanel worldState
          m = musak $ mainPanel worldState
  
      -- update item button limits/uses
      let itemButtonList' = updateItemCounts (itemButtonList $ itemPanel worldState) lvlItemCounts
  
      let curBGTex = backgroundTexture $ mainPanel worldState
          mainPanel' = MainPanel initCameraPos [] curBGTex cat' lvlRect lvlPoly lvlPuddles lvlFireHydrants levelend [] [] [] item Nothing m
          goStopBtn = goStopButton $ itemPanel worldState
          itemPanel' = (itemPanel worldState) {itemButtonList = itemButtonList', goStopButton = goStopBtn {goStopState = GoState}}
  
      return (worldState {curLevel = lvl, mainPanel = mainPanel', itemPanel = itemPanel',
                          gameState = GameRunningState})
  
  -- loadLevelBackgrounds (NO TIME TO IMPLEMENT THIS IN FILE FORMAT PROPERLY!)
  loadLevelBackgrounds :: String -> Level -> IO [(Vector2d, Nxt.Types.Texture)]
  loadLevelBackgrounds levelPath _ = do
      dataPath <- getDataDir
      -- let lvlData = levelData level
  
      -- this doesn't seem to actually do anything..
      -- free previous level's textures
      -- mapM_ (\(_, oldBg) -> freeTexture oldBg) (levelBackgrounds lvlData)
  
      let lvlPos = case drop (length dataPath) levelPath of
                      "/data/levels/water1/water1.lvl"         -> [(0.0, 0.0), (1024.0, 0.0)]
                      "/data/levels/movement1/movement1.lvl"   -> [(-15.0, -265.0), (1009.0, -265.0), (2033, -265.0)]
                      "/data/levels/water2/water2.lvl"         -> [(0.0, -200.0), (1024.0, -200.0)]
                      "/data/levels/movement2/movement2.lvl"   -> [(5.0, -70.0), (1029.0, -70.0)]
                      "/data/levels/pool/pool.lvl"             -> [(53.0, -295.0), (1077.0, -295.0)]
                      "/data/levels/rift/rift.lvl"             -> [(10.0, -545.0), (1034.0, -545.0), (10.0, 479.0), (1034.0, 479.0)]
                      "/data/levels/skyline/skyline.lvl"       -> [(-40.0, -685.0), (984.0, -685.0), (2008.0, -685.0),
                                                                      (-40.0, 339.0), (984.0, 339.0), (2008.0, 339.0)]
                      "/data/levels/river/river.lvl"           -> [(10.0, -315.0), (1034.0, -315.0), (2058.0, -315.0)]
                      "/data/levels/pinball/pinball.lvl"       -> [(110.0, -330.0), (1134.0, -330.0)]
                      _                                        -> []
  
      lvlBgs <- case drop (length dataPath) levelPath of
                   "/data/levels/water1/water1.lvl"        -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/water1/water1_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/water1/water1_1_0.png")]
                   "/data/levels/movement1/movement1.lvl"  -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/movement1/movement1_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/movement1/movement1_1_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/movement1/movement1_2_0.png")]
                   "/data/levels/water2/water2.lvl"        -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/water2/water2_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/water2/water2_1_0.png")]
                   "/data/levels/movement2/movement2.lvl"  -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/movement2/movement2_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/movement2/movement2_1_0.png")]
                   "/data/levels/pool/pool.lvl"            -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/pool/pool_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/pool/pool_1_0.png")]
                   "/data/levels/rift/rift.lvl"            -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/rift/rift_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/rift/rift_1_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/rift/rift_0_1.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/rift/rift_1_1.png")]
                   "/data/levels/skyline/skyline.lvl"      -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/skyline/skyline_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/skyline/skyline_1_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/skyline/skyline_2_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/skyline/skyline_0_1.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/skyline/skyline_1_1.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/skyline/skyline_2_1.png")]
                   "/data/levels/river/river.lvl"          -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/river/river_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/river/river_1_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/river/river_2_0.png")]
                   "/data/levels/pinball/pinball.lvl"      -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/pinball/pinball_0_0.png"),
                                                                           Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/pinball/pinball_1_0.png")]
                   -- HACK FIX:This is warning fix and might be usefull if variable levels count can be used.
                   -- Image unknown.png doesn't exist, so exeption will be raised.
                   _                                       -> sequence [Nxt.Graphics.loadTexture (dataPath ++ "/data/levels/unknown_level/unknown.png")]
  
      return (zip lvlPos lvlBgs)
  
  