-- Copyright © 2023 @Groick (Twitch). All rights reserved.
local function L(key, ...) return EasyOptions:Localize(key, ...) end
function EasyOptions:CreateTabControl(parent, customControlName, text, tooltipTitleText, tooltipText, tabInfos, tabsOnBottom, positionInfo, customSize, allowFillWidthByDefault, fontObjectName, customFontInfo, customTextColor)
  local typeName = "TabControl"
  local baseTypeName = "TabControl"
  local defaultSize = EasyOptions:GetDefaultTabControlSize()
  local showBackgroundAndBorder = true
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateGroupBoxBase(typeName, baseTypeName, parent, customControlName, text, tooltipTitleText, tooltipText, positionInfo, customSize, defaultSize, showBackgroundAndBorder, allowFillWidthByDefault, fontObjectName, customFontInfo, customTextColor)

  control.GetValue = function(self)
    return self:GetTabButtonIDOfSelectedTabButton()
  end
  control.SetValue = function(self, value)
    self:SelectTabButton(value)
  end
  control.GetNumberOfTabButtons = function(self)
    return EasyOptions:GetLength(self.TabButtons)
  end
  control.GetTabButton = function(self, tabButtonID)
    local control = self
    if (control.TabButtons == nil) or (tabButtonID == nil) then
      return nil
    end
    return control.TabButtons[tabButtonID]
  end
  control.GetFirstTabButton = function(self)
    local control = self
    local length = control:GetNumberOfTabButtons()
    if (length == 0) then
      return nil
    end
    return control.TabButtons[1]
  end
  control.GetLastTabButton = function(self)
    local control = self
    local length = control:GetNumberOfTabButtons()
    if (length == 0) then
      return nil
    end
    return control.TabButtons[length]
  end
  control.GetNextAvailableTabButtonID = function(self)
    local control = self
    return control:GetNumberOfTabButtons() + 1
  end
  control.HasSelectedTabButton = function(self)
    local control = self
    return (control.SelectedTabButton ~= nil)
  end
  control.IsValidTabButtonID = function(self, tabButtonID)
    if (tabButtonID == nil) then
      return false
    end
    return (tabButtonID >= 1) and (tabButtonID <= control:GetNumberOfTabButtons())
  end
  control.GetTabButtonIDOfSelectedTabButton = function(self)
    return EasyOptions:GetTabControlValue(self)
  end
  control.SelectTabButton = function(self, tabButtonID)
    EasyOptions:SetTabControlValue(self, tabButtonID)
  end
  
  control.TabButtons = {}
  control.TabButtonFrames = {}
  control.TabsOnBottom = tabsOnBottom
  control.AllowResizeToFitTabButtons = (customSize == nil)
  control.TabButtonsRegionWidth = 0
  control.TabButtonsRegionHeight = 0

  local tabButtonID
  local tabInfo
  local tabText, tabCustomWidth
  local tabTooltipTitleText = nil
  local tabTooltipText = nil
  local onClickHandler = nil
  local control_TabButton, controlRegionWidth_TabButton, controlRegionHeight_TabButton, shouldFillWidth_TabButton
  local length = EasyOptions:GetLength(tabInfos)
  for i = 1, length do
    tabButtonID = control:GetNextAvailableTabButtonID()
    tabInfo = tabInfos[i]
    tabText, tabCustomWidth = EasyOptions:GetValuesFromTabInfo(tabInfo)
    control_TabButton, controlRegionWidth_TabButton, controlRegionHeight_TabButton, shouldFillWidth_TabButton = EasyOptions:CreateTabButton(control, control, tabButtonID, tabText, tabTooltipTitleText, tabTooltipText, tabCustomWidth, onClickHandler)
  end
  -- control.ControlRegionWidth = control.ControlRegionWidth + 0
  -- control.ControlRegionHeight = control.ControlRegionHeight + 0
  EasyOptions:UpdateTabControlAfterAddTabButtons(control)
  controlRegionWidth = control.ControlRegionWidth -- This parameter must be updated after EasyOptions:UpdateTabControlAfterAddTabButtons is called.
  controlRegionHeight = control.ControlRegionHeight -- This parameter must be updated after EasyOptions:UpdateTabControlAfterAddTabButtons is called.

  -- Override the OnEnabledChangedHandler method.
  local onEnabledChangedHandlerBase = control.OnEnabledChangedHandler
  control.OnEnabledChangedHandler = function(self)
    local control = self
    -- Reserved.
    if (onEnabledChangedHandlerBase ~= nil) then
      onEnabledChangedHandlerBase(self)
    end
  end

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateTabButton(parent, tabControl, tabButtonID, text, tooltipTitleText, tooltipText, customSize, onClickHandler)
  local tabsOnBottom
  if (tabControl == nil) then
    tabsOnBottom = false
  else
    tabsOnBottom = tabControl.TabsOnBottom
  end

  local customControlName
  local controlTypeName = "TabButton"
  if (tabControl == nil) or (tabControl.Name == nil) or (tabButtonID == nil) then
    customControlName = nil
  else
    customControlName = tabControl.Name.."."..controlTypeName..tostring(tabButtonID)
  end
  local controlName = EasyOptions:GetControlName(controlTypeName, customControlName)
  
  local labelAnchorControl = tabControl
  local customControlName = controlName
  local fontObjectName = EasyOptions.Fields.DefaultLabelFontObjectName
  local positionInfo_Initial = {"TOPLEFT", "TOPLEFT", 0, 0} -- The TabButton will be moved later in this method (see below).
  local customSize_Initial = nil
  local wordWrap = false -- Do not allow text to wrap.
  local customFontInfo = nil
  local customTextColor = nil
  local includeUnderline = false
  local customUnderlineWidth = nil
  local frameTemplate = "BackdropTemplateMixin" and "BackdropTemplate"
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateLabel(parent, labelAnchorControl, controlTypeName, customControlName, text, tooltipTitleText, tooltipText, fontObjectName, positionInfo_Initial, customSize_Initial, wordWrap, customFontInfo, customTextColor, includeUnderline, customUnderlineWidth, frameTemplate)
  control.BaseType = controlTypeName
  
  local labelMarginX = 9 -- This mimics the margin that is used by the WoW API.
  local labelOffsetX = 0 -- EasyOptions:GetLabelOffsetX()
  local labelOffsetY = EasyOptions:IIF(tabsOnBottom, 1, -1) -- EasyOptions:GetLabelOffsetY()
  control.Label:ClearAllPoints()
  control.Label:SetPoint("CENTER", control, "CENTER", labelOffsetX, labelOffsetY) -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  control.Label:SetPoint("LEFT", control, "LEFT", labelMarginX, labelOffsetY)
  control.Label:SetPoint("RIGHT", control, "RIGHT", -labelMarginX, labelOffsetY)
  control.Label:SetJustifyH("CENTER") -- "LEFT", "RIGHT", "CENTER"
  control.Label:SetJustifyV("MIDDLE") -- "TOP", "BOTTOM", "MIDDLE"
  
  control.Select = function(self)
    local control = self
    if (control.TabControl == nil) then
      return
    end
    control.TabControl:SelectTabButton(control.TabButtonID)
  end
  
  local tabButtonFrame = EasyOptions:CreateTabButtonFrame(tabControl, tabButtonID)

  control.TabControl = tabControl
  control.TabButtonID = tabButtonID
  control.TabButtonFrame = tabButtonFrame
  control.TabsOnBottom = tabsOnBottom
  control.IsSelected = false
  control.IsHighlighted = false
  tabButtonFrame.TabButton = control

  local stringWidth = EasyOptions:GetLabelStringWidth(control.Label, true)
  local defaultWidth = math.max(math.ceil(stringWidth + 2 * labelMarginX), 72) -- math.ceiling -- This is similar to the default width of TabButtons in the WoW API which is given by the following: math.max(EasyOptions:Round(0.989 * stringWidth + 18, 0.5), 72)
  -- local defaultWidth = math.max(EasyOptions:Round(0.989 * stringWidth + 18, 0.5), 72) -- This mimics the default width of a TabButton that is used by the WoW API.
  local defaultHeight = EasyOptions:GetTabButtonHeightMax() -- Use the maximum height for layout purposes.
  local widthMaxAllowed = EasyOptions.Fields.ControlSizeMaxAllowed_Large
  local ignoreCustomHeight = true -- Setting a custom height is not supported because the height of the TabButton can change when it is selected.
  local width, height, hasWidth, hasHeight, shouldFillWidth = EasyOptions:GetSizeFromCustomSize(customSize, ignoreCustomHeight, defaultWidth, defaultHeight, widthMaxAllowed, EasyOptions.Fields.ControlSizeMaxAllowed_Large, true, false)
  control:SetSize(width, EasyOptions:GetDefaultTabButtonHeight())
  
  local marginX = EasyOptions:GetDefaultTabButtonMarginX()
  local offsetX_Initial = marginX
  local offsetY_Initial = 2
  local offsetX_Adjacent = EasyOptions:GetDefaultTabButtonPaddingX()
  local offsetY_Adjacent = 0
  local tabButtonPrevious = tabControl:GetLastTabButton()
  local positionReferenceControl
  local positionInfo
  if (tabsOnBottom) then
    if (tabButtonPrevious == nil) then
      positionReferenceControl = parent
      positionInfo = {"TOPLEFT", "BOTTOMLEFT", offsetX_Initial, offsetY_Initial} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
    else
      positionReferenceControl = tabButtonPrevious
      positionInfo = {"TOPLEFT", "TOPRIGHT", offsetX_Adjacent, offsetY_Adjacent} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
    end
  else
    if (tabButtonPrevious == nil) then
      positionReferenceControl = parent
      positionInfo = {"BOTTOMLEFT", "TOPLEFT", offsetX_Initial, -offsetY_Initial} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
    else
      positionReferenceControl = tabButtonPrevious
      positionInfo = {"BOTTOMLEFT", "BOTTOMRIGHT", offsetX_Adjacent, -offsetY_Adjacent} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
    end
  end
  control:ClearAllPoints()
  control:SetPoint(positionInfo[1], positionReferenceControl, positionInfo[2], positionInfo[3], positionInfo[4])
  -- if (shouldFillWidth) then
  --   EasyOptions:SetControlPointToFillWidth(control, parent, positionInfo, offsetX, 2)
  -- end
  
  EasyOptions:UpdateTabButtonAppearance(control)

  control:HookScript("OnEnter", function(self)
    local control = self
    control.IsHighlighted = true
    EasyOptions:UpdateTabButtonAppearance(control)
  end)
  control:HookScript("OnLeave", function(self)
    local control = self
    control.IsHighlighted = false
    EasyOptions:UpdateTabButtonAppearance(control)
  end)
  local onClickHandlerCustom = onClickHandler
  control:HookScript("OnMouseDown", function(self, button)
    local control = self
    if (control.TabControl ~= nil) and (button == "LeftButton") then
      control.TabControl.MouseDownTabButton = control
    end
    if (onClickHandlerCustom ~= nil) then
      onClickHandlerCustom(self, button)
    end
  end)
  control:HookScript("OnMouseUp", function(self, button)
    local control = self
    if (not control.IsSelected) and (control.IsHighlighted) and (control.TabControl ~= nil) and (control.TabControl.MouseDownTabButton == control) and (button == "LeftButton") then
      control.TabControl:SelectTabButton(control.TabButtonID)
    end
  end)
  -- control:SetScript("OnClick", onClickHandler)
  
  table.insert(tabControl.TabButtons, control)
  table.insert(tabControl.TabButtonFrames, tabButtonFrame)
  EasyOptions:AddControlToOwner(control, tabControl)
  EasyOptions:AddControlToParent(control, tabControl)
  EasyOptions:AddControlToOwner(tabButtonFrame, tabControl)
  EasyOptions:AddControlToParent(tabButtonFrame, tabControl)
  
  -- Override the OnEnabledChangedHandler method.
  local onEnabledChangedHandlerBase = control.OnEnabledChangedHandler
  control.OnEnabledChangedHandler = function(self)
    local control = self
    if (not control:IsEnabled()) then
      control.IsHighlighted = false
    end
    EasyOptions:UpdateTabButtonAppearance(control)
    if (onEnabledChangedHandlerBase ~= nil) then
      onEnabledChangedHandlerBase(self)
    end
  end
  -- EasyOptions:AddSupportForEnabledState(control) -- We do not call this method here because we assume that this method is called in the method that creates this control.
  -- EasyOptions:AddSupportForDesaturationTexture(control, nil, desaturationTexturePadding, desaturationTexturePadding, desaturationTexturePadding, desaturationTexturePadding)
  
  local paddingX = offsetX_Adjacent
  local widthPadding = EasyOptions:IIF(tabsOnBottom, 0, 0)
  local heightPadding = EasyOptions:IIF(tabsOnBottom, 0, 0)
  local widthEffective = width + widthPadding
  local heightEffective = height + heightPadding -- NOTE: We don't use control:GetHeight() because some controls don't implement that method and most controls that support that method return a value that is larger than desired.
  
  local controlRegionWidth = widthEffective
  local controlRegionHeight = heightEffective
  control.ControlRegionWidth = controlRegionWidth
  control.ControlRegionHeight = controlRegionHeight
  tabControl.TabButtonsRegionWidth = tabControl.TabButtonsRegionWidth + controlRegionWidth + EasyOptions:IIF(tabButtonPrevious ~= nil, paddingX, 0)
  tabControl.TabButtonsRegionHeight = math.max(controlRegionHeight, tabControl.TabButtonsRegionHeight)
  EasyOptions:UpdateTabControlAfterAddTabButtons(tabControl) -- IMPORTANT: This must be called after tabControl.TabButtonsRegionWidth and tabControl.TabButtonsRegionHeight are set.

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateTabButtonFrame(tabControl, tabButtonID)
  local controlName = EasyOptions:GetChildControlName(tabControl, ".TabButtonFrame"..tostring(tabButtonID))
  local control = EasyOptions:CreateContainerFrame(controlName, tabControl, false, false, true)
  control.Name = controlName
  control.Type = "TabButtonFrame"
  control.BaseType = "TabButtonFrame"
  control:EnableMouse(false)

  control.TabButtonID = tabButtonID
  
  local width = 1
  local height = 1
  control:SetSize(width, height)

  control:ClearAllPoints()
  control:SetPoint("TOPLEFT", tabControl, "TOPLEFT", 0, 0) -- "LEFT", "TOP", "RIGHT", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  control:SetPoint("BOTTOMRIGHT", tabControl, "BOTTOMRIGHT", 0, 0) -- "LEFT", "TOP", "RIGHT", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  control:Hide()
  
  -- control:SetScript("OnClick", onClickHandler)
  control.OnEnabledChangedHandler = function(self)
    -- Reserved.
  end
  EasyOptions:AddSupportForEnabledState(control)
  
  local controlRegionWidth = width -- tabControl.ControlRegionWidth
  local controlRegionHeight = height -- tabControl.ControlRegionHeight
  control.ControlRegionWidth = controlRegionWidth
  control.ControlRegionHeight = controlRegionHeight
  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionTabControl(parent, positionInfo, optionItem)
  local optionName = optionItem.Name
  local text = EasyOptions:GetControlText(optionItem)
  local tooltipTitleText = optionItem.TooltipTitleText or text
  local tooltipText = optionItem.TooltipText
  local tabInfos = nil
  local tabsOnBottom = optionItem.TabsOnBottom
  local customSize = optionItem.Size
  local allowFillWidthByDefault = (optionItem.AutoFitWidth == false)
  local fontObjectName = nil
  local customFontInfo = optionItem.FontInfo
  local customTextColor = optionItem.TextColor
  --
  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateTabControl(parent, nil, text, tooltipTitleText, tooltipText, tabInfos, tabsOnBottom, positionInfo, customSize, allowFillWidthByDefault, fontObjectName, customFontInfo, customTextColor)
  -- EasyOptions:AddRightButtonDownHandlerForOptionControl(control)
  --
  optionItem.Control = control
  control.OptionItem = optionItem
  if (optionName ~= nil) and (optionName ~= "") then
    EasyOptions.Current.OptionControls[optionName] = control
  end
  
  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateOptionTabButton(parent, positionInfo, optionItem)
  local optionName = optionItem.Name
  local text = EasyOptions:GetControlText(optionItem)
  local tooltipTitleText = optionItem.TooltipTitleText or text
  local tooltipText = optionItem.TooltipText
  local customSize = optionItem.Width
  local onClickHandler = optionItem.OnClickHandler
  
  local tabControl
  local tabButtonID
  if (parent == nil) or (parent.BaseType ~= "TabControl") then
    tabControl = nil
    tabButtonID = 1
  else
    tabControl = parent
    tabButtonID = tabControl:GetNextAvailableTabButtonID()
  end

  local control, controlRegionWidth, controlRegionHeight = EasyOptions:CreateTabButton(parent, tabControl, tabButtonID, text, tooltipTitleText, tooltipText, customSize, onClickHandler)
  -- EasyOptions:AddRightButtonDownHandlerForOptionControl(control)
  
  optionItem.Control = control
  control.OptionItem = optionItem
  control.TabButtonFrame.OptionItem = optionItem
  if (optionName ~= nil) and (optionName ~= "") then
    EasyOptions.Current.OptionControls[optionName] = control
  end
  
  return control.TabButtonFrame, controlRegionWidth, controlRegionHeight -- IMPORTANT: We must return control.TabButtonFrame rather than control so controls of child OptionItems will be added to control.TabButtonFrame.
end
function EasyOptions:UpdateTabControlAfterAddTabButtons(control)
  -- Initialize properties.
  control.TabButtonsRegionWidthPrevious = control.TabButtonsRegionWidthPrevious or 0
  control.TabButtonsRegionHeightPrevious = control.TabButtonsRegionHeightPrevious or 0
  
  -- Update properties.
  control.ControlRegionWidth = math.max(control.ControlRegionWidth, control.TabButtonsRegionWidth)
  control.ControlRegionHeight = control.ControlRegionHeight + (control.TabButtonsRegionHeight - control.TabButtonsRegionHeightPrevious)
  
  -- Resize the TabControl to be wide enough for its TabButtons (if required).
  local marginX = EasyOptions:GetDefaultTabButtonMarginX()
  local controlWidth = control:GetWidth()
  local controlWidthMinDesired = control.TabButtonsRegionWidth + 2 * marginX
  if (control.AllowResizeToFitTabButtons) and (controlWidth < controlWidthMinDesired) then
    control:SetWidth(controlWidthMinDesired)
    control.ControlRegionWidth = math.max(control:GetWidthEffective(), control.LabelRegionWidth)
    controlWidth = control:GetWidth()
  end

  -- Reposition the TabControl and its label to account for the height of the TabButtons region (if required).
  if (control.TabButtonsRegionHeight > control.TabButtonsRegionHeightPrevious) then
    local deltaLeft = 0
    local deltaRight = 0
    local deltaTop = -(control.TabButtonsRegionHeight - control.TabButtonsRegionHeightPrevious)
    local deltaBottom = -deltaTop
    if (control.TabsOnBottom) then
      EasyOptions:MoveFrame(control, deltaLeft, deltaRight, 0, deltaBottom) -- NOTE: This will only move the control up if the control is docked to the bottom of its parent.
    else
      EasyOptions:MoveFrame(control.LabelControl, deltaLeft, deltaRight, deltaTop, deltaBottom)
      EasyOptions:MoveFrame(control, deltaLeft, deltaRight, deltaTop, 0)
    end
  end
  
  -- Update the state of the TabButtons.
  local tabButtonIDOfSelectedTabButton = control:GetTabButtonIDOfSelectedTabButton() or 1 -- init
  local optionItem = control.OptionItem
  if (optionItem ~= nil) then
    if (EasyOptionsDB["EnableStickyTabButtons"]) then
      -- Restore the previously selected tab from options.
      local optionName = optionItem.Name
      local value = EasyOptions:GetOptionValueOrDefaultValue(optionName, nil) -- IMPORTANT: We don't pass optionItem.DefaultValue because we want to use a value that is stored in options, but not the default value for the option item.
      if (control:IsValidTabButtonID(value)) then
        tabButtonIDOfSelectedTabButton = value
      end
    else
      -- -- Set the option value to the initially selected tab.
      -- local allowUpdateControl = false
      -- EasyOptions:SetOptionValueFromControlInfo(control, tabButtonIDOfSelectedTabButton, allowUpdateControl)
    end
  end
  control:SelectTabButton(tabButtonIDOfSelectedTabButton) -- IMPORTANT: We must call control:SelectTabButton after a new tab is added to the TabControl in order to update the graphics of the TabButton that was added, even if the newly added TabButton should not be selected.
  
  -- Update properties.
  control.TabButtonsRegionWidthPrevious = control.TabButtonsRegionWidth
  control.TabButtonsRegionHeightPrevious = control.TabButtonsRegionHeight
end
function EasyOptions:UpdateTabButtonAppearance(control)
  if (control == nil) then
    return
  end

  -- Height
  local height = EasyOptions:IIF(control.IsSelected, EasyOptions:GetDefaultSelectedTabButtonHeight(), EasyOptions:GetDefaultTabButtonHeight())
  control:SetHeight(height)

  -- Text
  if (control:IsEnabled()) then -- Only modify the text color if the control is enabled.
    local textColor = EasyOptions:IIF(control.IsSelected or control.IsHighlighted, {1.0, 1.0, 1.0}, EasyOptionsDB["ControlHighlightColor"]) -- The text color of the standard WoW TabButton is white when it is selected and the highlight color (a.k.a., title color) when it is not selected.
    control.Label:SetTextColor(textColor[1], textColor[2], textColor[3], 1.0)
    EasyOptions:SetDefaultTextColor(control.Label, true) -- Update the control's default text color.
  end

  -- Backdrop & Border
  EasyOptions:UpdateTabButtonBorderBackdropInfo(control)
  local backdropColor, backdropBorderColor, highlightTextureColor = EasyOptions:GetTabButtonColors(control)
  control:SetBackdropColor(backdropColor[1], backdropColor[2], backdropColor[3], backdropColor[4] or 1.0)
  control:SetBackdropBorderColor(backdropBorderColor[1], backdropBorderColor[2], backdropBorderColor[3], backdropBorderColor[4] or 1.0)

  -- HighlightTexture
  if (control.HighlightTexture == nil) then
    EasyOptions:SetTabButtonHighlightTexture(control)
  end
  local highlightTextureVisible = control.IsSelected or control.IsHighlighted
  control.HighlightTexture:SetVertexColor(highlightTextureColor[1], highlightTextureColor[2], highlightTextureColor[3], 1.0)
  EasyOptions:SetVisibleState(control.HighlightTexture, highlightTextureVisible)
end
function EasyOptions:UpdateTabButtonBorderBackdropInfo(control)
  if (control == nil) then
    return
  end
  local backdropInfo = EasyOptions:GetTabButtonBorderBackdropInfo(control)
  control:SetBackdrop(backdropInfo)
end
function EasyOptions:GetTabButtonBorderBackdropInfo(control)
  local controlStyle = EasyOptionsDB["ControlStyle"]
  local backdropInfo = EasyOptions:GetDefaultBorderBackdropInfo(controlStyle) -- init
  backdropInfo.edgeFile = EasyOptions:GetTabButtonBorderTextureFilePath(control)
  backdropInfo.edgeSize = math.min(0.5 * EasyOptions:GetTabButtonHeightMin(), backdropInfo.edgeSize) -- IMPORTANT: The edgeSize must be <= half the width or height of the control (whichever is smaller) to prevent overlaps where the side and corner textures join.
  if (not control.TabsOnBottom) then
    backdropInfo.insets.bottom = 0 -- Do not indent the frame along the bottom edge.
  else
    backdropInfo.insets.top = 0 -- Do not indent the frame along the top edge.
  end
  return backdropInfo
end
function EasyOptions:GetTabButtonColors(control) -- backdropColor, backdropBorderColor, highlightTextureColor
  local backdropColor
  local backdropColorBase = {(32 / 255), (32 / 255), (32 / 255)}
  local backdropBorderColor
  local backdropBorderColorBase = {(128 / 255), (128 / 255), (128 / 255)}
  local highlightTextureColor
  local highlightColorBase = EasyOptionsDB["ControlHighlightColor"]
  if (control.IsSelected) and (control:IsEnabled()) then
    backdropColor = backdropColorBase
    backdropBorderColor = EasyOptions:LightenColor(highlightColorBase, 0.25)
    highlightTextureColor = EasyOptions:DarkenColor(highlightColorBase, 0.5)
  elseif (control.IsHighlighted) and (control:IsEnabled()) then
    backdropColor = EasyOptions:LightenColor(backdropColorBase, 0.125)
    backdropBorderColor = EasyOptions:LightenColor(backdropBorderColorBase, 0.5)
    highlightTextureColor = EasyOptions:LightenColor(backdropColorBase, 0.0625)
  elseif (not control:IsEnabled()) then
    backdropColor = backdropColorBase
    backdropBorderColor = backdropBorderColorBase
    highlightTextureColor = {(64 / 255), (64 / 255), (64 / 255)}
  else
    backdropColor = backdropColorBase
    backdropBorderColor = backdropBorderColorBase
    highlightTextureColor = EasyOptions:LightenColor(backdropColorBase, 0.0625)
  end
  return backdropColor, backdropBorderColor, highlightTextureColor
end
function EasyOptions:GetTabButtonBorderTextureFilePath(control)
  if (not control.TabsOnBottom) then
    if (control.IsSelected) then
      return EasyOptions:GetTextureInfo("TabButtonBorderHighlightTopFilePath")
    else
      return EasyOptions:GetTextureInfo("TabButtonBorderNormalTopFilePath")
    end
  else
    if (control.IsSelected) then
      return EasyOptions:GetTextureInfo("TabButtonBorderHighlightBottomFilePath")
    else
      return EasyOptions:GetTextureInfo("TabButtonBorderNormalBottomFilePath")
    end
  end
end
function EasyOptions:SetTabButtonHighlightTexture(control)
  if (control == nil) then
    return
  end

  local highlightTextureSubLevel = 4 -- -8 to 7 -- Specifies the sublevel of the texture. The control's background is at drawLayer = "BACKGROUND", sublevel = 0.
  local highlightTexturePadding = EasyOptions:GetDefaultBorderBackdropInset(nil)
  control.HighlightTexture = control:CreateTexture(nil, "BACKGROUND", nil, highlightTextureSubLevel)
  if (not control.TabsOnBottom) then
    control.HighlightTexture:SetTexture(EasyOptions:GetTextureInfo("TabButtonBackgroundHighlightTopFilePath"))
    control.HighlightTexture:SetPoint("TOPLEFT", control, "TOPLEFT", highlightTexturePadding, -highlightTexturePadding)
    control.HighlightTexture:SetPoint("BOTTOMRIGHT", control, "BOTTOMRIGHT", -highlightTexturePadding, 0)
  else
    control.HighlightTexture:SetTexture(EasyOptions:GetTextureInfo("TabButtonBackgroundHighlightBottomFilePath"))
    control.HighlightTexture:SetPoint("TOPLEFT", control, "TOPLEFT", highlightTexturePadding, 0)
    control.HighlightTexture:SetPoint("BOTTOMRIGHT", control, "BOTTOMRIGHT", -highlightTexturePadding, highlightTexturePadding)
  end
end
function EasyOptions:SelectTabButton(tabControl, tabButtonID)
  if (tabControl:GetNumberOfTabButtons() == 0) then
    return
  end

  -- Update control properties.
  local length = tabControl:GetNumberOfTabButtons()
  local tabButton
  local tabButtonFrame
  tabControl.SelectedTabButton = nil -- init
  for i = 1, length do
    tabButton = tabControl.TabButtons[i]
    tabButtonFrame = tabButton.TabButtonFrame
    -- Set tabButton.IsSelected.
    tabButton.IsSelected = (tabButton.TabButtonID == tabButtonID)
    if (tabButton.IsSelected) then
      tabControl.SelectedTabButton = tabButton
    end
    -- Update the TabButton's appearance.
    EasyOptions:UpdateTabButtonAppearance(tabButton)
    -- Update the visible state of the TabButton's TabButtonFrame.
    if (tabButtonFrame ~= nil) then
      EasyOptions:SetVisibleState(tabButtonFrame, tabButton.IsSelected)
    end
  end
end
function EasyOptions:GetTabControlValue(control)
  if (control.SelectedTabButton == nil) then
    return nil
  else
    return control.SelectedTabButton.TabButtonID
  end
end
function EasyOptions:SetTabControlValue(control, tabButtonID)
  -- Update the control.
  EasyOptions:SelectTabButton(control, tabButtonID)

  -- Update Options (if required).
  if (not EasyOptions.Current.IsBuildingOptionFrame) then
    local allowUpdateControl = false
    EasyOptions:SetOptionValueFromControlInfo(control, tabButtonID, allowUpdateControl)
  end
end
function EasyOptions:GetDefaultTabControlSize()
  return EasyOptions:GetDefaultGroupBoxSize()
end
function EasyOptions:GetDefaultSelectedTabButtonHeight()
  return 26 -- Specifies the height of selected TabButtons.
end
function EasyOptions:GetDefaultTabButtonHeight()
  return math.max(EasyOptions:GetDefaultSelectedTabButtonHeight() - 4, 0) -- Specifies the height of TabButtons that are not selected.
end
function EasyOptions:GetTabButtonHeightMin()
  return math.min(EasyOptions:GetDefaultSelectedTabButtonHeight(), EasyOptions:GetDefaultTabButtonHeight())
end
function EasyOptions:GetTabButtonHeightMax()
  return math.max(EasyOptions:GetDefaultSelectedTabButtonHeight(), EasyOptions:GetDefaultTabButtonHeight())
end
function EasyOptions:GetDefaultTabButtonMarginX()
  -- Description: Specifies the default distance from the left edge of a TabControl to the left edge of the first TabButton.
  return 4
end
function EasyOptions:GetDefaultTabButtonPaddingX()
  -- Description: Specifies the default distance between TabButtons.
  return 0 -- The WoW API uses a value of 3.
end
