-- menusystem :: the controller of the menu system. This object handle the
-- different menu objects

--[[
  Copyright © 2019 Kazhnuz

  Permission is hereby granted, free of charge, to any person obtaining a copy of
  this software and associated documentation files (the "Software"), to deal in
  the Software without restriction, including without limitation the rights to
  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  the Software, and to permit persons to whom the Software is furnished to do so,
  subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]

local cwd  = (...):gsub('%.init$', '') .. "."

local MenuSystem = Object:extend()

-- Load the differents menu object to get an easy access
MenuSystem.Parent       = require(cwd .. "parent")
MenuSystem.ListBox      = require(cwd .. "listbox")
MenuSystem.FlowBox      = require(cwd .. "flowbox")
MenuSystem.Grid         = require(cwd .. "grid")

-- load widgets object
MenuSystem.Widget       = require(cwd .. "widgets")

-- INIT FUNCTIONS
-- Initialize and configure the menu controller

function MenuSystem:new(scene)
  self.scene = scene
  self.menus = {}
  self.focusedMenu = ""
  self.isActive = true
end

function MenuSystem:reset()
  self.menus = {}
end

-- ACTIVATION FUNCTIONS
-- Activate and deactivate the whole menusystem

function MenuSystem:activate()
  self.isActive = true
end

function MenuSystem:deactivate()
  self.isActive = false
end

function MenuSystem:getActiveState()
  return self.isActive
end

-- MENUS FUNCTIONS
-- Controle the menus of the menusystem

function MenuSystem:addMenu(name, menu)
  self.menus[name] = menu
end

function MenuSystem:menuExist(name)
  return (self.menus[name] ~= nil)
end

function MenuSystem:switchMenu(menu)
  for k,v in pairs(self.menus) do
    if k == menu then
      v:getFocus()
      v:setVisibility(true)
      v:setActivity(true)
    else
      v:setVisibility(false)
      v:setActivity(false)
    end
  end
end

function MenuSystem:lockMenu(menu, lock)
  local lock = lock or true
  if self:menuExist(menu) then
    self.menus[menu]:lock(lock)
  end
end

function MenuSystem:lockMenuVisibility(menu, lock)
  local lock = lock or true
  if self:menuExist(menu) then
    self.menus[menu]:lockVisibility(lock)
  end
end

function MenuSystem:setMenuActivity(menu, activity)
  local activity = activity or true
  if self:menuExist(menu) then
    self.menus[menu]:setActivity(activity)
    if activity == true then
      -- if we make the menu active, he have to be visible too
      self.menus[menu]:setVisibility(true)
    end
  end
end

function MenuSystem:setMenuVisibility(menu, visibility)
  local visibility = visibility or true
  if self:menuExist(menu) then
    self.menus[menu]:setVisibility(visibility)
  end
end

function MenuSystem:setAllMenuVisibility(visibility)
  for k,v in pairs(self.menus) do
    v:setVisibility(visibility)
  end
end

function MenuSystem:setAllMenuActivity(activity)
  for k,v in pairs(self.menus) do
    v.isActive = activity
  end
end

function MenuSystem:removeDestroyedMenus()
 -- On retire les entitées marquées comme supprimées
  for k,v in pairs(self.menus) do
    if (v.isDestroyed == true) then
      self.menus[k] = nil
    end
  end
end

-- SOUND FUNCTIONS
-- Add sounds to every menus

function MenuSystem:setSoundFromSceneAssets(soundname)
  for k,v in pairs(self.menus) do
    v:setSoundFromSceneAssets(soundname)
  end
end

function MenuSystem:setSound(soundasset)
  for k,v in pairs(self.menus) do
    v:setSound(soundasset)
  end
end

-- UPDATE FUNCTIONS
-- Update the menus of the menusystem

function MenuSystem:update(dt)
  if (self.isActive) then
    self:removeDestroyedMenus()
    for k,v in pairs(self.menus) do
      v:update(dt)
      v:updateWidgets(dt)
    end

    if self.menus[self.focusedMenu] ~= nil then
      -- Only check buttons if the current focused menu is actually active
      if self.menus[self.focusedMenu].isActive then
        for k,v in pairs(self.keys) do
          if self.keys[k].isPressed then
            self.menus[self.focusedMenu]:keyreleased(k)
          end
        end
      end
    end
  end
end

-- MOUSE FUNCTIONS
-- Send mouse inputs to the menu

function MenuSystem:mousemoved(x, y, dx, dy)
  if (self.isActive) then

    for k,v in pairs(self.menus) do
      if v.isActive then
        if (x > v.x) and (x < v.x + v.w) and (y > v.y) and (y < v.y + v.h) then
          v:mousemoved(x - v.x, y - v.y)
          break;
        end
      end
    end

  end
end

function MenuSystem:mousepressed( x, y, button, istouch )
  if (self.isActive) then
    for k,v in pairs(self.menus) do
      if v.isActive then
        if (x > v.x) and (x < v.x + v.w) and (y > v.y) and (y < v.y + v.h) then
          v:mousepressed(x - v.x, y - v.y, button, istouch )
          break;
        end
      end
    end
  end
end

-- DRAW FUNCTIONS
-- All functions to draw the menus of the menusystem

function MenuSystem:getDrawList()
  local drawList = {}
  for k,v in pairs(self.menus) do
    local drawObject = {}
    drawObject.name   = k
    drawObject.depth  = v.depth
    table.insert(drawList, drawObject)
  end
  table.sort(drawList, function(a,b) return a.depth > b.depth end)

  return drawList
end

function MenuSystem:draw(dt)
  if (self.isActive) then
    -- Draw all the menus
    self.drawList = self:getDrawList()

    for i,v in ipairs(self.drawList) do
      local v2 = self.menus[v.name]
      if (v2.isVisible) then
        v2:draw(dt)
      end
    end

    if self.menus[self.focusedMenu] ~= nil then
      if (self.menus[self.focusedMenu].isVisible) then
        self.menus[self.focusedMenu]:drawCursor()
      end
    end
  end
end

return MenuSystem
