local classlib = require("core.class")
local tablex = require("core.tablex")
local animationUtil = require("ui.animationUtil")
local characterUtil = require("ui.characterUtil")
local colors = require("ui.colors")
local consts = require("ui.consts")
local buttonUtil = require("ui.buttonUtil")
local emptyCard = require("ui.emptyCard")
local fsm = require("ui.fsm")
local iconConsts = require("ui.iconConsts")
local lamsIDs = require("ui.lamsConsts")
local list = require("ui.list")
local menu = require("ui.menu")
local pickupConsts = require("ui.pickupConsts")
local pickupUtil = require("ui.pickupUtil")
local statsCard = require("ui.statsCard")
local recipeUtil = require("ui.recipeUtil")
local resourceConsts = require("ui.resourceConsts")
local resourceUtil = require("ui.resourceUtil")
local runeUtil = require("ui.runeUtil")
local tutorialUtil = require("ui.tutorialUtil")
local util = require("ui.util")
local AI = game.AI
local Audio = game.Audio
local Player = game.Player
local UI = game.UI
local Pickup = game.Pickup
local g_originalRuneOwnerPickup
local g_originalRuneOwnerSocket = pickupConsts.INVALID_SOCKET_INDEX
local UpgradeMenu = classlib.Class("UpgradeMenu", fsm.UIState)
local UpgradeOff = UpgradeMenu:StateClass("UpgradeOff", fsm.UIState)
local UpgradeOn = UpgradeMenu:StateClass("UpgradeOn", fsm.UIState)
local PickupUpgrade = UpgradeMenu:StateClass("PickupUpgrade", fsm.UIState)
local upgradeMenu = UpgradeMenu.New("upgradeMenu", {
  UpgradeOff,
  UpgradeOn,
  {PickupUpgrade}
})
function UpgradeMenu:Setup()
end
function UpgradeMenu:Enter()
  self:WantPadEvents(true)
  self:TurnOff()
end
function UpgradeMenu:TurnOff()
  self:Goto("UpgradeOff")
end
UpgradeMenu.EVT_GAME_OVER = UpgradeMenu.TurnOff
UpgradeMenu.EVT_Restart = UpgradeMenu.TurnOff
function UpgradeOff:Setup()
  self.upgradeOn = self:GetState("UpgradeOn")
end
function UpgradeOff:Enter()
end
function UpgradeOff:Exit()
end
function UpgradeOff:EVT_TURN_ON_UPGRADE_MENU(pickupBeingUpgraded, menuOpenedFromArmorSublist, instructionEntries, instructionArgs)
  self.upgradeOn.pickupBeingUpgraded = pickupBeingUpgraded
  self.upgradeOn._menuOpenedFromArmorSublist = menuOpenedFromArmorSublist
  self.upgradeOn.substateCharacter = pickupConsts.TAG_PICKUP_KRATOS
  if pickupUtil.IsValidName(pickupBeingUpgraded) and pickupUtil.HasTag(pickupBeingUpgraded, pickupConsts.TAG_PICKUP_SON) then
    self.upgradeOn.substateCharacter = pickupConsts.TAG_PICKUP_SON
  end
  self.upgradeOn.pickupUpgrade.menu:set_instructionEntries(instructionEntries)
  self.upgradeOn.pickupUpgrade.menu:set_instructionArgs(instructionArgs)
  self:Goto("UpgradeOn")
end
function UpgradeOn:Setup()
  self.pickupBeingUpgraded = nil
  self.pickupUpgrade = self:GetState("PickupUpgrade")
end
function UpgradeOn:Enter()
  util.Show("Upgrade")
  self:Goto("PickupUpgrade")
end
function UpgradeOn:Exit()
  util.Hide("Upgrade")
end
function UpgradeOn:CanOpenSubList()
  return true
end
function UpgradeOn:GetCreature(forceGetKratos)
  local creature
  if forceGetKratos == true then
    creature = Player.FindPlayer()
  else
    creature = self.substateCharacter == pickupConsts.TAG_PICKUP_KRATOS and Player.FindPlayer() or AI.FindSon()
  end
  assert(creature ~= nil, "UpgradeOn:GetCreature was not able to find a creature!")
  return creature
end
function UpgradeOn:Menu_BackReleaseHandler()
  self:SendEventToUIFsm("statsMenu", "EVT_RETURN_FROM_SUB_MENU")
end
function UpgradeOn:EVT_TURN_OFF_UPGRADE_MENU()
  self:Goto("UpgradeOff")
end
function PickupUpgrade:Setup()
  self.upgradeOn = self:GetState("UpgradeOn")
  self._officiallyEquippedRuneID = pickupConsts.INVALID_RUNE_ID
  self._officiallyEquippedRuneInfo = nil
  self._allRuneInfoTables = nil
  self._waitingForEquippedAttributes = false
  self._onGainFocusWhenAttributesUpdated = false
  self.menu = menu.Menu.New(self, {
    FooterButtonInfo = {
      {
        Item = "Equip",
        Text = "[AdvanceButton] " .. util.GetLAMSMsg(lamsIDs.Equip)
      },
      {
        Item = "Unsocket",
        Text = "[AdvanceButton] " .. util.GetLAMSMsg(lamsIDs.Unequip)
      },
      {
        Item = "Select",
        Text = "[AdvanceButton] " .. util.GetLAMSMsg(lamsIDs.Select)
      },
      {
        Item = "Back",
        Text = "[BackButton] " .. util.GetLAMSMsg(lamsIDs.Back)
      },
      {
        Item = "Exit",
        Text = "[BackButton] " .. util.GetLAMSMsg(lamsIDs.Exit)
      },
      {
        Item = "Close",
        Text = "",
        EventHandlers = {
          {
            Events = {
              "EVT_Options_Release"
            },
            Handler = function()
              self:Menu_OptionsReleaseHandler()
            end
          }
        }
      }
    },
    Name = self.name
  })
  local runeSocketsListName = self.menu:get_name() .. "_MainList"
  local runeSocketsList = list.List.New(self, {
    MaxFocusableObjectCount = 4,
    Name = runeSocketsListName,
    ListObjectName = "UpgradeSocketList",
    HoverToSelect = true,
    EventHandlers = {
      {
        Events = {
          "EVT_Advance_Release"
        },
        Handler = function()
          self:MainList_AdvanceReleaseHandler()
        end
      },
      {
        Events = {
          "EVT_MOUSE_RELEASED"
        },
        Handler = function()
          local selected = UI.GetEventSenderGameObject()
          local list = self.menu:GetList("MainList")
          local button = list:GetSelectedButton()
          if button ~= nil and selected == button:GetInstancedChildObject() then
            self:MainList_AdvanceReleaseHandler()
          end
        end
      },
      {
        Events = {
          "EVT_Back_Release",
          "EVT_MOUSE_RIGHT_CLICKED"
        },
        Handler = function()
          self:MainList_BackReleaseHandler()
        end
      },
      {
        Events = {
          "EVT_Square_Release"
        },
        Handler = function()
          self:MainList_SquareReleaseHandler()
        end
      }
    },
    Button_Update = function(button)
      self:MainList_Button_Update(button)
    end,
    Button_OnGainFocus = function(button)
      self:MainList_Button_OnGainFocus(button)
    end,
    Button_HighlightOn = function(button, animateImmediately)
      self:MainList_Button_HighlightOn(button, animateImmediately)
    end,
    Button_HighlightOff = function(button, animateImmediately)
      self:MainList_Button_HighlightOff(button, animateImmediately)
    end
  })
  self.menu:SetList("MainList", runeSocketsList)
  tutorialUtil.RegisterDesaturationList(runeSocketsListName, runeSocketsList)
  runeSocketsList:SetSelectedButton(1, false)
  self.menu:SetupSubLists("PickupList_EquippedItem", runeUtil.GetSocketNames(), runeUtil.RuneInfo_Compare, function(button)
    return self:GetSortItem(button)
  end, recipeUtil.SubList_Sort_Runes)
  local goSublist = util.GetUiObjByName("PickupList_EquippedItem")
  local goSortList = goSublist:FindSingleGOByName("list_sort_nav")
  self.menu:SetupSortList("SortList", goSortList)
  local goStatsCard = util.GetUiObjByName("statsdetail_card_statsMenu")
  self.statsCard = statsCard.StatsCard.New(goStatsCard)
  local gostatsCard_Comparison = util.GetUiObjByName("statsdetail_card_statsMenu_comparison")
  self.statsCard_Comparison = statsCard.StatsCard.New(gostatsCard_Comparison)
  local goEmptyCard = util.GetUiObjByName("EmptyCard")
  self._emptyCard = emptyCard.EmptyCard.New(goEmptyCard)
  local isRuneCard = true
  self._emptyCard:Init(isRuneCard)
  local isVendorCard = false
  local isComparisonCard = false
  self.statsCard:Init(isVendorCard, isComparisonCard, {
    ComparisonCard = self.statsCard_Comparison
  })
  isVendorCard = false
  isComparisonCard = true
  self.statsCard_Comparison:Init(isVendorCard, isComparisonCard, {
    NonComparisonCard = self.statsCard
  })
  self.goUpgradeSocketList = util.GetUiObjByName("UpgradeSocketList")
  self.goUpgradeSocketList_Talisman = util.GetUiObjByName("UpgradeSocketList_Talisman")
  tutorialUtil.RegisterDesaturationObject("Upgrade_Stats_Card", goStatsCard)
end
function PickupUpgrade:Enter()
  self.menu:Activate()
  self._officiallyEquippedRuneID = pickupConsts.INVALID_RUNE_ID
  self._officiallyEquippedRuneInfo = nil
  self._waitingForEquippedAttributes = false
  self._onGainFocusWhenAttributesUpdated = false
  self._backingOutToPickupList = false
  self._delayClearNew = true
  local runeIDs, runeInfoTables = runeUtil.GetRunes(false, nil, nil, resourceConsts.POWER_LEVEL_SORTING)
  self._allRuneInfoTables = runeInfoTables
  self:SendEventToUIFsm("statsMenu", "EVT_SHOW_SUB_MENU_LIST")
  local runeSocketsList = self.menu:GetList("MainList")
  local currPickupSlot = pickupUtil.GetSlotName(self.upgradeOn.pickupBeingUpgraded)
  local goList = currPickupSlot == pickupConsts.Slot_ArmorTrinket and self.goUpgradeSocketList_Talisman or self.goUpgradeSocketList
  runeSocketsList:SetGameObject(goList)
  local newItemArray = self:GetSocketSlotsListNames(self.upgradeOn.pickupBeingUpgraded)
  local showList = true
  local useOnGainFocus = false
  local itemDetermineFocusabilityFunc
  local itemGetTextFunc = runeUtil.GetSocketDisplayName
  runeSocketsList:Refresh(newItemArray, showList, useOnGainFocus, itemDetermineFocusabilityFunc, itemGetTextFunc)
  runeSocketsList:SetSelectedButton(1, false)
  self.comparisonToggled = false
  self:EnableItemComparison(self.comparisonToggled)
  local animTime = 0
  animationUtil.SetUpgradeSlotPositions(runeSocketsList, animTime)
  local forUpgradeSlots = true
  animationUtil.ResetPickupSlotPositions(runeSocketsList, forUpgradeSlots)
  local sortListName = self.menu:get_sortListName()
  local sortList = self.menu:GetList(sortListName)
  local sort_newItemArray = resourceUtil.GetSortGroups(resourceConsts.SORTING_GROUP_RARITY_STATS_EFFECTS)
  local sort_showList = false
  local sort_useOnGainFocus = false
  local sort_itemDetermineFocusabilityFunc
  local sort_getDisplayNameFunc = resourceUtil.GetSortGroupDisplayName
  sortList:Refresh(sort_newItemArray, sort_showList, sort_useOnGainFocus, sort_itemDetermineFocusabilityFunc, sort_getDisplayNameFunc)
  sortList:SetSelectedButton(1, false)
  local showAll = false
  local doDefaultAnimTransition = false
  self.statsCard:ShowCard(showAll, doDefaultAnimTransition)
  showAll = false
  doDefaultAnimTransition = false
  self.statsCard_Comparison:ShowCard(showAll, doDefaultAnimTransition)
  self.statsCard_Comparison:HideCard()
  self.statsCard:SetButtonStates("", "")
  self.statsCard_Comparison:SetButtonStates("", "")
  if not self.menu:HasInstructionEntryForMenuState() then
    local reselect_useOnGainFocus = true
    runeSocketsList:ReselectSelectedItem(reselect_useOnGainFocus)
  end
  self.menu:ExecuteInstructions()
end
function PickupUpgrade:Exit()
  self:CancelRunePreview()
  self.menu:Deactivate(true)
end
function PickupUpgrade:GetSortItem(button)
  local runeInfo = button:get_item()
  return runeUtil.GetRuneInfoRuneID(runeInfo)
end
function PickupUpgrade:IsHeaderSlot(socketName)
  return type(socketName) ~= "number" and pickupUtil.IsValidSlotName(socketName)
end
function PickupUpgrade:GetSocketSlotsListNames(pickupName)
  local buttonListSlotNames = {pickupName}
  local socketNames = runeUtil.GetSocketNames(pickupName)
  for _, socketName in ipairs(socketNames) do
    tablex.FastInsert(buttonListSlotNames, socketName, #buttonListSlotNames + 1)
  end
  return buttonListSlotNames
end
function PickupUpgrade:IsRuneOfficiallyEquipped(runeID)
  return runeUtil.IsValidRuneID(runeID) and runeUtil.IsValidRuneID(self._officiallyEquippedRuneID) and runeID == self._officiallyEquippedRuneID
end
function PickupUpgrade:SelectRune(currSocketIndex, currRuneInfo)
  self:UpdateSelectedRuneInfo(currSocketIndex, currRuneInfo)
  local currRuneID = runeUtil.GetRuneInfoRuneID(currRuneInfo)
  local isRuneOfficiallyEquipped = self:IsRuneOfficiallyEquipped(currRuneID)
  local doesRuneExist = currRuneInfo ~= nil
  local character = pickupConsts.TAG_PICKUP_KRATOS
  local currentlyEquippedRuneInfo = runeUtil.GetRuneInfoInSocketFromPickup(self.upgradeOn.pickupBeingUpgraded, currSocketIndex)
  local currentlyEquippedRuneID = runeUtil.GetRuneInfoRuneID(currentlyEquippedRuneInfo)
  if g_originalRuneOwnerPickup ~= nil then
    runeUtil.UnsocketRune(g_originalRuneOwnerPickup, g_originalRuneOwnerSocket)
  end
  self._runePreviewed = true
  if currentlyEquippedRuneInfo ~= nil then
    runeUtil.UnsocketRune(self.upgradeOn.pickupBeingUpgraded, currSocketIndex)
  end
  runeUtil.PreviewRune(resourceConsts.WALLET_KRATOS, self.upgradeOn.pickupBeingUpgraded, currSocketIndex, currRuneID, pickupConsts.INVALID_RUNE_ID)
  self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_ATTRIBUTES_PREVIEW", character)
  self.statsCard:SetButtonState_Middle(nil)
  self:UpdateFooterButtonPrompt(doesRuneExist, true, true, isRuneOfficiallyEquipped)
end
function PickupUpgrade:UnselectRune(currSocketIndex, currRuneInfo)
  runeUtil.UnsocketRune(self.upgradeOn.pickupBeingUpgraded, currSocketIndex)
  if g_originalRuneOwnerPickup ~= nil then
    runeUtil.SocketRune(resourceConsts.WALLET_KRATOS, g_originalRuneOwnerPickup, g_originalRuneOwnerSocket, currRuneInfo.Id, pickupConsts.INVALID_RUNE_ID)
    g_originalRuneOwnerPickup = nil
    g_originalRuneOwnerSocket = pickupConsts.INVALID_SOCKET_INDEX
  end
end
function PickupUpgrade:CancelRunePreview()
  local mainList = self.menu:GetList("MainList")
  local socketIndex = mainList:GetSelectedItem()
  local sublistIsActive = not mainList:get_active()
  if sublistIsActive then
    local equippedRuneInfo = runeUtil.GetRuneInfoInSocketFromPickup(self.upgradeOn.pickupBeingUpgraded, socketIndex)
    local equippedRuneID = runeUtil.GetRuneInfoRuneID(equippedRuneInfo)
    self:UnselectRune(socketIndex, equippedRuneInfo)
    runeUtil.PreviewRune(resourceConsts.WALLET_KRATOS, self.upgradeOn.pickupBeingUpgraded, socketIndex, self._officiallyEquippedRuneID, pickupConsts.INVALID_RUNE_ID)
    self._officiallyEquippedRuneID = pickupConsts.INVALID_RUNE_ID
    self._officiallyEquippedRuneInfo = nil
    self._runePreviewed = false
    if self:PickupBeingUpgradedIsEquipped() then
      self:SendEventToUIFsm("inWorldMenu", "EVT_CLEAR_ATTRIBUTES_PREVIEW")
    end
  else
    self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_ATTRIBUTES_PREVIEW", pickupConsts.TAG_PICKUP_KRATOS)
  end
end
function PickupUpgrade:CloseSubList(socketIndex)
  self:SendEventToUIFsm("statsMenu", "EVT_SHOW_SUB_MENU_LIST")
  local runeList = self.menu:GetList(socketIndex)
  local hideList = true
  local clearButtons = false
  runeList:Deactivate(hideList, clearButtons)
  local sortListName = self.menu:get_sortListName()
  local sortList = self.menu:GetList(sortListName)
  local sortList_hideList = true
  local sortList_clearButtons = false
  sortList:Deactivate(sortList_hideList, sortList_clearButtons)
  local runeSocketsList = self.menu:GetList("MainList")
  local showList = true
  local useOnGainFocus = true
  runeSocketsList:Activate(showList, useOnGainFocus)
  local forUpgradeSlots = true
  animationUtil.ResetPickupSlotPositions(runeSocketsList, forUpgradeSlots)
  runeSocketsList:ShowHeader()
end
function PickupUpgrade:UpdateSelectedRuneInfo(currSocketIndex, runeInfo)
  local runeID = runeUtil.GetRuneInfoRuneID(runeInfo)
  if runeUtil.IsValidRuneID(runeID) then
    local itemType = resourceConsts.RESOURCE_FLAG_RUNE
    local character = pickupConsts.TAG_PICKUP_KRATOS
    local currentSublist = self.menu:GetList(currSocketIndex)
    local subListIsOpen = currentSublist:get_active()
    local itemIsEquipped = not subListIsOpen or runeID == self._officiallyEquippedRuneID
    local canEquip = not itemIsEquipped and subListIsOpen
    local rightButtonMsg, middleButtonMsg
    self._canCompare = runeUtil.IsValidRuneID(self._officiallyEquippedRuneID) and runeID ~= self._officiallyEquippedRuneID and subListIsOpen
    if self._canCompare then
      rightButtonMsg = "[R3]" .. util.GetLAMSMsg(lamsIDs.Compare)
    end
    self:HandleRuneComparisonLogic(runeID)
    self.statsCard:SetItem(runeInfo, itemType, character, itemIsEquipped)
    self.statsCard:SetButtonState_Right(rightButtonMsg)
    self.statsCard:SetButtonState_Middle(middleButtonMsg)
    self._emptyCard:HideCard()
  else
    self.statsCard:ClearCard()
    self.statsCard:HideCard()
    self._emptyCard:Update(currSocketIndex)
    self._emptyCard:ShowCard()
  end
end
function PickupUpgrade:HandleRuneComparisonLogic(currentlySelectedRune)
  if self.comparisonToggled then
    local runeIDInSocket = self._officiallyEquippedRuneID
    if runeIDInSocket and currentlySelectedRune ~= runeIDInSocket then
      local equippedRuneInfo = self._officiallyEquippedRuneInfo
      if equippedRuneInfo ~= nil then
        local itemIsEquipped = true
        self.statsCard_Comparison:ShowCard()
        self.statsCard_Comparison:SetItem(equippedRuneInfo, resourceConsts.RESOURCE_FLAG_RUNE, pickupConsts.TAG_PICKUP_KRATOS, itemIsEquipped)
        self:SendEventToUIFsm("inWorldMenu", "EVT_SMALL_ATTRIBUTE_CARD")
      else
        self.statsCard_Comparison:HideCard()
        self:SendEventToUIFsm("inWorldMenu", "EVT_LARGE_ATTRIBUTE_CARD")
      end
    else
      self.statsCard_Comparison:HideCard()
      self:SendEventToUIFsm("inWorldMenu", "EVT_LARGE_ATTRIBUTE_CARD")
    end
  else
    self.statsCard_Comparison:HideCard()
    self:SendEventToUIFsm("inWorldMenu", "EVT_LARGE_ATTRIBUTE_CARD")
  end
end
function PickupUpgrade:AllRuneInfoTable_RefreshSingle(runeID, forceUnequip)
  local newRuneInfo = runeUtil.GetRuneInfo(runeID)
  for i, runeInfo in ipairs(self._allRuneInfoTables) do
    if runeUtil.RuneInfo_Compare(newRuneInfo, runeInfo) == true then
      if forceUnequip == true then
        self._allRuneInfoTables[i].Pickup = engine.Hash("")
        self._allRuneInfoTables[i].SocketIndex = pickupConsts.INVALID_SOCKET_INDEX
        break
      end
      self._allRuneInfoTables[i] = newRuneInfo
      break
    end
  end
end
function PickupUpgrade:GetRuneInfo(runeID)
  for _, runeInfo in ipairs(self._allRuneInfoTables) do
    if runeInfo.Id == runeID then
      return runeInfo
    end
  end
  return nil
end
function PickupUpgrade:GetRuneInfoTables(currState, socketIndex)
  local availableRuneInfoTables = {}
  for _, runeInfo in ipairs(self._allRuneInfoTables) do
    local keepRuneInfo = true
    if runeUtil.RuneInfo_IsSocketed(runeInfo) then
      local currRuneOwnerPickup = Pickup.GetName(runeInfo.Pickup)
      if characterUtil.ItemIsEquipped(currRuneOwnerPickup) and not runeUtil.RuneInfo_IsRuneInSocket(runeInfo, self.upgradeOn.pickupBeingUpgraded, socketIndex) then
        keepRuneInfo = false
      end
    end
    if keepRuneInfo then
      tablex.FastInsert(availableRuneInfoTables, runeInfo, #availableRuneInfoTables + 1)
    end
  end
  return availableRuneInfoTables
end
function PickupUpgrade:UpdateRuneListBySocket(currState, currSocketIndex, useOnGainFocus, selectEquippedItem)
  local subListName = currSocketIndex
  local headerText = runeUtil.GetSocketDisplayName(currSocketIndex)
  local getSubListItemsFunc = function(socketIndex)
    return self:GetRuneInfoTables(currState, socketIndex)
  end
  local itemDetermineFocusabilityFunc
  local itemGetTextFunc = runeUtil.GetRuneInfoDisplayName
  local deactivateSublist = false
  currState.menu:RefreshEquippedItemSublist(subListName, headerText, getSubListItemsFunc, self._officiallyEquippedRuneInfo, itemDetermineFocusabilityFunc, itemGetTextFunc, useOnGainFocus, selectEquippedItem, deactivateSublist)
  local sortListName = self.menu:get_sortListName()
  local sortList = self.menu:GetList(sortListName)
  if sortList:get_active() == false then
    local subList = currState.menu:GetList(subListName)
    if subList:GetButtonCount() > 1 then
      local sortList_showList = true
      sortList:Activate(sortList_showList, useOnGainFocus)
      self.menu:AnimateSortList()
    end
  end
end
function PickupUpgrade:UpdateFooterButtonPrompt(doesRuneExist, subListOpen, canOpenSubList, showRuneEquip)
  local canSelect = not subListOpen and canOpenSubList
  self.menu:UpdateFooterButton("Unsocket", subListOpen and showRuneEquip)
  self.menu:UpdateFooterButton("Equip", subListOpen and not showRuneEquip)
  self.menu:UpdateFooterButton("Select", canSelect)
  self.menu:UpdateFooterButton("Back", subListOpen)
  self.menu:UpdateFooterButton("Exit", not subListOpen)
  self.menu:UpdateFooterButton("Close", true)
  self.menu:UpdateFooterButtonText()
end
function PickupUpgrade:SortList_Button_OnGainFocus(button)
  local runeSocketsList = self.menu:GetList("MainList")
  local currSocketIndex = runeSocketsList:GetSelectedItem()
  if runeUtil.IsValidSocketIndex(currSocketIndex) then
    local subList = self.menu:GetList(currSocketIndex)
    local sortingGroup = resourceUtil.GetSortGroupFromMenu(self.menu)
    subList:Sort(sortingGroup, nil, true, false)
    local labelText = resourceUtil.GetSortGroupLabelDisplayText(button:get_item())
    self.menu:SetMenuListLabelText("SortList", labelText)
  else
    local sortListName = self.menu:get_sortListName()
    local sortList = self.menu:GetList(sortListName)
    local sortList_hideList = true
    local sortList_clearButtons = false
    sortList:Deactivate(sortList_hideList, sortList_clearButtons)
  end
end
function PickupUpgrade:MainList_Button_Update(button)
  local buttonItem = button:get_item()
  local isRune = type(buttonItem) == "number"
  local currentSocketName = isRune and buttonItem or pickupUtil.GetSlotName(buttonItem)
  local isHeaderSlot = self:IsHeaderSlot(buttonItem)
  local socketedRuneID
  local socketedRuneColor = colors.BLACK
  local socketedRuneIcon = ""
  if buttonItem ~= nil then
    if self._clearPickupIcon then
      socketedRuneID = -1
      self._clearPickupIcon = false
    elseif isRune then
      local socketedRuneInfo = runeUtil.GetRuneInfoInSocketFromPickup(self.upgradeOn.pickupBeingUpgraded, buttonItem)
      socketedRuneID = runeUtil.GetRuneInfoRuneID(socketedRuneInfo)
    end
    if runeUtil.IsValidRuneID(socketedRuneID) then
      socketedRuneColor = runeUtil.GetRuneColorFromID(socketedRuneID)
      socketedRuneIcon = runeUtil.GetRuneIconFromID(socketedRuneID)
    end
    local isTalismanButton = false
    if isHeaderSlot then
      local creature = self.upgradeOn:GetCreature(false)
      local pickupName = buttonItem
      local pickupSlotName = pickupUtil.GetSlotName(pickupName)
      local headerButtonEquippedPickupName = pickupUtil.GetPickupNameInSlot(creature, pickupSlotName)
      isTalismanButton = pickupSlotName == pickupConsts.Slot_ArmorTrinket
      if isTalismanButton then
        socketedRuneIcon = iconConsts.GetIcon(headerButtonEquippedPickupName)
      else
        socketedRuneIcon = resourceUtil.GetMaterialSwapName(headerButtonEquippedPickupName)
      end
      if pickupUtil.IsValidName(pickupName) then
        socketedRuneColor = resourceUtil.GetRarityColor(pickupName)
      end
      buttonUtil.UpdateSlotButtonColor(button, pickupName, socketedRuneColor, isTalismanButton)
    else
      buttonUtil.UpdateUpgradeButtonColor(button, socketedRuneID, socketedRuneColor)
    end
    button:SetText("text_level", "")
    if isHeaderSlot and not isTalismanButton then
      button:SetIcon(socketedRuneIcon)
    else
      button:SetText("icon_text", socketedRuneIcon)
    end
  end
end
function PickupUpgrade:MainList_Button_OnGainFocus(button)
  local currItem = button:get_item()
  local currList = button:get_list()
  local isRune = type(currItem) == "number"
  if not isRune then
    if currItem ~= nil then
      local pickupSlot = pickupUtil.GetSlotName(currItem)
      currList:SetHeaderText(pickupUtil.GetSlotDisplayName(pickupSlot))
      local showAll = false
      local isEquipped
      self.statsCard:ShowCard(showAll)
      self.statsCard:SetItem(currItem, resourceConsts.RESOURCE_FLAG_PICKUP, pickupConsts.TAG_PICKUP_KRATOS, isEquipped, {})
      self.statsCard:SetButtonStates(nil, nil)
      self.statsCard:SetButtonState_Middle(nil)
      self._emptyCard:HideCard()
    else
      self.statsCard:HideCard()
    end
    local currentPickupSlot = pickupUtil.GetSlotName(self.upgradeOn.pickupBeingUpgraded)
    if currentPickupSlot == pickupConsts.Slot_ArmorTrinket then
      self:SendEventToUIFsm("globalMenu", "EVT_SET_FOOTER_TOOL_TIP", util.GetLAMSMsg(lamsIDs.TalismanTooltip))
    else
      self:SendEventToUIFsm("globalMenu", "EVT_SET_FOOTER_TOOL_TIP", util.GetLAMSMsg(lamsIDs.ArmorMenuTooltip))
    end
    self:UpdateFooterButtonPrompt(false, false, false, false)
  else
    local currentPickupName = self.upgradeOn.pickupBeingUpgraded
    local currRuneInfo = runeUtil.GetRuneInfoInSocketFromPickup(currentPickupName, currItem)
    local runeExists = currRuneInfo ~= nil
    local isRuneEquipped = runeExists
    local subListOpen = false
    if runeExists then
      local showAll = false
      self.statsCard:ShowCard(showAll)
    else
      self.statsCard:HideCard()
    end
    currList:SetHeaderText(runeUtil.GetSocketDisplayName(currItem))
    self:UpdateSelectedRuneInfo(currItem, currRuneInfo)
    self.statsCard:SetButtonState_Left(isRuneEquipped and "[SquareButton] " .. util.GetLAMSMsg(lamsIDs.UnsocketEnchantmentPrompt) or nil, nil)
    self.statsCard:SetButtonState_Middle(nil)
    self:UpdateFooterButtonPrompt(runeExists, subListOpen, self.upgradeOn:CanOpenSubList())
  end
end
function PickupUpgrade:SubList_Button_Update(button)
  local currRuneInfo = button:get_item()
  local currRuneID = runeUtil.GetRuneInfoRuneID(currRuneInfo)
  local runeIsSocketed = runeUtil.RuneInfo_IsSocketed(self:GetRuneInfo(currRuneID))
  local runeSocketsList = self.menu:GetList("MainList")
  local socketIndex = runeSocketsList:GetSelectedItem()
  local runeIsSocketedInThisSocket = runeUtil.RuneInfo_IsRuneInSocket(self:GetRuneInfo(currRuneID), self.upgradeOn.pickupBeingUpgraded, socketIndex)
  local shouldGrayOut = runeIsSocketed and not runeIsSocketedInThisSocket
  button:UpdateEquippedIcon(function(button)
    return self:IsRuneOfficiallyEquipped(currRuneID)
  end, function(button)
    return shouldGrayOut
  end)
  local textColor = shouldGrayOut and colors.GRAY or colors.WHITE
  button:SetTextColor(textColor)
  local runeColor = colors.BLACK
  if runeUtil.IsValidRuneID(currRuneID) then
    runeColor = runeUtil.GetRuneColorFromID(currRuneID)
  end
  buttonUtil.UpdateColorQuad(button, runeColor)
  self.statsCard:SetButtonState_Left(nil)
  local effectFlag = runeUtil.GetEffectFlagFromID(currRuneID)
  local effectFlagIcon = ""
  if effectFlag ~= nil then
    effectFlagIcon = iconConsts[effectFlag]
  end
  button:SetText("icon_text", effectFlagIcon)
  button:UpdateNewIcon(function(button)
    return buttonUtil.ShowNotification(button, consts.NotificationTypes.Rune)
  end)
end
function PickupUpgrade:MainList_Button_HighlightOn(button, animateImmediately)
  local currSelectionID = button:get_item()
  local buttonIsForRunes = type(currSelectionID) == "number"
  if currSelectionID ~= nil and not buttonIsForRunes then
    buttonUtil.StatsMenuPickupSlot_HighlightOn(button, animateImmediately)
  else
    buttonUtil.DefaultButtonHighlightOn(button, animateImmediately)
  end
end
function PickupUpgrade:MainList_Button_HighlightOff(button, animateImmediately)
  local currSelectionID = button:get_item()
  local buttonIsForRunes = type(currSelectionID) == "number"
  if currSelectionID ~= nil and not buttonIsForRunes then
    buttonUtil.StatsMenuPickupSlot_HighlightOff(button, animateImmediately)
  else
    buttonUtil.DefaultButtonHighlightOff(button, animateImmediately)
  end
end
function PickupUpgrade:SubList_Button_OnGainFocus(button)
  local listRuneInfo = button:get_item()
  local tableRuneInfo = self:GetRuneInfo(listRuneInfo.Id)
  local runeSocketsList = self.menu:GetList("MainList")
  local currSocketIndex = runeSocketsList:GetSelectedItem()
  local unsocketWarningTooltip = false
  if runeUtil.RuneInfo_IsSocketed(tableRuneInfo) then
    local originalRuneOwner = Pickup.GetName(tableRuneInfo.Pickup)
    g_originalRuneOwnerPickup = originalRuneOwner
    g_originalRuneOwnerSocket = tableRuneInfo.SocketIndex
    assert(g_originalRuneOwnerPickup ~= nil, "A socketed rune does not have pickup?")
    if not self:IsRuneOfficiallyEquipped(runeUtil.GetRuneInfoRuneID(tableRuneInfo)) then
      unsocketWarningTooltip = true
    end
  end
  if unsocketWarningTooltip then
    self:SendEventToUIFsm("globalMenu", "EVT_SET_FOOTER_TOOL_TIP", util.GetLAMSMsg(lamsIDs.UnsocketFromAnotherArmor))
  else
    self:SendEventToUIFsm("globalMenu", "EVT_SET_FOOTER_TOOL_TIP", "")
  end
  self:SelectRune(currSocketIndex, tableRuneInfo)
end
function PickupUpgrade:SubList_Button_OnLoseFocus(button)
  local currRuneInfo = button:get_item()
  local currRuneID = runeUtil.GetRuneInfoRuneID(currRuneInfo)
  local runeSocketsList = self.menu:GetList("MainList")
  local currSocketIndex = runeSocketsList:GetSelectedItem()
  if self._runePreviewed then
    self:UnselectRune(currSocketIndex, currRuneInfo)
  end
  if self._delayClearNew then
    self._delayClearNew = false
  elseif runeUtil.IsValidRuneID(currRuneID) then
    runeUtil.ClearNew(currRuneID)
    button:UpdateNewIcon(function(button)
      return buttonUtil.ShowNotification(button, consts.NotificationTypes.Rune)
    end)
  end
end
function PickupUpgrade:Menu_OptionsReleaseHandler()
  self:SendEventToUIFsm("globalMenu", "EVT_TURN_OFF_GLOBAL_MENU")
end
function PickupUpgrade:MainList_AdvanceReleaseHandler()
  local runeSocketsList = self.menu:GetList("MainList")
  local currentlySelectedID = runeSocketsList:GetSelectedItem()
  local selectionIsRune = type(currentlySelectedID) == "number"
  if self.upgradeOn:CanOpenSubList() == true and selectionIsRune then
    local submenu_hideList = true
    self:SendEventToUIFsm("statsMenu", "EVT_HIDE_SUB_MENU_LIST", submenu_hideList)
    local hideList = false
    local clearButtons = false
    runeSocketsList:Deactivate(hideList, clearButtons)
    animationUtil.AnimatePickupSlotPositions(runeSocketsList, "PickupSlot_Selected_EquippedItem", buttonUtil.DefaultButtonHighlightOn)
    runeSocketsList:HideHeader()
    local selectedButton = runeSocketsList:GetSelectedButton()
    selectedButton:UpdateNewIcon(nil)
    selectedButton:HighlightOff(true)
    self._officiallyEquippedRuneInfo = runeUtil.GetRuneInfoInSocketFromPickup(self.upgradeOn.pickupBeingUpgraded, currentlySelectedID)
    self._officiallyEquippedRuneID = runeUtil.GetRuneInfoRuneID(self._officiallyEquippedRuneInfo)
    self._runePreviewed = false
    local useOnGainFocus = true
    local selectEquippedItem = true
    self:UpdateRuneListBySocket(self, currentlySelectedID, useOnGainFocus, selectEquippedItem)
    Audio.PlaySound("SND_UX_Menu_Tick_Confirm")
    local subList = self.menu:GetList(currentlySelectedID)
    if subList:GetButtonCount() > 0 then
      Audio.PlaySound("SND_UX_Menu_Tick_Confirm")
    else
      Audio.PlaySound("SND_UX_Menu_Tick_Fail")
    end
  else
    Audio.PlaySound("SND_UX_Menu_Tick_Fail")
  end
end
function PickupUpgrade:MainList_BackReleaseHandler()
  if self:PickupBeingUpgradedIsEquipped() then
    self:SendEventToUIFsm("inWorldMenu", "EVT_CLEAR_ATTRIBUTES_PREVIEW")
  end
  local runeSocketsList = self.menu:GetList("MainList")
  local animTime = 0.15
  animationUtil.SetUpgradeSlotPositions(runeSocketsList, animTime)
  local pickupToOpenTo
  if self.upgradeOn._menuOpenedFromArmorSublist then
    pickupToOpenTo = self.upgradeOn.pickupBeingUpgraded
  end
  self.upgradeOn._menuOpenedFromArmorSublist = false
  self._backingOutToPickupList = true
  self:SendEventToUIFsm("statsMenu", "EVT_START_RETURN_FROM_SUB_MENU", pickupToOpenTo)
  self:StartTimer("UpgradeMenuReturnAnimationDelay", animTime, function()
    self.upgradeOn:Menu_BackReleaseHandler()
  end)
  Audio.PlaySound("SND_UX_Menu_Tick_Back")
end
function PickupUpgrade:PickupBeingUpgradedIsEquipped()
  return characterUtil.ItemIsEquipped(self.upgradeOn.pickupBeingUpgraded)
end
function PickupUpgrade:MainList_SquareReleaseHandler()
  local mainList = self.menu:GetList("MainList")
  local socketIndex = mainList:GetSelectedItem()
  local selectingRuneSlot = type(socketIndex) == "number"
  if selectingRuneSlot then
    local currEquippedRuneInfo = runeUtil.GetRuneInfoInSocketFromPickup(self.upgradeOn.pickupBeingUpgraded, socketIndex)
    if currEquippedRuneInfo ~= nil then
      local equippedRuneID = runeUtil.GetRuneInfoRuneID(currEquippedRuneInfo)
      runeUtil.UnsocketRune(self.upgradeOn.pickupBeingUpgraded, socketIndex)
      self:AllRuneInfoTable_RefreshSingle(equippedRuneID, false)
      local reselect_useOnGainFocus = true
      mainList:ReselectSelectedItem(reselect_useOnGainFocus)
      mainList:UpdateSelectedButton()
      if self:PickupBeingUpgradedIsEquipped() then
        self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_EQUIPPED_ATTRIBUTES", pickupConsts.TAG_PICKUP_KRATOS)
        self:SendEventToUIFsm("inWorldMenu", "EVT_CLEAR_ATTRIBUTES_PREVIEW")
      else
        self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_ATTRIBUTES_PREVIEW", pickupConsts.TAG_PICKUP_KRATOS)
      end
      self:UpdateSelectedRuneInfo(socketIndex, nil)
      Audio.PlaySound("SND_UX_UnEquip_Rune_Stone")
    end
  end
end
function PickupUpgrade:SubList_BackReleaseHandler(socketIndex)
  self:CancelRunePreview()
  self:CloseSubList(socketIndex)
  Audio.PlaySound("SND_UX_Menu_Tick_Back")
end
function PickupUpgrade:EquipRune(socketIndex)
  local currRuneList = self.menu:GetList(socketIndex)
  local currRuneInfo = currRuneList:GetSelectedItem()
  local currRuneID = runeUtil.GetRuneInfoRuneID(currRuneInfo)
  if self._officiallyEquippedRuneID ~= currRuneID and runeUtil.IsValidRuneID(currRuneID) then
    g_originalRuneOwnerPickup = nil
    g_originalRuneOwnerSocket = pickupConsts.INVALID_SOCKET_INDEX
    self._waitingForEquippedAttributes = true
    if self:PickupBeingUpgradedIsEquipped() then
      self._waitingForEquippedAttributes = true
      self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_EQUIPPED_ATTRIBUTES", pickupConsts.TAG_PICKUP_KRATOS)
      self:SendEventToUIFsm("inWorldMenu", "EVT_CLEAR_ATTRIBUTES_PREVIEW")
      self:StartTimer("UpgradePreviewClearDelay", consts.SingleFrameDelayTime, function()
        self:SendEventToUIFsm("inWorldMenu", "EVT_CLEAR_ATTRIBUTES_PREVIEW")
      end)
    else
      self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_ATTRIBUTES_PREVIEW", pickupConsts.TAG_PICKUP_KRATOS)
    end
    game.UnlockTrophy(20)
    self:AllRuneInfoTable_RefreshSingle(self._officiallyEquippedRuneID, false)
    self._officiallyEquippedRuneInfo = runeUtil.GetRuneInfoInSocketFromPickup(self.upgradeOn.pickupBeingUpgraded, socketIndex)
    self._officiallyEquippedRuneID = runeUtil.GetRuneInfoRuneID(self._officiallyEquippedRuneInfo)
    Audio.PlaySound("SND_UX_Equip_Enchantment")
    self.statsCard:PlayFlourishOnEquip()
    local runeSocketsList = self.menu:GetList("MainList")
    runeSocketsList:UpdateSelectedButton()
    local isOnEquip = true
    self.menu:EquippedItemSublist_UpdateEquippedItemHeader(currRuneList, self._officiallyEquippedRuneInfo, runeUtil.GetRuneInfoDisplayName, isOnEquip)
    self:AllRuneInfoTable_RefreshSingle(currRuneID, false)
    local useOnGainFocus = true
    currRuneList:ReselectSelectedItem(useOnGainFocus)
    if self:PickupBeingUpgradedIsEquipped() then
      local hide = false
      local clearButtons = false
      local allowLoseFocus = false
      currRuneList:Deactivate(hide, clearButtons, allowLoseFocus)
    end
  end
end
function PickupUpgrade:UnequipRune(socketIndex)
  local currRuneList = self.menu:GetList(socketIndex)
  local currRuneInfo = currRuneList:GetSelectedItem()
  local currRuneID = runeUtil.GetRuneInfoRuneID(currRuneInfo)
  if self._officiallyEquippedRuneID == currRuneID then
    self:CancelRunePreview()
    if self:PickupBeingUpgradedIsEquipped() then
      local runeAttributes = runeUtil.GetRuneAttributesFromInfo(currRuneInfo)
      local deltaTable = {}
      local resistanceIndex = tablex.Index(pickupConsts.Attributes, "Resistance")
      for i, _ in ipairs(runeAttributes) do
        deltaTable[i] = -runeAttributes[i].value
      end
      deltaTable[pickupConsts.PowerLevelIndex] = -runeUtil.GetRuneInfoImprovementAttributeValue(currRuneInfo, "PowerLevel")
      deltaTable[pickupConsts.MaxHealthIndex] = -util.Round(runeAttributes[resistanceIndex].value / 2)
      self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_EQUIPPED_ATTRIBUTES_WITH_DELTA_RUNESWAP", pickupConsts.TAG_PICKUP_KRATOS, deltaTable)
      self._waitingForEquippedAttributes = true
      self._onGainFocusWhenAttributesUpdated = true
    else
      self:SendEventToUIFsm("inWorldMenu", "EVT_UPDATE_ATTRIBUTES_PREVIEW", pickupConsts.TAG_PICKUP_KRATOS)
    end
    self._clearPickupIcon = true
    local runeSocketsList = self.menu:GetList("MainList")
    runeSocketsList:UpdateSelectedButton()
    self.menu:EquippedItemSublist_UpdateEquippedItemHeader(currRuneList, self._officiallyEquippedRuneInfo, runeUtil.GetRuneInfoDisplayName)
    self:AllRuneInfoTable_RefreshSingle(currRuneID, true)
    local useOnGainFocus = false
    currRuneList:ReselectSelectedItem(useOnGainFocus)
    if self:PickupBeingUpgradedIsEquipped() then
      local hide = false
      local clearButtons = false
      local allowLoseFocus = false
      currRuneList:Deactivate(hide, clearButtons, allowLoseFocus)
    end
    game.Audio.PlaySound("SND_UX_UnEquip_Enchantment")
  end
end
function PickupUpgrade:SubList_AdvanceReleaseHandler(socketIndex)
  local currRuneList = self.menu:GetList(socketIndex)
  local currRuneInfo = currRuneList:GetSelectedItem()
  local currRuneID = runeUtil.GetRuneInfoRuneID(currRuneInfo)
  if runeUtil.IsValidRuneID(currRuneID) then
    if currRuneID == self._officiallyEquippedRuneID then
      self:UnequipRune(socketIndex)
      Audio.PlaySound("SND_UX_UnEquip_Rune_Stone")
    else
      self:EquipRune(socketIndex)
    end
  end
end
function PickupUpgrade:EnableItemComparison(value)
  local newValue = self.comparisonToggled ~= value
  self.comparisonToggled = value
  if newValue then
    local mainList = self.menu:GetList("MainList")
    local runeSocketsList = self.menu:GetList(mainList:GetSelectedItem())
    local useOnGainFocus = true
    local ignoreRefreshAnim = true
    if not self.comparisonToggled then
      self.statsCard_Comparison:HideCard()
      self:SendEventToUIFsm("inWorldMenu", "EVT_LARGE_ATTRIBUTE_CARD")
    end
    runeSocketsList:ReselectSelectedItem(useOnGainFocus, ignoreRefreshAnim)
  end
end
function PickupUpgrade:SubList_R3ReleaseHandler(selectionID)
  if self._canCompare then
    self:EnableItemComparison(not self.comparisonToggled)
  end
end
function PickupUpgrade:EVT_EQUIPPED_ATTRIBUTES_UPDATED()
  local mainList = self.menu:GetList("MainList")
  local socketIndex = mainList:GetSelectedItem()
  local currRuneList = self.menu:GetList(socketIndex)
  if self._waitingForEquippedAttributes == true then
    currRuneList:Activate(false, false)
    if self._onGainFocusWhenAttributesUpdated then
      currRuneList:ReselectSelectedItem(true)
      self._onGainFocusWhenAttributesUpdated = false
    end
    self._waitingForEquippedAttributes = false
  end
end
function UpgradeMenu:OnSaveCheckpoint(tab)
end
function UpgradeMenu:OnRestoreCheckpoint(tab)
end
