local classlib = require("core.class")
local tablex = require("core.tablex")
local buttonUtil = require("ui.buttonUtil")
local consts = require("ui.consts")
local hooks = require("ui.hooks")
local tutorialConsts = require("ui.tutorialConsts")
local tutorialUtil = require("ui.tutorialUtil")
local util = require("ui.util")
local Audio = game.Audio
local UI = game.UI
local Button = classlib.Class("Button")
function Button:init(list, args)
  self._list = list
  self._state = list._state
  self._active = false
  self._focusable = args.Focusable
  self._item = args.Item
  self._text = args.Text
  self._checked = util.GetValueWithDefault(args.Checked, false)
  self._onGainFocus_sound = args.OnGainFocus_Sound
  self._buttonType = util.GetValueWithDefault(args.ButtonType, "button")
  self._buttonToolTip = args.ButtonToolTip
  self._toggleToolTip = args.ToggleToolTip
  self._toggle = args.Toggle
  self._advance = args.Advance
  self._hookTokens = {}
  self._buttonGOs = {}
  self._eventHandlers = util.GetValueWithDefault(args.EventHandlers, {})
  self._activationList = util.GetValueWithDefault(args.ActivationList, {})
  assert(self._eventHandlers ~= nil and type(self._eventHandlers) == "table", "Attempted to create Button with invalid EventHandlers table!")
  assert(self._activationList ~= nil and type(self._activationList) == "table", "Attempted to create Button with invalid ActivationList table!")
  self:SetupActivationList()
end
function Button:Activate()
  if not self._active then
    for _, item in ipairs(self._eventHandlers) do
      util.InstallEventHooks(hooks, self, item.Events, function(button)
        tutorialUtil.HandleEvent(button, item.Events, item.Handler)
      end)
    end
    for _, activationSet in ipairs(self._activationList) do
      local item = activationSet.Item
      if item.Activate ~= nil and item:get_active() ~= true then
        local condition = activationSet.Condition
        local allowActivate = true
        if condition ~= nil then
          allowActivate = condition(self._item)
        end
        if allowActivate then
          item:Activate()
        end
      end
    end
    self._active = true
  end
end
function Button:Deactivate()
  if self._active then
    self._active = false
    for _, item in ipairs(self._eventHandlers) do
      util.UninstallEventHooks(hooks, self, item.Events)
    end
    for _, activationSet in ipairs(self._activationList) do
      local item = activationSet.Item
      if item.Deactivate ~= nil and item:get_active() == true then
        item:Deactivate()
      end
    end
    tablex.Clear(self._hookTokens)
  end
end
function Button:Show()
  local goButtonParent = self._buttonGOs.buttonParent
  if goButtonParent ~= nil then
    goButtonParent:Show()
    local buttonChildGONames = buttonUtil.GetButtonChildrenObjectNames()
    for _, childGOName in ipairs(buttonChildGONames) do
      local childGOs = self._buttonGOs[childGOName]
      if childGOs ~= nil then
        local goChild = childGOs[childGOName]
        if childGOName == self._buttonType then
          goChild:Show()
          local childSubGONames = buttonUtil.GetButtonChildrenSubObjectNames(childGOName)
          for _, subGOName in ipairs(childSubGONames) do
            local goChildSub = childGOs[subGOName]
            if goChildSub ~= nil then
              if subGOName == "text" then
                goChildSub:Show()
              else
                goChildSub:Hide()
              end
            end
          end
        else
          goChild:Hide()
        end
      end
    end
  end
  for _, activationSet in ipairs(self._activationList) do
    local settingsItem = activationSet.Item
    if settingsItem ~= nil then
      settingsItem:Update()
      settingsItem:Show()
    end
  end
end
function Button:Hide()
  local goButtonParent = self._buttonGOs.buttonParent
  if goButtonParent ~= nil then
    goButtonParent:Hide()
    local buttonChildGONames = buttonUtil.GetButtonChildrenObjectNames()
    for _, childGOName in ipairs(buttonChildGONames) do
      local childGOs = self._buttonGOs[childGOName]
      if childGOs ~= nil then
        local goChild = childGOs[childGOName]
        goChild:Hide()
        local childSubGONames = buttonUtil.GetButtonChildrenSubObjectNames(childGOName)
        for _, subGOName in ipairs(childSubGONames) do
          local goChildSub = childGOs[subGOName]
          if goChildSub ~= nil then
            goChildSub:Hide()
          end
        end
      end
    end
  end
  for _, activationSet in ipairs(self._activationList) do
    local settingsItem = activationSet.Item
    if settingsItem ~= nil then
      settingsItem:Hide()
    end
  end
end
function Button:SetupActivationList()
  for _, activationSet in ipairs(self._activationList) do
    local settingsItem = activationSet.Item
    if settingsItem ~= nil then
      settingsItem:Setup()
    end
  end
end
function Button:HasItem(item)
  assert(self._list._Button_ItemCompare ~= nil, "HasItem called on a Button without an ItemCompare method!!")
  return self._list._Button_ItemCompare(self:get_item(), item)
end
function Button:GainFocus(animateImmediately, useOnGainFocus, bypassHighlight)
  if self._list:get_active() == true then
    self:Activate()
  end
  if not bypassHighlight then
    self:HighlightOn(animateImmediately)
  end
  if useOnGainFocus == true then
    self:PlaySound(self._list._Button_onGainFocus_sound)
    if self._list._Button_OnGainFocus ~= nil then
      if (self._toggle == nil or self._buttonToolTip ~= nil) and not self._toggleToolTip then
        self._state:SendEventToUIFsm("globalMenu", "EVT_SET_FOOTER_TOOL_TIP_TOP", self._buttonToolTip)
      end
      self._list._Button_OnGainFocus(self)
      tutorialUtil.CheckConditionMet(self._state, tutorialConsts.EVENT_TYPE_BUTTON_ON_GAIN_FOCUS, self:get_item(), self._list._Button_ItemCompare)
    end
  end
end
function Button:LoseFocus(animateImmediately, bypassHighlight)
  self:Deactivate()
  if not bypassHighlight then
    self:HighlightOff(animateImmediately)
  end
  if self._list._Button_OnLoseFocus ~= nil then
    self._list._Button_OnLoseFocus(self)
  end
end
function Button:Update()
  if self._item == nil then
    self:UpdateNewIcon(nil)
    self:UpdateEquippedIcon(nil)
    self:HighlightOff(true)
    self:Hide()
  else
    self:Show()
  end
  self:SetText("text", self:get_text())
  if self._list._Button_Update ~= nil then
    self._list._Button_Update(self)
  end
end
function Button:UpdateNewIcon(showNotificationFunc)
  buttonUtil.UpdateIcon(self, "newIcon", showNotificationFunc)
end
function Button:UpdateEquippedIcon(showNotificationFunc, altShowNotificationFunc)
  buttonUtil.UpdateIcon(self, "equippedIcon", showNotificationFunc)
  buttonUtil.UpdateIcon(self, "equippedIcon2", altShowNotificationFunc)
end
function Button:UpdateCheckmark()
  buttonUtil.UpdateCheckmark(self)
end
function Button:AlphaFade(alpha, time)
  assert(alpha ~= nil, "Button:AlphaFade called without an alpha value!")
  assert(time ~= nil, "Button:AlphaFade called without a time value!")
  UI.AlphaFade(self:GetGameObject(), alpha, time)
end
function Button:GetGameObject()
  return self._buttonGOs.buttonParent
end
function Button:GetInstancedChildObject()
  local goChild
  local currButtonGOs = self._buttonGOs[self._buttonType]
  if currButtonGOs ~= nil then
    goChild = currButtonGOs[self._buttonType]
  end
  return goChild
end
function Button:GetChildSubObject(childSubGOName)
  local goChildSub
  local currButtonGOs = self._buttonGOs[self._buttonType]
  if currButtonGOs ~= nil then
    goChildSub = currButtonGOs[childSubGOName]
  end
  return goChildSub
end
function Button:GetTextHandle(textObjectName)
  local goTextHandle, thText
  if textObjectName == "text" then
    goTextHandle = self:GetChildSubObject("text")
  else
    goTextHandle = self:GetInstancedChildObject()
  end
  if goTextHandle ~= nil then
    thText = util.GetTextHandle(goTextHandle, textObjectName)
  end
  return thText
end
function Button:GetSortItem()
  if self._list._Button_GetSortItem ~= nil then
    return self._list._Button_GetSortItem(self)
  end
end
function Button:get_list()
  return self._list
end
function Button:get_active()
  return self._active
end
function Button:get_focusable()
  return self._focusable
end
function Button:get_item()
  return self._item
end
function Button:get_text()
  return self._text
end
function Button:set_text(text)
  self._text = text
end
function Button:get_checked()
  return self._checked
end
function Button:get_advance()
  return self._advance
end
function Button:get_activationList()
  return self._activationList
end
function Button:SetGameObjects(focusableObjectIndex)
  if focusableObjectIndex ~= nil then
    self._buttonGOs = self._list:GetButtonGameObjects(focusableObjectIndex)
    if self._buttonGOs == nil then
      self._buttonGOs = {}
    else
      assert(self._buttonGOs[self._buttonType] ~= nil, "Button:SetGameObject called with instance that does not have a button root object! (buttonType " .. self._buttonType .. ")")
      for _, activationSet in ipairs(self._activationList) do
        local settingsItem = activationSet.Item
        if settingsItem ~= nil then
          local settingsItemGOName
          local isInstance = classlib.isInstance(settingsItem)
          if isInstance and (settingsItem.CLASSNAME == "Toggle" or settingsItem.CLASSNAME == "Slider" or settingsItem.CLASSNAME == "Control") then
            local goItem = self:GetChildSubObject(settingsItem.CLASSNAME)
            if goItem ~= nil then
              settingsItem:SetGameObject(goItem)
            end
          end
        end
      end
    end
  end
end
function Button:SetText(textObjectName, text)
  local thText = self:GetTextHandle(textObjectName)
  if thText ~= nil then
    UI.SetText(thText, text or "")
  end
end
function Button:SetTextColor(color, material)
  local goText = self:GetChildSubObject("text")
  if goText ~= nil then
    util.SetGameObjectColor(goText, color, material or "medium_text", "LayerX", "cst_EmissiveTint")
  end
end
function Button:SetIcon(iconMaterialName)
  if iconMaterialName == nil then
    iconMaterialName = consts.EMPTY_MATERIAL_NAME
  end
  local goButtonChild = self:GetInstancedChildObject()
  goButtonChild:SetMaterialSwap(iconMaterialName)
end
function Button:SetDefaultValue()
  for _, activationSet in ipairs(self._activationList) do
    local item = activationSet.Item
    if item._default ~= nil then
      item:SetDefault()
    end
  end
end
function Button:HighlightOn(animateImmediately)
  if self._list._Button_HighlightOn ~= nil then
    self._list._Button_HighlightOn(self, animateImmediately)
  end
end
function Button:HighlightOff(animateImmediately)
  if self._list._Button_HighlightOff ~= nil then
    self._list._Button_HighlightOff(self, animateImmediately)
  end
end
function Button:PlaySound(soundName)
  if not util.IsStringNilOrEmpty(soundName) then
    Audio.PlaySound(soundName)
  end
end
return {Button = Button}
