------ All content © 2008 DigiPen (USA) Corporation, all rights reserved. ------
-- Author: Justin Whitney
-- Created: 11/25/2008

dofile( "../../Assets/Scripts/key_name_mappings.lua" )
dofile( "../../Assets/Scripts/util_math.lua" )

------------------------------------------------------------------------------
-- VARS EPISODE 1
local ASSETS_XML = "../../Assets/Xml/"
local PAUSETEXT = "entities/game_PauseMenuText.xml"
local STICK_EPSILON = .8
--text units are fractions of screen height
local TEXT_GROWTH = 1.5
local TEXT_BUMPER = 1.1
local TEXT_MINI  = 0.02
local TEXT_SMALL = TEXT_MINI * TEXT_GROWTH
local TEXT_LARGE = TEXT_SMALL * TEXT_GROWTH
local GR_RANGE_1 = 0
local POETRY_X = .40
local POETRY_Y_MAX = 50
local POETRY_Y_MIN = .1

local buttons = {}
local x       = .05
local y       = .9
local dx      = 0
local dy      = 0
local nilOpt  = 0
local waitX   = 200        -- in ms
local waitY   = 150        -- in ms
local waitT   = waitY
local deltaL

local xStack = { x }       -- X stack
local yStack = { y }       -- Y stack
local BStack = { 0 }       -- Button index stack
local MStack = { nilOpt }  -- Menu stack

local currMenu             -- current menu
local currIdx              -- current index into the menu (one-based)
local currAffirm           -- current menu options
local currChild            -- current child object
local currOpt              -- store the chosen option for each menu 

local key
local pad

local pauseOpt    
local invOpt     
local gfxOpt
local invVineYOpt
local invYOpt
local invXOpt
local resOpt
local screenOpt
local shadowOpt 
local filterOpt
local poetryOpt
local realTmOpt
local dispPtOpt
local dispScrollY = 1
local dispScrollSpeed = 1
local disper = nil

local onAffirm
local onPush
local onPop
local onTab

-----------------------------------------------------------------------------
local function AddButtonColumn( toAdd, textSize, x, y, height )
  for i,str in ipairs(toAdd) do
    table.insert( buttons, Global:CreateEntity( ASSETS_XML .. PAUSETEXT ) )
    buttons[ #buttons ]:VIS_SetText( str )
    buttons[ #buttons ]:VIS_SetTextSize( textSize )
    buttons[ #buttons ]:VIS_sTextPos(x, y, 0)
    y = y - height
  end
end

-----------------------------------------------------------------------------
local function TabForward( menu )
  currOpt[ menu ] = (currOpt[ menu ] % #menu) + 1
  buttons[ BStack[#BStack] + currIdx ]:VIS_SetText( currMenu[currIdx] .. menu[ currOpt[ menu ] ] )
  onTab[menu]()
end

-----------------------------------------------------------------------------
local function PopButtonsAbove( num )
  while #buttons > num do
    Global:DeleteEntityByPtr( buttons[#buttons] )
    table.remove( buttons )
  end
end

-----------------------------------------------------------------------------
local function PopMenu()

  PopButtonsAbove( BStack[#BStack] )

  table.remove( xStack )
  table.remove( yStack )
  table.remove( BStack )
  table.remove( MStack )
  x = xStack[ #xStack ]
  y = yStack[ #yStack ]
  
  if(onPop[ currMenu ] ~= nil) then
    onPop[ currMenu ]()
  end
 
  currMenu = MStack[ #MStack ] 
  if( currMenu == nilOpt ) then
    Global:SetGameMode( true )
  else
    currIdx = currOpt[ currMenu ]
    currAffirm = onAffirm[ currMenu ]
    currChild = currAffirm[ currIdx ]
    for i = BStack[#BStack] + 1, #buttons, 1 do
      buttons[i]:VIS_SetTextSize( TEXT_SMALL )
    end
    buttons[ BStack[ #BStack ] + currIdx ]:VIS_SetTextSize( TEXT_LARGE )
  end
  
end

-----------------------------------------------------------------------------
local function PushMenu( menu )
  x = xStack[#xStack] + shiftX[currMenu]
  y = yStack[#yStack] + shiftY[currMenu]
  table.insert( MStack, menu )
  table.insert( BStack, #buttons )
  table.insert( xStack, x )
  table.insert( yStack, y )

  currMenu = menu
  currIdx  = currOpt[ currMenu ]
  currAffirm = onAffirm[ currMenu ]
  currChild = currAffirm[ currIdx ]
  AddButtonColumn( currMenu, TEXT_SMALL, x, y, TEXT_LARGE * TEXT_BUMPER) 
  
  for i,child in ipairs(currAffirm) do
    if( onTab[ child ] ~= nil ) then
      buttons[ BStack[#BStack] + i ]:VIS_SetText( currMenu[i] .. child[ currOpt[ child ] ] )
    end
  end
  
  if(onPush[currMenu]) then
    onPush[currMenu]()
  end
  
  buttons[ BStack[#BStack] + currIdx ]:VIS_SetTextSize( TEXT_LARGE )
end

-----------------------------------------------------------------------------
local function Affirm()
  -- A menu's affirm table has functions and submenus
  if( type(currChild) == "nil" ) then
    print( "Nil value in Affirm" )                 -- BAD!
  elseif( type(currChild) == "function" ) then
    currChild()                                    -- function
  elseif( onTab[ currChild ] ~= nil ) then
    TabForward( currChild )                        -- tabbed submenu
  else
    for i = BStack[#BStack] + 1, #buttons, 1 do    -- full submenu
      buttons[i]:VIS_SetTextSize( TEXT_MINI )
    end
    buttons[ BStack[#BStack] + currIdx ]:VIS_SetTextSize( TEXT_SMALL )
    PushMenu( currAffirm[ currIdx ] )
  end
end

-----------------------------------------------------------------------------
local function UpdateSelection( dir )
  buttons[ BStack[#BStack] + currIdx ]:VIS_SetTextSize( TEXT_SMALL )
  currIdx = ((currIdx - 1 + dir) % #currMenu) + 1
  currChild = currAffirm[ currIdx ]
  currOpt[currMenu] = currIdx
  buttons[ BStack[#BStack] + currIdx ]:VIS_SetTextSize( TEXT_LARGE )
end

-----------------------------------------------------------------------------
local function DisplayControls()
  AddButtonColumn( controls, TEXT_LARGE, x, y - TEXT_LARGE * TEXT_BUMPER * 5, TEXT_LARGE * TEXT_BUMPER )
end

-----------------------------------------------------------------------------
local function SetVineInversion()
  Global:sVineInversion( ((currOpt[invVineYOpt]-1)*-2) + 1 )
end

-----------------------------------------------------------------------------
local function SetInversion()
  local camera = Global:FindEntityByName( "CameraInput", false )
  Entity.SPT_GiveNumber( camera, "Xinv", ((currOpt[invXOpt]-1)*-2) + 1 )
  Entity.SPT_GiveNumber( camera, "Yinv", ((currOpt[invYOpt]-1)*-2) + 1 )
end

-----------------------------------------------------------------------------
local function SetShadow()
  Global:SetShadow( currOpt[ shadowOpt ] - 1 )
end

-----------------------------------------------------------------------------
local function SetFilter()
  Global:SetFilter( currOpt[ filterOpt ] - 1 )
end

-----------------------------------------------------------------------------
local function ToggleRealTimePoetry()
  Global:TogglePoetry()
end

-----------------------------------------------------------------------------
local function DispPoetry()
  dispScrollY = -.05
  
  disper = Global:CreateEntityAt( ASSETS_XML .. PAUSETEXT, 0, 0, 0, 0, 0, 0 )
  disper:VIS_sTextPos( POETRY_X, dispScrollY, 0 )
  disper:VIS_SetText( Global:AllPoetry() )

end

-----------------------------------------------------------------------------
local function UnDispPoetry()
  dispScrollSpeed = 1
  
  Global:DeleteEntityByPtr( disper:GetMyPointer() )
  disper = nil

end

-----------------------------------------------------------------------------
local function SetResolution()
  Global:SetResolution( currOpt[ resOpt ] - 1 )
end

-----------------------------------------------------------------------------
local function ResetCurrOpt()
  currOpt[currMenu] = 1
end

-----------------------------------------------------------------------------
local function Quit()
  Global:QuitGame()
end

-----------------------------------------------------------------------------
local function ExitMenu()
  while( #MStack > 1 ) do
    PopMenu()
  end
end

-----------------------------------------------------------------------------
local function ZoomOutAndSpinTheCamera()
  Global:UpdateCameraThird(.1, 0, 1)
  Global:ClampCameraZoomMinMax(600, 600)
end

-----------------------------------------------------------------------------
-- Init
MStack   = { nilOpt }
currMenu    = nilOpt
currIdx     = 0

pauseOpt     = { "Controls", "Settings", "Poetry", "Continue", "Quit" }
invOpt       = { "Invert Vine Y: ", "Invert Camera Y: ", "Invert Camera X: " }
gfxOpt       = { "Screen width ...", "Full Screen: ", "Shadows: ", "Filter: " }
invVineYOpt  = { "Off", "On" }
invYOpt      = { "Off", "On" }
invXOpt      = { "Off", "On" }
screenOpt    = { "Off", "On" }
shadowOpt    = { "Off", "On" }
filterOpt    = { "Low", "High" }
poetryOpt    = { "Real-Time Poetry: ", "Read Poetry ..." }
realTmOpt    = { "On", "Off" }
dispPtOpt    = { "" }
key          = { "WASD - Move",
                 "Space - Jump",
                 "Shift - Grow Vine", 
                 "Control - Ungrow Vine",
                 "Mouse - Move Camera",
                 --"L/R Click - Zoom In/Out",
                 "C - Center Camera",
                 "V - Enter/Exit Look Around Mode" }
pad          = { "Left Stick - Move",
                 "A - Jump",
                 "X - Grow Vine", 
                 "B - Ungrow Vine",
                 "Right Stick - Move Camera",
                 --"L/R Bumper - Zoom In/Out",
                 --"Click Right Stick - Center Camera",
                 "Y - Center Camera",
                 "Directional Pad Up - Enter/Exit Look Around Mode" }

if( Global:ControllerConnected() ) then
  controls = pad
else
  controls = key
end

resOpt, currChild = Global.GetResolution()

shiftX   = { [nilOpt] = 0, [pauseOpt] = 0.15, [invOpt] = 0.20, [gfxOpt] = 0.20, [poetryOpt] = .20 }
shiftY   = { [nilOpt] = 0, [pauseOpt] = 0, [invOpt] = 0, [gfxOpt] = 0, [poetryOpt] = 0 }
currOpt  = { [nilOpt] = 0,
             [pauseOpt] = 1,
             [invOpt]  = 1,
             [invVineYOpt] = 1,
             [invYOpt] = 1,
             [invXOpt] = 1,
             [gfxOpt] = 1,
             [screenOpt] = 1,
             [shadowOpt] = 2,
             [filterOpt] = 2,
             [resOpt] = currChild + 1 ,
             [poetryOpt] = 1,
             [realTmOpt] = 1,
             [dispPtOpt] = 1 }

onAffirm = { [pauseOpt]  = { invOpt, gfxOpt, poetryOpt, PopMenu, Quit },
             [invOpt]    = { invVineYOpt, invYOpt, invXOpt },
             [gfxOpt]    = { resOpt, screenOpt, shadowOpt, filterOpt },
             [poetryOpt] = { realTmOpt, dispPtOpt },
             [resOpt]    = { },
             [dispPtOpt] = { } }
onPush   = { [invOpt]   = DisplayControls,
             [dispPtOpt] = DispPoetry }
onPop    = { [pauseOpt] = ResetCurrOpt,
             [invOpt]   = ResetCurrOpt,
             [dispPtOpt] = UnDispPoetry }
onTab    = { [invVineYOpt] = SetVineInversion,
             [invYOpt]     = SetInversion, 
             [invXOpt]     = SetInversion,
             [screenOpt]   = Global.ToggleFullscreen,
             [shadowOpt]   = SetShadow,
             [filterOpt]   = SetFilter,
             [realTmOpt]   = ToggleRealTimePoetry
           }
             
for i = 1, #resOpt, 1 do
  table.insert( onAffirm[resOpt], SetResolution )
end

-----------------------------------------------------------------------------
while( 1 ) 
do
  coroutine.yield()
  if( currMenu == nilOpt ) then
    --Pause menu is closed
    if( Global:IsGameButtonTriggered( 2 ) ) and ( Global:IsInGameMode( ) ~= 0 ) then
      PushMenu( pauseOpt )
      Global:SetGameMode( false )
    end
  else
    --Pause menu is open
    ZoomOutAndSpinTheCamera()

    dx = 0
    dy = 0
    waitT = math.max( waitT - Global:TimeElapsed(), 0 )

    if(waitT == 0) then
      local deltaL = Global:gRangeState(0)
      if( math.abs( deltaL.x ) < STICK_EPSILON ) and ( math.abs( deltaL.z ) < STICK_EPSILON )
      then
        deltaL = Global:gRangeState(2)
      end
      
      -- left or right?
      if(deltaL.x < -STICK_EPSILON) then
        dx = -1
        waitT = waitX
      elseif( deltaL.x > STICK_EPSILON and type(currChild) == "table" ) then
        dx = 1
        waitT = waitX
      end
      
      -- up or down?
      if(math.abs(deltaL.z) > STICK_EPSILON) 
      then
        -- speed up poetry
        if( disper ) then
          local modifier = 1
          if( dispScrollSpeed <= 2 ) then
            modifier = .1
          end
          dispScrollSpeed = Clamp( dispScrollSpeed - ( deltaL.z * modifier ), POETRY_Y_MIN, POETRY_Y_MAX )
          
        -- different selection
        else
          dy = deltaL.z / math.abs(deltaL.z)
          UpdateSelection( dy )
        end
        
        waitT = waitY
      end
    end

    if( disper )
    then
      local dispScrollYMax = ( 1 + Global:LinesOfPoetry( disper:VIS_GetText() ) * TEXT_LARGE )
      if( dispScrollY < dispScrollYMax )
      then
        dispScrollY = dispScrollY + ( Global:TimeElapsed() / 17500 ) * dispScrollSpeed
        disper:VIS_sTextPos( POETRY_X, dispScrollY, 0 )
        if( dispScrollY >= dispScrollYMax )
        then
          PopMenu()
        end
      end
    end
    
    if( Global:IsGameButtonTriggered( 2 ) ) then
      ExitMenu()
    elseif( Global:IsGameButtonTriggered( 0 ) or dx > 0 or Global:IsTriggered( key_names_to_values( "Enter" ) ) ) then
      Affirm()
    elseif( Global:IsGameButtonTriggered( 1 ) or dx < 0 ) then
      PopMenu()
    end
  end
  
end
