-------------------------------------
-- The different types of transitions
-------------------------------------
MenuTransition =
{
   NONE = 0,
   PUSHING = 1,
   POPPING = 2,
}

------------------------------------
-- Creates the main-menu of the game
------------------------------------
function newMenu()
   local o = {}
   
   
   -------------------------------
   -- Constructor of the main-menu
   -------------------------------
   function o:construct()
      self.transition = MenuTransition.NONE
      self.transitionOffset = 0
      self.transitionTime = 0.0
      self.sparklesTime = 3.0
      self.entryTime = 0.0
      self.glowAlpha = 255
      self.stack = { { name = "root", selected = 1 } }
      
      self.veraBI = newFont("fonts/veraBI.ttf", 34)
      self.background = newSprite("images/menuBg.png")
      self.returnImg = newSprite("images/return.png")
      
      self.menus =
      {
         root =
         {
            box = newSprite("images/menuBoxes.png", 0, 0, 369, 164),
            
            {
               name  = "startGame",
               image = newSprite("images/menuEntries.png", 0,   0,   236, 53),
               glow  = newSprite("images/menuEntries.png", 0,   53,  236, 53),
            },
            {
               name  = "howToPlay",
               image = newSprite("images/menuEntries.png", 0,   106, 254, 53),
               glow  = newSprite("images/menuEntries.png", 0,   159, 254, 53),
            },
            {
               name  = "credits",
               image = newSprite("images/menuEntries.png", 0,   212, 160, 53),
               glow  = newSprite("images/menuEntries.png", 0,   265, 160, 53),
            },
         },
         
         startGame =
         {
            box = newSprite("images/menuBoxes.png", 0, 0, 369, 164),
            
            {
               name  = "start",
               image = newSprite("images/menuEntries.png", 254, 212, 152, 53),
               glow  = newSprite("images/menuEntries.png", 254, 265, 152, 53),
            },
            {
               name  = "enemies",
               image = newSprite("images/menuEntries.png", 254, 106, 212, 53),
               glow  = newSprite("images/menuEntries.png", 254, 159, 212, 53),
               choices = { 1, 2, 3 },
               selected = 3,
            },
            {
               name  = "difficulty",
               image = newSprite("images/menuEntries.png", 254, 0,   219, 53),
               glow  = newSprite("images/menuEntries.png", 254, 53,  219, 53),
               choices = { "Easy", "Med", "Hard" },
               selected = 3,
            },
         },
         
         howToPlay =
         {
            box = newSprite("images/menuBoxes.png", 0, 164, 369, 164),
         },
         
         credits =
         {
            box = newSprite("images/menuBoxes.png", 0, 328, 369, 164),
         },
      }
      
      return self
   end

   
   ----------------------------------------------------
   -- Selects another entry (dir = 1 to select the next
   -- entry, dir = -1 to select the previous entry)
   ----------------------------------------------------
   function o:selectEntry(dir)
      if (self.transition == MenuTransition.NONE) then
         local currentMenu = self.stack[#self.stack]
         local numEntries = #self.menus[currentMenu.name]
         if (numEntries > 0) then
            currentMenu.selected = ((currentMenu.selected - 1 + dir) % numEntries) + 1
            self.entryTime = 0.0
         end
      end
   end
   
   
   ---------------------------------------------------------
   -- Selects another value for the current entry
   -- (dir = 1 for the next value, -1 for the previous value
   ---------------------------------------------------------
   function o:selectValue(dir)
      if (self.transition == MenuTransition.NONE) then
         local currentMenu = self.stack[#self.stack]
         local numEntries = #self.menus[currentMenu.name]
         if (numEntries > 0) then
            local currentEntry = self.menus[currentMenu.name][currentMenu.selected]
            if (currentEntry.choices) then
               local numChoices = #currentEntry.choices
               currentEntry.selected = ((currentEntry.selected - 1 + dir) % numChoices) + 1
            end 
         end
      end
   end
   
   
   ------------------------------------------------------------------------
   -- Validates the selected entry and returns the name of the active entry
   ------------------------------------------------------------------------
   function o:validate()
      if (self.transition == MenuTransition.NONE) then
         local currentMenu = self.stack[#self.stack]
         local numEntries = #self.menus[currentMenu.name]
         if (numEntries > 0) then
            local currentEntry = self.menus[currentMenu.name][currentMenu.selected]
            if (self.menus[currentEntry.name]) then
               self:pushMenu(currentEntry.name)
            else
               return currentEntry.name
            end
         end
      end
   end
   
   
   -----------------------------------------
   -- Gets the value of an entry of the menu
   -----------------------------------------
   function o:getValue(valueName)
      for k, menu in pairs(self.menus) do
         for k, entry in ipairs(menu) do
            if (entry.name == valueName and entry.choices) then
               return entry.choices[entry.selected]
            end
         end
      end
   end
   
   
   ---------------------------------------------
   -- Pushes the menu corresponding to the given
   -- name on the top of the menu-stack
   ---------------------------------------------
   function o:pushMenu(menu)
      if (self.transition == MenuTransition.NONE) then
         table.insert(self.stack, { name = menu, selected = 1 })
         self.transition = MenuTransition.PUSHING
         self.transitionTime = 0.0
         self.entryTime = 0.0
      end
   end
   
   
   ------------------------
   -- Pops the current menu
   ------------------------
   function o:popMenu()
      if (self.transition == MenuTransition.NONE and #self.stack > 1) then
         self.transition = MenuTransition.POPPING
         self.transitionTime = 0.0
      end
   end
   
   
   ------------------------
   -- Goes to the root-menu
   ------------------------
   function o:goToRoot()
      self.transition = MenuTransition.NONE
      self.transitionTime = 0.0
      self.entryTime = 0.0
      self.stack = { { name = "root", selected = 1 } }
   end
   
   
   ------------------------
   -- Updates the main-menu
   ------------------------
   function o:update(dt)
      self.transitionOffset = 0
      self.transitionTime = self.transitionTime + dt
      
      -- Animate menu-pushing
      if (self.transition == MenuTransition.PUSHING) then
         if (self.transitionTime >= 0.3) then
            self.transition = MenuTransition.NONE
         else
            self.transitionOffset = (self.transitionTime * 480) / 0.3 - 480
         end
      
      -- Animate menu-popping
      elseif (self.transition == MenuTransition.POPPING) then
         if (self.transitionTime >= 0.3) then
            table.remove(self.stack)
            self.transition = MenuTransition.NONE
         else
            self.transitionOffset = -(self.transitionTime * 480) / 0.3
         end
      end
      
      self.transitionOffset = self.transitionOffset + (#self.stack - 1) * 480
      
      -- Update the alpha of the glow
      self.entryTime = self.entryTime + dt
      self.glowAlpha = 128 * (math.cos(10 * self.entryTime) + 1)
      
      -- Add sparkles randomly
      self.sparklesTime = self.sparklesTime - dt
      if (self.sparklesTime <= 0) then
         local x = math.random(20, 50) + 410 * math.random(0, 1)
         local y = math.random(40, 230)
         boombastic.particleSystems:addMenuSparkles(x, y)
         self.sparklesTime = 3.0 + math.random() * 3.0
      end
   end
   

   ----------------------
   -- Draws the main-menu
   ----------------------
   function o:draw()
   
      -- Draw the background of the main-menu
      self.background:draw(0, 0)
      
      -- Draw the different menus of the stack
      local startX = 60 - self.transitionOffset
      local endX = 410 - self.transitionOffset
      local midX = (startX + endX) / 2
      for k, menu in ipairs(self.stack) do
         
         local box = self.menus[menu.name].box
         box:setCenter(0.5, 0.0)
         box:draw(midX, 86)
         
         -- Draw the entries of the menu
         local y = 114
         for l, entry in ipairs(self.menus[menu.name]) do
            if (entry.choices) then
               
               entry.image:setCenter(0.0, 0.5)
               entry.image:draw(startX, y)
               
               if (menu.selected == l) then
                  entry.glow:setCenter(0.0, 0.5)
                  entry.glow:draw(startX, y, 0, 1, 1, self.glowAlpha)
               end
               
               self.veraBI:draw(entry.choices[entry.selected],
                                startX + 260, y + 12, 179, 187, 195)
               
            else
               entry.image:setCenter(0.5, 0.5)
               entry.image:draw(midX, y)
               
               if (menu.selected == l) then
                  entry.glow:setCenter(0.5, 0.5)
                  entry.glow:draw(midX, y, 0, 1, 1, self.glowAlpha)
               end
            end
            
            y = y + 55
         end
         
         startX = startX + 480
         endX = endX + 480
         midX = midX + 480
      end
      
      -- Draw the "0 to return" image
      if (#self.stack > 1) then
         self.returnImg:draw(390, 250)
      end
   end
   
   
   return o:construct()
end
