local tablex = require("core.tablex")
local animationUtil = require("ui.animationUtil")
local attributeUtil = require("ui.attributeUtil")
local card = require("ui.card")
local cardComponent_Header = require("ui.cardComponent_Header")
local cardComponent_Video = require("ui.cardComponent_Video")
local characterUtil = require("ui.characterUtil")
local colors = require("ui.colors")
local consts = require("ui.consts")
local frame = require("ui.frame")
local frameGroup = require("ui.frameGroup")
local gemUtil = require("ui.gemUtil")
local lamsConsts = require("ui.lamsConsts")
local meterPreview = require("ui.meterPreview")
local pickupUtil = require("ui.pickupUtil")
local pickupConsts = require("ui.pickupConsts")
local recipeUtil = require("ui.recipeUtil")
local resourceConsts = require("ui.resourceConsts")
local resourceUtil = require("ui.resourceUtil")
local sliderHoldFill = require("ui.sliderHoldFill")
local skillTreeConsts = require("ui.skillTreeConsts")
local skillUtil = require("ui.skillUtil")
local util = require("ui.util")
local UI = game.UI
local GetTextHandle = util.GetTextHandle
local SetText = game.UI.SetText
local Pickup = game.Pickup
local MAX_GEM_ATTRIBUTES = 3
local MAX_PIPS = 3
local FRAMEINDEX = {
  attributes = 0,
  level1 = 1,
  level2 = 2,
  level3 = 3,
  buttonPromptFooter = 4
}
local GemInfoCard = {}
setmetatable(GemInfoCard, {
  __index = card.Card
})
function GemInfoCard.New(state, gameObject)
  assert(gameObject ~= nil, "GameObject reference entered into GemInfoCard constructor was nil.")
  assert(state ~= nil, "FSM State entered into GemInfoCard constructor was nil.")
  local newTable = {
    _gameObject = gameObject,
    _state = state,
    _activePurchasableRecipe = nil,
    _skillTreeType = nil,
    _refreshArgs = {},
    _attributeMeters = {},
    _children = {
      goBlurFrame = nil,
      goUnlockedText = nil,
      goMainRequirementsGroup = nil,
      goMainRequirements = {
        nil,
        nil,
        nil
      },
      goLevelSlots = {
        {
          nil,
          nil,
          nil,
          nil
        }
      },
      goCardButtonFooter = nil
    },
    _components = {},
    _properties = {},
    _textHandles = {
      Header = nil,
      Description = nil,
      attributeNames = {},
      Levels = {
        {
          Unlocked = nil,
          Description = nil,
          Requirement = {Numerator = nil, Name = nil}
        }
      }
    }
  }
  local mt = {__index = GemInfoCard}
  setmetatable(newTable, mt)
  return newTable
end
function GemInfoCard:GetGemLevelRequirementGOTable(goLevelSlot, index)
  local newTable = {
    goRefnode = nil,
    goRefnodeGroup = nil,
    goNumerator = nil
  }
  local textHandlesTable = {}
  newTable.goRefnode = goLevelSlot:FindSingleGOByName("Requirement" .. index)
  newTable.goRefnodeGroup = newTable.goRefnode:FindSingleGOByName("Requirement")
  newTable.goNumerator = newTable.goRefnodeGroup:FindSingleGOByName("Text_Numerator")
  textHandlesTable.Numerator = util.GetTextHandle(newTable.goNumerator)
  return newTable, textHandlesTable
end
function GemInfoCard:GetGemLevelSlotGOTable(cardObj, index)
  local newTable = {
    goRefnode = nil,
    goRefnodeGroup = nil,
    goPurchased = nil,
    goTextGroup = nil,
    goTextDescription = nil,
    goRequirementSlots = {}
  }
  local textHandlesTable = {}
  newTable.goRefnode = cardObj:FindSingleGOByName("SkillInfoCard_LevelSlot" .. index)
  newTable.goRefnodeGroup = newTable.goRefnode:FindSingleGOByName("levelSlot")
  newTable.goPurchased = newTable.goRefnodeGroup:FindSingleGOByName("Text_Unlocked")
  newTable.goTextGroup = newTable.goRefnodeGroup:FindSingleGOByName("TextObjects")
  newTable.goTextDescription = newTable.goRefnodeGroup:FindSingleGOByName("Text_Description")
  newTable.goTextNextLevel = newTable.goRefnodeGroup:FindSingleGOByName("Text_NextLvl")
  if 1 < index then
    newTable.pips = {}
    textHandlesTable.pips = {}
    for i = 1, MAX_PIPS do
      local goPip = newTable.goRefnodeGroup:FindSingleGOByName("Pip_" .. tostring(i))
      newTable.pips[i] = goPip
      textHandlesTable.pips[i] = util.GetTextHandle(goPip, "Text")
    end
  end
  textHandlesTable.Requirements = {}
  for i = 1, skillTreeConsts.MAX_GEM_REQUIREMENTS_COUNT do
    newTable.goRequirementSlots[i], textHandlesTable.Requirements[i] = self:GetGemLevelRequirementGOTable(newTable.goRefnode, i)
  end
  textHandlesTable.Unlocked = util.GetTextHandle(newTable.goPurchased)
  textHandlesTable.Description = util.GetTextHandle(newTable.goTextDescription)
  textHandlesTable.thCantPurchase = util.GetTextHandle(newTable.goTextGroup, "Text_CantPurchase")
  return newTable, textHandlesTable
end
function GemInfoCard:GetStatGOTables(index)
  local goStatRefnode = self._children.goLeftGroup:FindSingleGOByName("Stat" .. index)
  local returnGOTable = {
    goStatRefnode = goStatRefnode,
    goStatChild = goStatRefnode.Child,
    goUpgradeArrow = goStatRefnode:FindSingleGOByName("upgradeArrow"),
    goUpgradeStat = goStatRefnode:FindSingleGOByName("UpgradeStat")
  }
  local returnTextHandlesTable = {
    thAttributeName = util.GetTextHandle(returnGOTable.goStatChild, "AttributeName"),
    thAttributeValue = util.GetTextHandle(returnGOTable.goStatChild, "AttributeNumber"),
    thUpgradeNumber = util.GetTextHandle(returnGOTable.goStatChild, "UpgradeNumber")
  }
  return returnGOTable, returnTextHandlesTable
end
function GemInfoCard:Init(state, inVendor)
  self._inVendor = inVendor
  local gameObj = self._gameObject
  local childrenGameObjsTable = self._children
  childrenGameObjsTable.goLeftGroup = gameObj:FindSingleGOByName("LeftGroup")
  childrenGameObjsTable.goRightGroup = gameObj:FindSingleGOByName("RightGroup")
  childrenGameObjsTable.rootObj = gameObj:FindSingleGOByName("gemInfoRoot")
  childrenGameObjsTable.goHeaderL_refnode = gameObj:FindSingleGOByName("cardcomponent_header_left")
  childrenGameObjsTable.goHeaderL_root = childrenGameObjsTable.goHeaderL_refnode.Child
  childrenGameObjsTable.goHeaderL_backing = childrenGameObjsTable.goHeaderL_root:FindSingleGOByName("mapMenu_Header")
  childrenGameObjsTable.goAttributesGroup = gameObj:FindSingleGOByName("attributesGroup")
  childrenGameObjsTable.goGraphsBacking = gameObj:FindSingleGOByName("graphsBacking")
  childrenGameObjsTable.goUnlockedText = gameObj:FindSingleGOByName("LockedText")
  childrenGameObjsTable.goEquippedText = gameObj:FindSingleGOByName("Equipped_Text")
  childrenGameObjsTable.goFooterBlur = gameObj:FindSingleGOByName("ButtonPromptBlur")
  childrenGameObjsTable.goCardButtonFooter = gameObj:FindSingleGOByName("CardButtonFooter")
  childrenGameObjsTable.goCardButtonFooterRoot = gameObj:FindSingleGOByName("buttonPrompts_Root")
  childrenGameObjsTable.goFooterButtonText_Left = gameObj:FindSingleGOByName("ButtonPrompt_Left")
  childrenGameObjsTable.goFooterButtonText_Right = gameObj:FindSingleGOByName("ButtonPrompt_Right")
  childrenGameObjsTable.goCardFooter_HoldToCraft = gameObj:FindSingleGOByName("cardFooter_HoldToCraft")
  childrenGameObjsTable.goBackground_top = gameObj:FindSingleGOByName("background_top")
  childrenGameObjsTable.goBackground_bottom = gameObj:FindSingleGOByName("background_bottom")
  childrenGameObjsTable.gemInfoCard_Backing = gameObj:FindSingleGOByName("gemInfoCard_Backing")
  childrenGameObjsTable.gemInfoCard_BackingRoot = childrenGameObjsTable.gemInfoCard_Backing.Child
  childrenGameObjsTable.goLevelPurchaseFlourish_Left = gameObj:FindSingleGOByName("LevelPurchaseFlourish_Left")
  childrenGameObjsTable.goLevelPurchaseFlourish_Right = gameObj:FindSingleGOByName("LevelPurchaseFlourish_Right")
  local animRate = 0
  UI.Anim(self._children.goLevelPurchaseFlourish_Left, consts.AS_Forward, "", animRate, 0)
  UI.Anim(self._children.goLevelPurchaseFlourish_Right, consts.AS_Forward, "", animRate, 0)
  childrenGameObjsTable.goUpgradeHeader_Refnode = gameObj:FindSingleGOByName("cardcomponent_upgradeHeader")
  childrenGameObjsTable.goUpgradeHeader_Root = childrenGameObjsTable.goUpgradeHeader_Refnode.Child
  childrenGameObjsTable.goUpgradeHeader_Backing = childrenGameObjsTable.goUpgradeHeader_Root:FindSingleGOByName("mapMenu_Header")
  local thUpgradeHeader = util.GetTextHandle(childrenGameObjsTable.goUpgradeHeader_Root, "Text")
  UI.SetText(thUpgradeHeader, util.GetLAMSMsg(lamsConsts.UpgradeRunicAttack))
  local textHandles = self._textHandles
  textHandles.HeaderL = util.GetTextHandle(childrenGameObjsTable.goHeaderL_root, "Text")
  textHandles.ButtonFooter_Left = util.GetTextHandle(childrenGameObjsTable.goFooterButtonText_Left)
  UI.SetTextIsClickable(textHandles.ButtonFooter_Left)
  textHandles.ButtonFooter_Right = util.GetTextHandle(childrenGameObjsTable.goFooterButtonText_Right)
  textHandles.thCurrentLevel = util.GetTextHandle(childrenGameObjsTable.goLeftGroup, "skill_Level_Current_Lvl")
  for levelIndex = 1, skillTreeConsts.MAX_GEM_LEVEL_COUNT do
    self._children.goLevelSlots[levelIndex], textHandles.Levels[levelIndex] = self:GetGemLevelSlotGOTable(self._gameObject, levelIndex)
  end
  local MAX_GEM_STATS = 2
  self._children.stats = {}
  textHandles.Stats = {}
  for statIndex = 1, MAX_GEM_STATS do
    self._children.stats[statIndex], textHandles.Stats[statIndex] = self:GetStatGOTables(statIndex)
  end
  childrenGameObjsTable.goGraphsBacking:Show()
  for attributeIndex = 1, MAX_GEM_ATTRIBUTES do
    local attributeMeterGameObj = childrenGameObjsTable.goAttributesGroup:FindSingleGOByName("gemAttributeBar_" .. attributeIndex)
    local attributeMeterGameObjChild = attributeMeterGameObj:FindSingleGOByName("attribute_bar")
    local attributeMeter = meterPreview.MeterPreview.New(self._state, {
      Name = "gemAttributeBar_" .. attributeIndex,
      MeterObject = attributeMeterGameObj,
      MeterInstanceChildName = "attribute_bar",
      FillObjectName = "baseMeter",
      PreviewFillObjectName = "previewMeter",
      TextMaterial = "body_text",
      MaxValue = 1
    })
    attributeMeter:Activate(true)
    attributeMeter:Show()
    attributeMeter:SetPercent(0.5, 5)
    textHandles.attributeNames[attributeIndex] = util.GetTextHandle(attributeMeterGameObjChild, "name")
    self._attributeMeters[attributeIndex] = attributeMeter
    self._attributeMeters[attributeIndex].goUpgradeArrow = attributeMeterGameObj:FindSingleGOByName("upgradeArrow")
  end
  self.holdFill_Left = sliderHoldFill.SliderHoldFill.New(state, {
    Name = "GemInfoCard_HoldToCraftMeter",
    SliderObject = childrenGameObjsTable.goCardFooter_HoldToCraft,
    PressEvent = "EVT_Square_Press",
    ReleaseEvent = "EVT_Square_Release",
    HoldStartSound = "SND_UX_Vendor_Upgrade_Hold_Button_Start",
    HoldSound = "SND_UX_Weapon_Menu_Runic_Upgrade_Hold",
    SuccessSound = "SND_UX_Weapon_Menu_Runic_Upgrade_Success",
    StopSound = "SND_UX_Vendor_Upgrade_Hold_Reset_LP",
    StopWhenFull = true,
    IncAnimRate = 0.6,
    DecAnimRate = 0.5
  })
  self.holdFill_Left:SetOnComplete(function()
    self:OnHoldFillComplete_Left()
  end)
  self.holdFill_Right = sliderHoldFill.SliderHoldFill.New(state, {
    Name = "holdFill_Right",
    SliderObject = childrenGameObjsTable.goRadialFillRight,
    PressEvent = "EVT_Square_Press",
    ReleaseEvent = "EVT_Square_Release",
    HoldSound = "SND_UX_Weapon_Menu_Runic_Upgrade_Hold",
    SuccessSound = "SND_UX_Weapon_Menu_Runic_Upgrade_Success",
    HoldStartSound = "SND_UX_Vendor_Upgrade_Hold_Button_Start",
    StopSound = "SND_UX_Vendor_Upgrade_Hold_Reset_LP",
    StopWhenFull = true,
    IncAnimRate = 0.6,
    DecAnimRate = 0.5
  })
  self.holdFill_Right:Reset()
  self.holdFill_Right:Hide()
  self:ShowCard(true, true)
  self:HideCard()
  self._frameGroup = frameGroup.FrameGroup.New()
  self._frameGroup:SetPadding(0.25)
  self._frameGroup:SetBorderPadding(0.75)
  self._frameGroup:AddRoot(frame.Frame.New(childrenGameObjsTable.goAttributesGroup))
  self._frameGroup:AddNode(frame.Frame.New(childrenGameObjsTable.goLevelSlots[1].goRefnode), FRAMEINDEX.level1)
  self._frameGroup:AddNode(frame.Frame.New(childrenGameObjsTable.goLevelSlots[2].goRefnode), FRAMEINDEX.level2)
  self._frameGroup:AddNode(frame.Frame.New(childrenGameObjsTable.goLevelSlots[3].goRefnode), FRAMEINDEX.level3)
  self._frameGroup:AddNode(frame.Frame.New(childrenGameObjsTable.goCardButtonFooter), FRAMEINDEX.buttonPromptFooter)
  self._frameGroup:GetRoot():Init({height = 6.75})
  for levelIndex = 1, skillTreeConsts.MAX_GEM_LEVEL_COUNT do
    self._frameGroup:GetNode(FRAMEINDEX["level" .. levelIndex]):SetHeight(7)
  end
  self._frameGroup:GetNode(FRAMEINDEX.buttonPromptFooter):SetHeight(0)
  self:AddComponent(cardComponent_Header.CardComponent_Header.New(self._gameObject))
  self:AddComponent(cardComponent_Video.CardComponent_Video.New(self._gameObject, state))
  self:InitComponents()
end
function GemInfoCard:ClearCard()
  self:ClearLevels()
end
function GemInfoCard:ClearLevels()
  for levelIndex = 1, skillTreeConsts.MAX_GEM_LEVEL_COUNT do
    for requirementIndex = 1, skillTreeConsts.MAX_GEM_REQUIREMENTS_COUNT do
      self:ClearRequirementSlot(levelIndex, requirementIndex)
    end
  end
end
function GemInfoCard:ClearRequirementSlot(levelIndex, requirementIndex)
  local clearString = ""
end
function GemInfoCard:SetGem(gemName, upgradeAvailable)
  assert(gemName ~= nil and type(gemName) == "string", "Invalid skillName passed into GemInfoCard")
  if gemName ~= self._currentItemName then
    animationUtil.DoDefaultTransitionAnim(self._children.goLeftGroup)
    self._currentItemName = gemName
  end
  self:ClearCard()
  self._currentGemName = gemName
  local textHandles = self._textHandles
  self:SetHeader(gemName)
  self:SetDescription(gemName)
  self:SetAttributes(gemName)
  self:SetBacking(gemName)
  if Pickup.GetProfileStageCooldown_StageParameterCheckFeature then
    self:SetStats(gemName)
  end
  self:SetCurrentLevel(gemName)
  local nextAvailableLevelRecipe = self:SetLevels(gemName, textHandles.Levels, upgradeAvailable)
  local canPurchaseGemUpgrade = false
  if not self._inVendor then
    canPurchaseGemUpgrade = gemUtil.CanPurchaseUpgrade(nextAvailableLevelRecipe) and upgradeAvailable
    self:SetCanPurchase(canPurchaseGemUpgrade)
  end
  if nextAvailableLevelRecipe == nil then
    self._children.goCardButtonFooter:Hide()
    game.UnlockTrophy(26)
  else
    self._children.goCardButtonFooter:Show()
  end
  if canPurchaseGemUpgrade then
    self._activePurchasableRecipe = nextAvailableLevelRecipe
  else
    self._activePurchasableRecipe = nil
  end
  if characterUtil.ItemIsEquipped(gemName) then
    self._children.goEquippedText:Show()
  else
    self._children.goEquippedText:Hide()
  end
  self:SetProperty("VideoNameToPlay", gemName)
  self:UpdateComponents()
  self._refreshArgs = {gemName, upgradeAvailable}
  return canPurchaseGemUpgrade
end
function GemInfoCard:SetBacking(gemName)
  local gameObj = self._children.goLeftGroup
  local jid_Axe = gameObj:GetJointIndex("SlotBacking_Axe")
  local jid_Blades = gameObj:GetJointIndex("SlotBacking_Blades")
  local jid_Bow = gameObj:GetJointIndex("SlotBacking_SonBow")
  gameObj:HideJoint(jid_Axe)
  gameObj:HideJoint(jid_Blades)
  gameObj:HideJoint(jid_Bow)
  if gemUtil.IsAxeWeaponSpecial(gemName) then
    gameObj:ShowJoint(jid_Axe)
  elseif gemUtil.IsBladesWeaponSpecial(gemName) then
    gameObj:ShowJoint(jid_Blades)
  else
    gameObj:ShowJoint(jid_Bow)
  end
end
function GemInfoCard:RefreshCard()
  self:SetGem(table.unpack(self._refreshArgs))
end
function GemInfoCard:SetHeader(gemName)
  local displayName = pickupUtil.GetDisplayName(gemName)
  self:SetProperty("Header", displayName)
  UI.SetText(self._textHandles.HeaderL, displayName)
end
function GemInfoCard:SetDescription(gemName)
  local textHandle = self._textHandles.Description
  local levelIndex = 1
  UI.SetText(self._textHandles.Levels[levelIndex].Description, pickupUtil.GetDescription(gemName))
  self._children.goLevelSlots[levelIndex].goPurchased:Show()
  local thControllerHelp = GetTextHandle(self._children.goLevelSlots[levelIndex].goPurchased)
  SetText(thControllerHelp, gemUtil.GetControllerHelpText(gemName))
  for i = 1, skillTreeConsts.MAX_GEM_REQUIREMENTS_COUNT do
    self._children.goLevelSlots[levelIndex].goRequirementSlots[i].goRefnode:Hide()
  end
end
local g_attributeMeterAnimRate = 25
function GemInfoCard:SetAttributes(gemName)
  local stageNum = self._inVendor and 0 or Pickup.GetProfileStage(gemName)
  local maxStage = pickupUtil.GetMaxStage(gemName)
  local attributesTable = Pickup.GetGemAttributes(gemName, stageNum)
  local previewAttributesTables
  if stageNum ~= maxStage then
    previewAttributesTables = Pickup.GetGemAttributes(gemName, stageNum + 1)
  end
  assert(#attributesTable <= MAX_GEM_ATTRIBUTES, "More attributes defined for weapon special than is currently supported in the gem card.")
  local attributeNames = self._textHandles.attributeNames
  for attributeIndex, attributeTable in ipairs(attributesTable) do
    local strHash = attributeTable.NameHash
    local lamsId = skillTreeConsts.GemAttributes[tostring(strHash)]
    assert(lamsId ~= nil, "Stat name not found. Check that the name matches what is defined in \\ui\\scripts\\consts\\skillTreeConsts.lua")
    local outputString = util.GetLAMSMsg(lamsId)
    UI.SetText(attributeNames[attributeIndex], outputString)
    self._attributeMeters[attributeIndex]:SetPercent(attributeTable.Value, g_attributeMeterAnimRate)
    if previewAttributesTables ~= nil then
      local previewAttributesTable = previewAttributesTables[attributeIndex]
      self._attributeMeters[attributeIndex]:AnimatePreviewBar(previewAttributesTable.Value, g_attributeMeterAnimRate)
      self._attributeMeters[attributeIndex].goUpgradeArrow:Hide()
    else
      self._attributeMeters[attributeIndex]:AnimatePreviewBar(0, g_attributeMeterAnimRate)
      self._attributeMeters[attributeIndex].goUpgradeArrow:Hide()
    end
  end
  if #attributesTable == 0 then
    UI.SetText(attributeNames[1], "Error: ")
    UI.SetText(attributeNames[2], tostring(gemName))
    UI.SetText(attributeNames[3], "Attributes not Defined.")
    UI.SetText(attributeNames[4], "")
    UI.SetText(attributeNames[5], ":(")
    for i = 1, MAX_GEM_ATTRIBUTES do
      self._attributeMeters[i]:SetPercent(0, 5)
    end
  end
end
function GemInfoCard:SetStats(gemName)
  local includeLevel = false
  local statTable = gemUtil.GetStatsTable(gemName, includeLevel)
  for statIndex, stat in ipairs(statTable) do
    local textHandles = self._textHandles.Stats[statIndex]
    local nameString = gemUtil.GetStatDisplayName(stat.Name)
    local value, baseValue = stat.GetValue(gemName)
    local valueString = tostring(value)
    if baseValue ~= nil then
      if stat.Name == "Cooldown" then
        valueString = util.StyleText(tostring(value), "NewBaseHeader2") .. " " .. util.GetLAMSMsg(lamsConsts.Seconds)
      else
        valueString = tostring(value)
      end
    end
    UI.SetText(textHandles.thAttributeName, nameString)
    UI.SetText(textHandles.thAttributeValue, valueString)
    self._children.stats[statIndex].goUpgradeStat:Hide()
    self._children.stats[statIndex].goUpgradeArrow:Hide()
    UI.SetText(textHandles.thUpgradeNumber, "")
  end
end
function GemInfoCard:SetCurrentLevel(gemName)
  local thCurrentTextLevel = util.GetTextHandle(self._children.goLeftGroup, "skill_Level_Current")
  local stageNum = self._inVendor and 0 or Pickup.GetProfileStage(gemName)
  UI.SetText(thCurrentTextLevel, tostring(stageNum + 1))
end
function GemInfoCard:SetLocked(skillName, skillIsLocked, skillIsPurchased)
  if skillIsLocked then
    self._children.goUnlockedText:Show()
    self._children.goMainRequirementsGroup:Hide()
  else
    self._children.goUnlockedText:Hide()
    local scalarColorValue = 1
    local color = {
      scalarColorValue,
      scalarColorValue,
      scalarColorValue
    }
    if not skillIsPurchased then
      self._children.goMainRequirementsGroup:Show()
    end
  end
end
function GemInfoCard:SetLevels(gemName, textHandleLevelGroups, upgradeAvailable)
  local availableLevelsOnGem = gemUtil.GetMaxLevel(gemName)
  local currentGemLevel = self._inVendor and 1 or gemUtil.GetCurrentLevel(gemName)
  local levelRecipesTable = gemUtil.GetAllLevelRecipes(gemName)
  local initialize = true
  self:AnimateBackingFlourish(currentGemLevel - 1, initialize)
  if 0 < availableLevelsOnGem and #levelRecipesTable == 0 then
    availableLevelsOnGem = 0
    self:SetErrorMessage("No recipes found in kratos' wallet for: " .. gemName .. ". Please check the output console for more information on specific recipe names.")
  end
  local nextAvailableLevelRecipe
  local iNextAvailableRecipe = -1
  for levelIndex = 2, skillTreeConsts.MAX_GEM_LEVEL_COUNT do
    if levelIndex <= availableLevelsOnGem then
      self._frameGroup:GetNode(FRAMEINDEX["level" .. levelIndex]):SetActive(true)
      self._children.goLevelSlots[levelIndex].goRefnodeGroup:Show()
      local levelLocked = levelIndex > currentGemLevel
      local isNextAvailableRecipe = levelLocked and levelIndex == currentGemLevel + 1
      if nextAvailableLevelRecipe == nil and levelLocked then
        local levelRecipesTableIndex = levelIndex - 1
        nextAvailableLevelRecipe = levelRecipesTable[levelRecipesTableIndex]
        iNextAvailableRecipe = levelIndex - 1
      end
      local levelRecipesTableIndex = levelIndex - 1
      self:SetSingleLevel(gemName, levelIndex, levelRecipesTable[levelRecipesTableIndex], levelLocked, isNextAvailableRecipe, upgradeAvailable, textHandleLevelGroups[levelIndex])
    else
      self._frameGroup:GetNode(FRAMEINDEX["level" .. levelIndex]):SetActive(false)
      self._children.goLevelSlots[levelIndex].goRefnodeGroup:Hide()
    end
  end
  if 0 < iNextAvailableRecipe then
    local goObjToMove = self._children.goCardButtonFooter
    local goObjToMoveTo = self._children.goRightGroup
    local nameOfJointToMoveTo = "FillFlourishJoint_Lvl" .. tostring(iNextAvailableRecipe)
    animationUtil.SetTransform(goObjToMove, goObjToMoveTo, nameOfJointToMoveTo)
  end
  return nextAvailableLevelRecipe
end
function GemInfoCard:SetErrorMessage(message)
end
function GemInfoCard:SetRequirementSlotsVisible(levelIndex, value)
  if value then
    for requirementSlotIndex = 1, skillTreeConsts.MAX_GEM_REQUIREMENTS_COUNT do
      self._children.goLevelSlots[levelIndex].goRequirementSlots[requirementSlotIndex].goRefnode:Show()
    end
  else
    for requirementSlotIndex = 1, skillTreeConsts.MAX_GEM_REQUIREMENTS_COUNT do
      self._children.goLevelSlots[levelIndex].goRequirementSlots[requirementSlotIndex].goRefnode:Hide()
    end
  end
end
function GemInfoCard:SetSingleLevel(gemName, levelIndex, recipeName, levelLocked, isNextAvailableRecipe, upgradeAvailable, textHandleGroup)
  UI.SetText(textHandleGroup.Description, recipeUtil.GetDescription(recipeName))
  self._children.goLevelSlots[levelIndex].goPurchased:Hide()
  local inputItems = recipeUtil.GetInputRecipeItems(recipeName)
  local outputItems = recipeUtil.GetOutputRecipeItems(recipeName)
  if isNextAvailableRecipe then
    self:SetLevelAsPurchasable(levelIndex, inputItems)
  else
    self:SetLevelLocked(levelIndex, levelLocked, inputItems)
  end
  self:SetPipDiffs(gemName, recipeName, levelIndex)
  UI.SetText(self._textHandles.Levels[levelIndex].thCantPurchase, "")
  local goPurchaseUnavailableBacking = self._children.goLevelSlots[levelIndex].goRefnode:FindSingleGOByName("gem_unavailableBacking")
  if levelLocked then
    self:SetRequirementSlotsVisible(levelIndex, true)
    self:SetLevelRequirements(gemName, inputItems, outputItems, levelIndex, levelLocked, isNextAvailableRecipe, upgradeAvailable, goPurchaseUnavailableBacking)
  else
    local thCantPurchase = self._textHandles.Levels[levelIndex].thCantPurchase
    UI.SetTextStyle(thCantPurchase, "NewBaseHeader4")
    UI.SetText(thCantPurchase, util.GetLAMSMsg(lamsConsts.Upgraded))
    goPurchaseUnavailableBacking:Hide()
    self:SetRequirementSlotsVisible(levelIndex, false)
  end
end
function GemInfoCard:SetPipDiffs(gemName, recipeName, levelIndex)
  local currentPickupStage = self._inVendor and 0 or Pickup.GetProfileStage(gemName)
  local stageNum = levelIndex - 1
  local iPip = 1
  local pips = self._children.goLevelSlots[levelIndex].pips
  local levelIsPurchased = currentPickupStage >= stageNum
  if not levelIsPurchased then
    local attributesTable = Pickup.GetGemAttributes(gemName, stageNum)
    local prevAttributesTable = Pickup.GetGemAttributes(gemName, stageNum - 1)
    local diffTable = {}
    for i, _ in ipairs(attributesTable) do
      diffTable[i] = {}
      diffTable[i].NameHash = attributesTable[i].NameHash
      diffTable[i].Value = util.Round((attributesTable[i].Value - prevAttributesTable[i].Value) * 10 * 0.5)
    end
    for i = 1, #diffTable do
      local attr = diffTable[i]
      local goPip = pips[iPip]
      local thPip = self._textHandles.Levels[levelIndex].pips[iPip]
      if attr.Value ~= 0 then
        goPip:Show()
        local printString = "+" .. tostring(attr.Value) .. " " .. util.GetLAMSMsg(skillTreeConsts.GemAttributes[tostring(attr.NameHash)])
        UI.SetText(thPip, printString)
        iPip = iPip + 1
      end
    end
  end
  for i = iPip, MAX_PIPS do
    local goPip = pips[i]
    goPip:Hide()
  end
end
function GemInfoCard:SetLevelAsPurchasable(levelIndex, inputItems)
  local alpha = 100
  local levelSlot = self._children.goLevelSlots[levelIndex]
  util.SetGameObjectAlpha(levelSlot.goTextDescription, alpha, "small_text", "LayerX", "cst_AlphaBlendAmount")
  util.SetGameObjectAlpha(levelSlot.goTextGroup, alpha, "xlarge_text", "LayerX", "cst_AlphaBlendAmount")
  util.SetGameObjectAlpha(levelSlot.goTextGroup, alpha, "large_text", "LayerX", "cst_AlphaBlendAmount")
  local pips = self._children.goLevelSlots[levelIndex].pips
  local fadeAlpha = 1
  for _, goPip in ipairs(pips) do
    util.SetGameObjectAlpha(goPip, alpha, "small_text", "LayerX", "cst_AlphaBlendAmount")
    util.SetGameObjectAlpha(goPip, alpha, "gemPip_Fill_Preview", "Layer0", "cst_AlphaBlendAmount")
  end
  levelSlot.goTextNextLevel:Show()
  for _, currentInputItem in ipairs(inputItems) do
    if currentInputItem.Name == "EconomyXP" then
      local displayIndex = 1
      local currentRequirementSlot = self._children.goLevelSlots[levelIndex].goRequirementSlots[displayIndex]
    end
  end
end
function GemInfoCard:SetLevelLocked(levelIndex, levelLocked, inputItems)
  local alpha
  if levelLocked and not self._inVendor then
    alpha = 30
  else
    alpha = 100
  end
  local pips = self._children.goLevelSlots[levelIndex].pips
  for _, goPip in ipairs(pips) do
    util.SetGameObjectAlpha(goPip, alpha, "small_text", "LayerX", "cst_AlphaBlendAmount")
    util.SetGameObjectAlpha(goPip, alpha, "gemPip_Fill_Preview", "Layer0", "cst_AlphaBlendAmount")
  end
  local currentLevelSlot = self._children.goLevelSlots[levelIndex]
  util.SetGameObjectAlpha(currentLevelSlot.goTextDescription, alpha, "small_text", "LayerX", "cst_AlphaBlendAmount")
  util.SetGameObjectAlpha(currentLevelSlot.goTextGroup, alpha, "xlarge_text", "LayerX", "cst_AlphaBlendAmount")
  util.SetGameObjectAlpha(currentLevelSlot.goTextGroup, alpha, "large_text", "LayerX", "cst_AlphaBlendAmount")
  currentLevelSlot.goTextNextLevel:Hide()
  for _, currentInput in ipairs(inputItems) do
    if currentInput.Name == "EconomyXP" then
      local displayIndex = 1
      local currentRequirementSlot = currentLevelSlot.goRequirementSlots[displayIndex]
    end
  end
end
function GemInfoCard:SetLevelRequirements(skillName, inputItems, outputItems, levelIndex, levelLocked, isNextAvailableRecipe, upgradeAvailable, goPurchaseUnavailableBacking)
  for requirementIndex, item in ipairs(inputItems) do
    if item.Name == "EconomyXP" then
      local currResourceAmount = resourceUtil.GetAmount(item.Name)
      local requiredAmount = item.Amount
      local currentRequirementSlot = self._children.goLevelSlots[levelIndex].goRequirementSlots[requirementIndex]
      currentRequirementSlot.goRefnode:Show()
      currentRequirementSlot.goNumerator:Show()
      local haveEnoughOfResource = currResourceAmount >= requiredAmount
      local alpha
      if (not (not isNextAvailableRecipe and levelLocked) or self._inVendor) and (upgradeAvailable or not haveEnoughOfResource) then
        alpha = 100
      else
        alpha = 30
      end
      local currentAmountTextStyle
      if not haveEnoughOfResource then
        currentAmountTextStyle = "Color_Red"
      end
      if isNextAvailableRecipe then
        if haveEnoughOfResource then
          goPurchaseUnavailableBacking:Hide()
        else
          goPurchaseUnavailableBacking:Show()
        end
      else
        goPurchaseUnavailableBacking:Hide()
      end
      local gameObj
      self:SetRequirementRowAlpha(levelIndex, requirementIndex, alpha)
      requirementIndex = 1
      self:SetAcquiredAndRequiredIngredients(levelIndex, requirementIndex, currResourceAmount, requiredAmount, currentAmountTextStyle)
      local skillLockedReasonString = ""
      local thCantPurchase = self._textHandles.Levels[levelIndex].thCantPurchase
      UI.SetTextStyle(thCantPurchase, "NewBaseHeader4_Left")
      if not haveEnoughOfResource then
        skillLockedReasonString = util.GetLAMSMsg(lamsConsts.skillLocked_notEnough)
      end
      if not isNextAvailableRecipe then
        UI.SetTextStyle(thCantPurchase, "NewBaseHeader4")
        skillLockedReasonString = util.GetLAMSMsg(lamsConsts.CantPurchase_PreviousLevelRequired)
        if self._inVendor then
          skillLockedReasonString = ""
        end
        currentRequirementSlot.goRefnode:Hide()
        currentRequirementSlot.goNumerator:Hide()
      end
      UI.SetText(self._textHandles.Levels[levelIndex].thCantPurchase, skillLockedReasonString)
    end
  end
  for requirementIndex = #inputItems + 1, skillTreeConsts.MAX_GEM_REQUIREMENTS_COUNT do
    if levelIndex == 0 then
      self._children.goMainRequirements[requirementIndex].goRefnode:Hide()
    else
      self._children.goLevelSlots[levelIndex].goRequirementSlots[requirementIndex].goRefnode:Hide()
    end
  end
end
function GemInfoCard:SetRequirementRowAlpha(levelIndex, requirementIndex, alpha)
  local objsToSet = {numerator = nil}
  local slotTableReference
  if levelIndex == 0 then
    slotTableReference = self._children.goMainRequirements[requirementIndex]
  else
    slotTableReference = self._children.goLevelSlots[levelIndex].goRequirementSlots[requirementIndex]
  end
  objsToSet.numerator = slotTableReference.goNumerator
  for _, obj in pairs(objsToSet) do
    util.SetGameObjectAlpha(obj, alpha, "large_text", "LayerX", "cst_AlphaBlendAmount")
  end
end
function GemInfoCard:SetAcquiredAndRequiredIngredients(levelIndex, requirementIndex, numeratorValue, denominatorValue, currentAmountTextStyle)
  assert(levelIndex ~= nil and requirementIndex ~= nil and numeratorValue ~= nil, "Nil values passed into GemInfoCard:SetAcquiredAndRequiredIngredients")
  local thNumerator = self._textHandles.Levels[levelIndex].Requirements[requirementIndex].Numerator
  local numeratorString = tostring(numeratorValue)
  local iconString = "[EconomyXP]"
  if currentAmountTextStyle ~= nil then
    numeratorString = util.StyleText(numeratorString, currentAmountTextStyle)
  end
  if denominatorValue == nil then
    UI.SetText(thNumerator, numeratorString)
  else
    UI.SetText(thNumerator, iconString .. " " .. numeratorString .. " / " .. tostring(denominatorValue))
  end
  if self._inVendor then
    UI.SetText(thNumerator, "")
  end
end
function GemInfoCard:SetOnHoldFillComplete_Left_Callback(callback)
  self.onHoldFillComplete_Left_Callback = callback
end
function GemInfoCard:AnimateBackingFlourish(gemLevel, initialize)
  assert(0 <= gemLevel and gemLevel < skillTreeConsts.MAX_GEM_LEVEL_COUNT, "Gem level was out of range for GemInfoCard:AnimateBackingFlourish. Value was " .. tostring(gemLevel))
  local framesPerSecond = 30
  local targetFrame = gemLevel * framesPerSecond
  local startFrame = (gemLevel - 1) * framesPerSecond
  if startFrame < 0 then
    startFrame = 0
  end
  startFrame = startFrame / framesPerSecond
  targetFrame = targetFrame / framesPerSecond
  local animRate = initialize and 0 or 1
  local goBacking = util.GetUiObjByName("gemInfoCard_Backing").Child
  if initialize then
    UI.Anim(goBacking, consts.AS_Forward, "gemInfoCard_Backing_Fill", 0, targetFrame)
  else
    UI.Anim(goBacking, consts.AS_Forward, "gemInfoCard_Backing_Fill", 0, startFrame)
    UI.Anim(goBacking, consts.AS_Forward, "gemInfoCard_Backing_Fill", animRate, startFrame, targetFrame)
  end
end
function GemInfoCard:OnHoldFillComplete_Left()
  self.holdFill_Left:Reset()
  gemUtil.PurchaseUpgrade(self._currentGemName, self._activePurchasableRecipe)
  self:RefreshCard()
  local initialize = false
  self:AnimateBackingFlourish(gemUtil.GetCurrentLevel(self._currentGemName) - 1, initialize)
  local callback = self.onHoldFillComplete_Left_Callback
  if callback ~= nil then
    callback()
  end
  local animRate = 1
  local startFrame = 0
  local targetFrame = 1
  UI.Anim(self._children.goLevelPurchaseFlourish_Left, consts.AS_Forward, "", animRate, startFrame, targetFrame)
  UI.Anim(self._children.goLevelPurchaseFlourish_Right, consts.AS_Forward, "", animRate, startFrame, targetFrame)
  self._state:SendEventToUIFsm("inWorldMenu", "EVT_REFRESH_NOTIFICATIONS")
end
function GemInfoCard:SetCanPurchase(canPurchaseNextLevel)
  self.holdFill_Left:Reset()
  if canPurchaseNextLevel then
    self:SetLeftButtonState("[SquareButton]" .. " " .. util.GetLAMSMsg(lamsConsts.VendorUpgrade))
    self.holdFill_Left:Activate(true)
  else
    self:SetLeftButtonState("")
    self.holdFill_Left:Deactivate(true)
  end
end
function GemInfoCard:DeactivateHoldFills()
  self.holdFill_Left:Deactivate(true)
end
function GemInfoCard:SetButtonStates(leftButtonMsg, rightButtonMsg)
  self:SetLeftButtonState("Left Butt")
  self:SetRightButtonState("Right Butt")
end
function GemInfoCard:SetLeftButtonState(msg)
  UI.SetText(self._textHandles.ButtonFooter_Left, tostring(msg))
end
function GemInfoCard:SetRightButtonState(msg)
  UI.SetText(self._textHandles.ButtonFooter_Right, tostring(msg))
end
function GemInfoCard:ShowCard(showAll, rightGroupVisible)
  self._gameObject:Show()
  if showAll then
    for _, obj in pairs(self._children) do
      if type(obj) == "table" then
        self:ShowCard_Recursive(obj)
      else
        obj:Show()
      end
    end
  end
  if rightGroupVisible then
    self._children.goRightGroup:Show()
  else
    self._children.goRightGroup:Hide()
  end
  animationUtil.DoDefaultTransitionAnim(self._children.goLeftGroup)
  local animRate = 0.05
  UI.Anim(self._children.gemInfoCard_BackingRoot, consts.AS_ForwardCycle, "gemInfoCard_Backing_Loop", animRate, 1)
end
function GemInfoCard:HideCard()
  for attributeIndex = 1, MAX_GEM_ATTRIBUTES do
    self._attributeMeters[attributeIndex]:AnimatePreviewBar(0, g_attributeMeterAnimRate)
  end
  self:SetCanPurchase(false)
  self._gameObject:Hide()
  animationUtil.ClearVideo()
  self.holdFill_Left:OnSliderParentHide()
  self.holdFill_Right:OnSliderParentHide()
end
return {GemInfoCard = GemInfoCard}
