module Main where
import Loop
import LoadConfig
import Dodge.Data
import Dodge.Initialisation
import Dodge.Update
import Dodge.Event
import Dodge.Render
import Dodge.Config.Data
import Dodge.Config.KeyConfig
import Dodge.Config.Load
import Dodge.Config.Update
import Dodge.SoundLogic.LoadSound
import Dodge.Debug.Flag.Data
import Picture
import Render
import Preload.Render
import Sound
import Preload
import Sound.Data
import Music
import Data.Preload
import Data.Preload.Render

import Control.Lens
--import Foreign (Word32)
import Control.Monad
--import System.Random
--import qualified Data.Map                  as M
import qualified Data.IntMap               as IM
import Graphics.Rendering.OpenGL hiding (color, rotate, scale, translate)
import qualified SDL
import qualified SDL.Mixer                 as Mix
--import qualified Control.Monad.Parallel as MP
import Control.Parallel

main :: IO ()
main = do
    (sizex,sizey) <- loadConfig
    setupLoop'
        (sizex,sizey)
        theCleanup
        (firstWorldLoad (sizex,sizey))
        theUpdateStep
        (flip handleEvent)

theCleanup :: World -> IO ()
theCleanup w = SDL.cursorVisible $= True >> cleanUpPreload (_preloadData w)

firstWorldLoad :: (Int,Int) -> IO World
firstWorldLoad (sizex,sizey) = do
    SDL.cursorVisible $= False
    theKeyConfig <- loadKeyConfig
    theConfig <- loadDodgeConfig
    pdata <- doPreload >>= applyWorldConfig theConfig
    w <- fmap (setWindowSize sizex sizey . (keyConfig .~ theKeyConfig) . (config .~ theConfig)) firstWorld
    return $ w & preloadData .~ pdata

theUpdateStep :: World -> IO World
theUpdateStep = doSideEffects <=< updateRenderSplit

updateRenderSplit :: World -> IO World
updateRenderSplit w = do
    let preData = _preloadData w
    update w `par` void (doDrawing (_renderData preData) w)
    return $ update w

doSideEffects :: World -> IO World
doSideEffects w = do
    let preData = _preloadData w
    newPlayingSounds <- playSoundAndUpdate (_soundData preData) (_playingSounds w) (_sounds w)
    w' <- _sideEffects w w
    
    endTicks <- SDL.ticks
    let lastFrameTicks = _frameTimer preData
    
    when (_displaySecondsPerFrame $ _debugFlags w) $ void $ renderFoldable
                (_pictureShaders $ _renderData preData)
                (setDepth (-1)
                    . translate (-0.5) (-0.8) . scale 0.0005 0.0005
                    . text $ "ms/frame " ++ show (endTicks - lastFrameTicks)
                )
    return $ w' & preloadData . frameTimer .~ endTicks
        & playingSounds .~ newPlayingSounds
        & sideEffects .~ return

doPreload :: IO PreloadData
doPreload = do
    lChunks <- loadSounds
    lMusic  <- loadMusic
    let sData = SoundData {_loadedChunks = lChunks}
        mData = MusicData {_loadedMusic = lMusic}
    Mix.playMusic Mix.Forever (lMusic IM.! 0)
    rData <- preloadRender
    return $ PreloadData 
        { _renderData   = rData 
        , _soundData    = sData 
        , _musicData    = mData
        , _frameTimer   = 0
        }

checkForGlErrors :: IO ()
checkForGlErrors = do
    errs <- errors
    unless (null errs) $ putStrLn $ "GLerror during doLoop: " ++ unwords (map show errs)

setWindowSize :: Int -> Int -> World -> World
setWindowSize x y w = w 
    & config . windowX .~ fromIntegral x
    & config . windowY .~ fromIntegral y
