module Dodge.Menu
    ( scodeToChar
    , pauseMenu
    , gameOverMenu
    ) where
import Dodge.Config.Data
import LensHelp
import Dodge.Menu.OptionType
import Dodge.StartNewGame
import Dodge.Menu.PushPop
import Dodge.Data
import Dodge.PreloadData
import Dodge.Save
import Dodge.Config.Update
import Padding
--import SDL.Internal.Numbered
--import Preload.Update
import Dodge.SoundLogic
--import Dodge.LevelGen

import Text.Read
import SDL
import System.Clipboard
--import Control.Lens
--import System.Random

slTitleOptionsEff :: String -> [MenuOption] -> (Universe -> IO (Maybe Universe)) -> ScreenLayer
slTitleOptionsEff title ops eff = OptionScreen
    { _scTitle = const title
    , _scOptions = ops
    , _scDefaultEff = eff
    , _scOptionFlag = NormalOptions
    , _scOptionsOffset = 0
    }
pauseMenu :: ScreenLayer
pauseMenu = slTitleOptionsEff "PAUSED" pauseMenuOptions (return . unpause)
pauseMenuOptions :: [MenuOption]
pauseMenuOptions = basicKeyOptions
    [ Toggle (return . Just . startNewGame) (opText "NEW LEVEL")
    , Toggle (return . Just . loadSaveSlot LevelStartSlot) (opText "RESTART")
    , Toggle (pushScreen $ seedStartMenu "START FROM SEED") (opText "START FROM SEED")
    , Toggle (pushScreen optionMenu ) (opText "OPTIONS")
    , Toggle (pushScreen displayControls) (opText "CONTROLS")
    ]
    ++
    [ InvisibleToggle ScancodeEscape (return . const Nothing)
    ]
  where
    opText = const . Left
seedStartMenu :: String -> ScreenLayer
seedStartMenu str = slTitleOptionsEff str seedStartOptions popScreen
seedStartOptions :: [MenuOption]
seedStartOptions =
    [ Toggle trySeedFromClipboard (const $ Left "PASTE NUMBER FROM CLIPBOARD") ScancodeA
--    , Toggle ScancodeI (return . Just . loadSaveSlot LevelStartSlot) (const "INSERT NUMBER")
    ]

trySeedFromClipboard :: Universe -> IO (Maybe Universe)
trySeedFromClipboard u = do
    mcstr <- getClipboardString
    case mcstr >>= readMaybe of
        Nothing -> pushScreen (seedStartMenu "CLIPBOARD UNUSABLE, NEED INTEGER")
            (u & menuLayers %~ tail)
        Just i -> return . Just $ startSeedGame i u

slTitleOptions :: String -> [MenuOption] -> ScreenLayer
slTitleOptions title ops = slTitleOptionsEff title ops (popScreen . writeConfig)

optionMenu :: ScreenLayer
optionMenu = slTitleOptionsEff "OPTIONS" optionsOptions popScreen

optionsOptions :: [MenuOption]
optionsOptions = basicKeyOptions
    [ makeSubmenuOption soundMenu      $ Left "VOLUME"
    , makeSubmenuOption graphicsMenu   $ Left "GRAPHICS"
    , makeSubmenuOption gameplayMenu   $ Left "GAMEPLAY"
    , makeSubmenuOption debugMenu      $ Left "DEBUG OPTIONS"
    ]
debugMenu :: ScreenLayer
debugMenu = slTitleOptions
    "OPTIONS:GAMEPLAY"
    debugMenuOptions
debugMenuOptions :: [MenuOption]
debugMenuOptions = zipWith ($)
    (map f [minBound..] ++ [makeEnumOption debug_view_clip_bounds "SHOW ROOM CLIP" return] )
    $ map Scancode [4..]
  where
    f :: DebugBool -> Scancode -> MenuOption
    f bd = Toggle (return . Just . (config . debug_booleans . at bd %~ toggleJust))
        (Right . g bd . (^? config . debug_booleans . ix bd))
    g bd Nothing = (show bd, "False")
    g bd _       = (show bd, "True")
--    zipWith ($)
--    [ makeBoolOption debug_seconds_frame "SHOW SECONDS/FRAME" 
--    , makeBoolOption debug_noclip "NOCLIP" 
--    , makeBoolOption debug_cr_status "SHOW CREATURE STATUS" 
--    , makeBoolOption debug_cr_awareness "SHOW CREATURE AWARENESS" 
--    , makeBoolOption debug_view_boundaries "SHOW VIEW BOUNDARIES" 
--    , makeBoolOption debug_pathing "SHOW PATHING" 
--    , makeBoolOption debug_show_sound     "SHOW VISUAL SOUNDS" 
--    , makeBoolOption debug_mouse_position    "SHOW MOUSE POSITION" 
--    , makeBoolOption debug_walls "SHOW WALL INFO"
--    , makeBoolOption debug_remove_LOS "REMOVE LOS"
--    , makeBoolOption debug_cull_more_lights "CULL MORE LIGHTS"
--    ]
--    $ map Scancode [4 ..]
gameplayMenu :: ScreenLayer
gameplayMenu  = slTitleOptions
    "OPTIONS:GAMEPLAY"
    gameplayMenuOptions

gameplayMenuOptions :: [MenuOption]
gameplayMenuOptions = basicKeyOptions
    [ makeBoolOption gameplay_rotate_to_wall "ROTATE TO WALL"
    ]
basicKeyOptions :: [Scancode -> c] -> [c]
basicKeyOptions xs = zipWith ($) xs $ map Scancode [4 .. ]

soundMenu :: ScreenLayer
soundMenu = slTitleOptions
    "OPTIONS:VOLUME"
    soundMenuOptions

soundMenuOptions :: [MenuOption]
soundMenuOptions =
    [ theoption ScancodeY volume_master ScancodeU "MASTER VOLUME"  _volume_master
    , theoption ScancodeH volume_sound  ScancodeJ "EFFECTS VOLUME" _volume_sound
    , theoption ScancodeN volume_music  ScancodeM "MUSIC VOLUME"   _volume_music
    ]
  where
    theoption scod1 stype scod2 str voltype = Toggle2
        scod1
        (change dec stype)
        scod2
        (change inc stype)
        (\w -> Right (str , leftPad 2 '.' $ show (round $ 10 * voltype (_config w)::Int)))
    change g vt = return . Just . (config . vt %~ g) . sw
    dec x = max 0 (x - 0.1)
    inc x = min 1 (x + 0.1)
    sw w = w & uvWorld . sideEffects %~ setVolThen (_config w)

writeConfig :: Universe -> Universe
writeConfig w = w & uvWorld . sideEffects %~ saveConfig (_config w)

graphicsMenu :: ScreenLayer
graphicsMenu = slTitleOptions "OPTIONS:GRAPHICS" graphicsMenuOptions

graphicsMenuOptions :: [MenuOption]
graphicsMenuOptions = basicKeyOptions
    [ makeEnumOption graphics_resolution_factor "RESOLUTION"    updateFramebufferSize
    , makeBoolOption graphics_wall_textured     "WALL TEXTURES"
    , makeBoolOption graphics_object_shadows    "OBJECT SHADOWS"
    , makeBoolOption graphics_cloud_shadows     "CLOUD SHADOWS"
    ]

gameOverMenu :: ScreenLayer
gameOverMenu = OptionScreen
    { _scTitle = const "GAME OVER"
    , _scOptions = pauseMenuOptions
    , _scDefaultEff = return . Just
    , _scOptionFlag = GameOverOptions
    , _scOptionsOffset = 0
    }

-- | hacky - no longer used
scodeToChar :: Scancode -> Char
scodeToChar = toEnum . (+ 61) . fromIntegral . unwrapScancode


--charToScode :: Char -> Scancode
--charToScode = Scancode . fromIntegral . (\x -> x - 61) . fromEnum

unpause :: Universe -> Maybe Universe
unpause w = Just . resumeSound $ w & menuLayers .~ []

displayControls :: ScreenLayer
displayControls = ColumnsScreen (const "CONTROLS") listControls

listControls :: [(String,String)]
listControls =
    [("wasd",           "MOVEMENT")
    ,("[rmb]",          "AIM")
    ,("[rmb+lmb]",      "SHOOT/USE/EQUIP SELECTED")
    ,("[lmb]",          "USE EQUIPPED")
    ,("[wheelscroll]" , "SELECT ITEM"  )
    ,("[space]" ,       "PICKUP ITEM"  )
    ,("m" ,             "DISPLAY MAP"    )
    ,("f" ,             "DROP ITEM"    )
    ,("c" ,             "COMBINE ITEMS"    )
    ,("x" ,             "TWEAK ITEMS"    )
    ,("c[esc]" ,        "PAUSE"        )
    ,("qe" ,            "ROTATE CAMERA")
    ,("F5" ,            "QUICKSAVE")
    ,("F9" ,            "QUICKLOAD")
    ]
