module Menu.Menu
    (menuMain,
     menuDraw,
     howtoMain,
     howtoDraw) where

import Graphics.Rendering.OpenGL as GL hiding (get)
import qualified Graphics.UI.GLUT as Glut
import Data.IORef
import Data.Time.Clock
import World.World
import Nxt.Graphics
import Nxt.Types
import Settings.DisplaySettings
import Game.GameState
import Input.InputState
import Control.Monad.State
import Level.Level
import Settings.Path

howtoRect :: Nxt.Types.Rect
backRect  :: Nxt.Types.Rect
lvl1Rect  :: Nxt.Types.Rect
lvl2Rect  :: Nxt.Types.Rect
lvl3Rect  :: Nxt.Types.Rect
lvl4Rect  :: Nxt.Types.Rect
lvl5Rect  :: Nxt.Types.Rect
lvl6Rect  :: Nxt.Types.Rect
lvl7Rect  :: Nxt.Types.Rect
lvl8Rect  :: Nxt.Types.Rect
lvl9Rect  :: Nxt.Types.Rect

howtoRect = Nxt.Types.Rect 690.0 470.0 200.0 60.0
backRect  = Nxt.Types.Rect 785.0 626.0 200.0 60.0

lvl1Rect = Nxt.Types.Rect 543.0 245.0 90.0 90.0
lvl2Rect = Nxt.Types.Rect 649.0 245.0 90.0 90.0
lvl3Rect = Nxt.Types.Rect 753.0 245.0 90.0 90.0
lvl4Rect = Nxt.Types.Rect 543.0 140.0 90.0 90.0
lvl5Rect = Nxt.Types.Rect 649.0 140.0 90.0 90.0
lvl6Rect = Nxt.Types.Rect 753.0 140.0 90.0 90.0
lvl7Rect = Nxt.Types.Rect 543.0  37.0 90.0 90.0
lvl8Rect = Nxt.Types.Rect 649.0  37.0 90.0 90.0
lvl9Rect = Nxt.Types.Rect 753.0  37.0 90.0 90.0

-- menuMain
menuMain :: IORef WorldState -> (IORef WorldState -> IO ()) -> IO ()
menuMain worldStateRef mainCallback = do
    dataPath   <- getDataDir
    startTime  <- getCurrentTime

    worldState <- readIORef worldStateRef
    keys'      <- readIORef (keysStateRef worldState)

    Size winW winH <- Glut.get Glut.windowSize
    mousePos <- readIORef (mousePosRef worldState)
    let (mousex, mousey) = translateMousePos mousePos winW winH

    let gameState' = if pointInRect (mousex, mousey) howtoRect && lMouseDown keys'
                        then HowtoMenuState
                        else MainMenuState

    worldState' <- execStateT (do
                                    -- level 1
                                    w1 <- get
                                    lvl1 <- if pointInRect (mousex, mousey) lvl1Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w1 (dataPath ++ "/data/levels/water1/water1.lvl")
                                                else return w1
                                    lvl1Bg <- if pointInRect (mousex, mousey) lvl1Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/water1/water1.lvl") (curLevel lvl1)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl1
                                    put (lvl1 {curLevel = (curLevel lvl1) {levelData = (levelData (curLevel lvl1)) {levelBackgrounds = lvl1Bg}}})

                                    -- level 2
                                    w2 <- get
                                    lvl2 <- if pointInRect (mousex, mousey) lvl2Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w2 (dataPath ++ "/data/levels/movement1/movement1.lvl")
                                                else return w2
                                    lvl2Bg <- if pointInRect (mousex, mousey) lvl2Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/movement1/movement1.lvl") (curLevel lvl2)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl2
                                    put (lvl2 {curLevel = (curLevel lvl2) {levelData = (levelData (curLevel lvl2)) {levelBackgrounds = lvl2Bg}}})

                                    -- level 3
                                    w3 <- get
                                    lvl3 <- if pointInRect (mousex, mousey) lvl3Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w3 (dataPath ++ "/data/levels/water2/water2.lvl")
                                                else return w3
                                    lvl3Bg <- if pointInRect (mousex, mousey) lvl3Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/water2/water2.lvl") (curLevel lvl3)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl3
                                    put (lvl3 {curLevel = (curLevel lvl3) {levelData = (levelData (curLevel lvl3)) {levelBackgrounds = lvl3Bg}}})

                                    -- level 4
                                    w4 <- get
                                    lvl4 <- if pointInRect (mousex, mousey) lvl4Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w4 (dataPath ++ "/data/levels/movement2/movement2.lvl")
                                                else return w4
                                    lvl4Bg <- if pointInRect (mousex, mousey) lvl4Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/movement2/movement2.lvl") (curLevel lvl4)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl4
                                    put (lvl4 {curLevel = (curLevel lvl4) {levelData = (levelData (curLevel lvl4)) {levelBackgrounds = lvl4Bg}}})

                                    -- level 5
                                    w5 <- get
                                    lvl5 <- if pointInRect (mousex, mousey) lvl5Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w5 (dataPath ++ "/data/levels/pool/pool.lvl")
                                                else return w5
                                    lvl5Bg <- if pointInRect (mousex, mousey) lvl5Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/pool/pool.lvl") (curLevel lvl5)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl5
                                    put (lvl5 {curLevel = (curLevel lvl5) {levelData = (levelData (curLevel lvl5)) {levelBackgrounds = lvl5Bg}}})

                                    -- level 6
                                    w6 <- get
                                    lvl6 <- if pointInRect (mousex, mousey) lvl6Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w6 (dataPath ++ "/data/levels/rift/rift.lvl")
                                                else return w6
                                    lvl6Bg <- if pointInRect (mousex, mousey) lvl6Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/rift/rift.lvl") (curLevel lvl6)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl6
                                    put (lvl6 {curLevel = (curLevel lvl6) {levelData = (levelData (curLevel lvl6)) {levelBackgrounds = lvl6Bg}}})

                                    -- level 7
                                    w7 <- get
                                    lvl7 <- if pointInRect (mousex, mousey) lvl7Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w7 (dataPath ++ "/data/levels/skyline/skyline.lvl")
                                                else return w7
                                    lvl7Bg <- if pointInRect (mousex, mousey) lvl7Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/skyline/skyline.lvl") (curLevel lvl7)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl7
                                    put (lvl7 {curLevel = (curLevel lvl7) {levelData = (levelData (curLevel lvl7)) {levelBackgrounds = lvl7Bg}}})

                                    -- level 8
                                    w8 <- get
                                    lvl8 <- if pointInRect (mousex, mousey) lvl8Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w8 (dataPath ++ "/data/levels/river/river.lvl")
                                                else return w8
                                    lvl8Bg <- if pointInRect (mousex, mousey) lvl8Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/river/river.lvl") (curLevel lvl8)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl8
                                    put (lvl8 {curLevel = (curLevel lvl8) {levelData = (levelData (curLevel lvl8)) {levelBackgrounds = lvl8Bg}}})

                                    -- level 9
                                    w9 <- get
                                    lvl9 <- if pointInRect (mousex, mousey) lvl9Rect && lMouseDown keys'
                                                then liftIO $ loadLevel w9 (dataPath ++ "/data/levels/pinball/pinball.lvl")
                                                else return w9
                                    lvl9Bg <- if pointInRect (mousex, mousey) lvl9Rect && lMouseDown keys'
                                                 then liftIO $ loadLevelBackgrounds  (dataPath ++ "/data/levels/pinball/pinball.lvl") (curLevel lvl9)
                                                 else return $ levelBackgrounds $ levelData $ curLevel lvl9
                                    put (lvl9 {curLevel = (curLevel lvl9) {levelData = (levelData (curLevel lvl9)) {levelBackgrounds = lvl9Bg}}})

                                    return ())
                                (worldState {gameState = gameState'})

    writeIORef worldStateRef worldState'

    Glut.postRedisplay Nothing
    endTime <- getCurrentTime

    let timeDiff = truncate (1000 * diffUTCTime endTime startTime)
        timeSleep = if timeDiff < refreshMS then refreshMS - timeDiff else 0

    Glut.addTimerCallback timeSleep (mainCallback worldStateRef)

-- menuDraw
menuDraw :: IORef WorldState -> IO ()
menuDraw worldStateRef = do
    worldState <- readIORef worldStateRef

    Nxt.Graphics.begin

    Nxt.Graphics.drawTexture 0.0 0.0 (fst $ menuTextures worldState) (1.0::GLdouble)

    {-Nxt.Graphics.drawRect howtoRect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl1Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl2Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl3Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl4Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl5Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl6Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl7Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl8Rect (Color4 0.0 1.0 1.0 0.5)
    Nxt.Graphics.drawRect lvl9Rect (Color4 0.0 1.0 1.0 0.5)-}

    -- mouse cursor position
    {-mousePos <- readIORef (mousePosRef worldState)
    let mousex = mouseX mousePos
    let mousey = mouseY mousePos
    Nxt.Graphics.drawString 10.0 740.0 ("Mouse Pos: (" ++ (show mousex) ++ ", " ++ (show mousey) ++ ")") (Color4 0.7 0.7 0.7 1.0)-}

    Nxt.Graphics.end

-- howtoMain
howtoMain :: IORef WorldState -> (IORef WorldState -> IO ()) -> IO ()
howtoMain worldStateRef mainCallback = do
    startTime <- getCurrentTime

    worldState <- readIORef worldStateRef
    keys' <- readIORef (keysStateRef worldState)
    Size winW winH <- Glut.get Glut.windowSize
    mousePos <- readIORef (mousePosRef worldState)
    let (mousex, mousey) = translateMousePos mousePos winW winH

    let gameState' = if pointInRect (mousex, mousey) backRect && lMouseDown keys'
                        then MainMenuState
                        else HowtoMenuState

    writeIORef worldStateRef (worldState {gameState = gameState'})

    Glut.postRedisplay Nothing
    endTime <- getCurrentTime

    let timeDiff = truncate (1000 * diffUTCTime endTime startTime)
        timeSleep = if timeDiff < refreshMS then refreshMS - timeDiff else 0

    Glut.addTimerCallback timeSleep (mainCallback worldStateRef)

-- howtoDraw
howtoDraw :: IORef WorldState -> IO ()
howtoDraw worldStateRef = do
    worldState <- readIORef worldStateRef

    Nxt.Graphics.begin

    Nxt.Graphics.drawTexture 0.0 0.0 (snd $ menuTextures worldState) (1.0::GLdouble)
    --Nxt.Graphics.drawRect backRect (Color4 0.0 1.0 1.0 0.5)

    -- mouse cursor position
    {-mousePos <- readIORef (mousePosRef worldState)
    let mousex = mouseX mousePos
    let mousey = mouseY mousePos
    Nxt.Graphics.drawString 10.0 740.0 ("Mouse Pos: (" ++ (show mousex) ++ ", " ++ (show mousey) ++ ")") (Color4 0.7 0.7 0.7 1.0)-}

    Nxt.Graphics.end

