--[[
Author: Jarth
Filename: CBs_Settings_List.lua
]] --
-------------------------------------------------------------------------------------------------
-- VARIABLES --
-------------------------------------------------------------------------------------------------
local base = CollectionBars
local texts = base.Texts

-------------------------------------------------------------------------------------------------
-- FUNCTIONS --
-------------------------------------------------------------------------------------------------
CBs_Settings_List = ZO_SortFilterList:Subclass()

function CBs_Settings_List:New(...)
    self.list = ZO_SortFilterList.New(self, ...)
    self.masterListType = texts.Components.Collectibles
    return self.list
end

function CBs_Settings_List:Initialize(category, ...)
    ZO_SortFilterList.Initialize(self, ...)
    self.category = category
    self.masterList = {}
    if not (self.category and self.category.Enabled) then self.masterListType = texts.Components.Categories end

    self:SetAlternateRowBackgrounds(false)
    self:AppendDataTypes()
end

-------------------------------------------------------------------------------------------------
-- FUNCTIONS - Append DataTypes --
-------------------------------------------------------------------------------------------------

function CBs_Settings_List:AppendDataTypes()
    local listRowAnd = base.Addon.Abbreviation .. texts.Helpers.Lowdash .. texts.Components.Settings .. texts.Helpers.Lowdash .. texts.Components.List .. texts.Components.Row .. texts.Helpers.Lowdash
    local categoriesAnd = texts.Components.Category .. texts.Helpers.Lowdash
    local dataTypes = {
        [10] = {name = listRowAnd .. texts.Components.Checkbox, height = 40, func = function(...) self:SetupRow_Checkbox(...) end},
        [11] = {name = listRowAnd .. categoriesAnd .. texts.Components.Title, height = 40, func = function(...) self:SetupRow_Category_Title(...) end},
        [15] = {name = listRowAnd .. categoriesAnd .. texts.Components.Checkbox, height = 40, func = function(...) self:SetupRow_Category_Checkbox(...) end},
        [20] = {name = listRowAnd .. texts.Components.Dropdown, height = 40, func = function(...) self:SetupRow_Dropdown(...) end},
        [30] = {name = listRowAnd .. texts.Components.Slider, height = 40, func = function(...) self:SetupRow_Slider(...) end},
        [40] = {name = listRowAnd .. texts.Components.EditBox, height = 40, func = function(...) self:SetupRow_EditBox(...) end},
        [50] = {name = listRowAnd .. texts.Components.Title, height = 40, func = function(...) self:SetupRow_Title(...) end},
        [60] = {name = listRowAnd .. texts.Components.Button, height = 40, func = function(...) self:SetupRow_Button(...) end},
        [100] = {name = listRowAnd .. texts.Components.Divider, height = 6, func = function(...) ZO_SortFilterList.SetupRow(self, ...) end}
    }

    for index, dataType in pairs(dataTypes) do ZO_ScrollList_AddDataType(self.list, index, dataType.name, dataType.height, dataType.func) end
end

-------------------------------------------------------------------------------------------------
-- FUNCTIONS - Append and Setup RowTypes --
-------------------------------------------------------------------------------------------------

function CBs_Settings_List:AppendRow_Checkbox(listType, data)
    data.listType = listType
    data.dataTypeId = 10
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_Checkbox(control, data)
    control.data = data
    ZO_SortFilterList.SetupRow(self, control, data)

    control.checkbox = GetControl(control, texts.Components.Checkbox)
    if control.checkbox then
        control.checkbox.tooltipText = data.tooltipText
        ZO_CheckButton_SetCheckState(control.checkbox, control.data.funcGet and control.data.funcGet())
        ZO_CheckButton_SetLabelText(control.checkbox, data.name)
        if control.checkbox.label then
            control.checkbox.label.defaultNormalColor = ZO_DEFAULT_ENABLED_COLOR
            control.checkbox.label:ClearAnchors()
            control.checkbox.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0)
            control.checkbox.label:SetAnchor(BOTTOMRIGHT, control.checkbox, BOTTOMLEFT)
        end
        ZO_CheckButton_SetTooltipAnchor(control.checkbox, TOP, control.checkbox.label)
        ZO_CheckButton_SetToggleFunction(control.checkbox, control.data.funcSet)
        ZO_CheckButton_SetEnableState(control.checkbox, not (control.data.disabledFunc and control.data.disabledFunc()))
    end
end

function CBs_Settings_List:AppendRow_Category_Title(listType, data)
    data.listType = listType
    data.dataTypeId = 11
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_Category_Title(control, data)
    control.data = data
    ZO_SortFilterList.SetupRow(self, control, control.data)
    control:SetHandler(texts.Action.OnMouseUp, function()
        local savedTypeData = base.Saved[data.name]
        if savedTypeData ~= nil then
            savedTypeData.ShowChildren = not savedTypeData.ShowChildren
            base.Global.SettingsList:RefreshFilters()
        end
    end)

    self.SetNameText(control, control.data.name)
    self.SetupIcon(control, control.data)
    self.SetActiveOrInactive(control)
end

function CBs_Settings_List:AppendRow_Category_Checkbox(listType, data)
    data.listType = listType
    data.dataTypeId = 15
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_Category_Checkbox(control, data)
    control.data = data
    self:SetupRow_Checkbox(control, data)
    control.button = GetControl(control, texts.Components.Button)
    if control.button then
        control.button:SetHidden(false)
        local isEnabled = control.data.funcGet and control.data.funcGet()
        ZO_CheckButton_SetEnableState(control.button, isEnabled)
        control.button:SetAlpha(isEnabled and 1 or 0.5)
        base.SetupSettingsFrameHandlers(control.button, data.tooltipText, function()
            PlaySound(SOUNDS.SINGLE_SETTING_RESET_TO_DEFAULT)
            control.data.funcCog(control.slider, data.default)
        end)
    end

    local hasIcon = self.SetupIcon(control, data)
    if control.checkbox ~= nil and control.checkbox.label ~= nil and hasIcon then control.checkbox.label:SetAnchor(TOPLEFT, control, TOPLEFT, 26) end
end

function CBs_Settings_List:AppendRow_Dropdown(listType, data)
    data.listType = listType
    data.dataTypeId = 20
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_Dropdown(control, data)
    control.data = data
    ZO_SortFilterList.SetupRow(self, control, data)

    control.dropdown = GetControl(control, texts.Components.Dropdown)
    control.comboBox = ZO_ComboBox_ObjectFromContainer(control.dropdown)
    control.comboBox:SetSortsItems(false)
    control.comboBox:SetFont(texts.Font.ZoFontWinT1)
    control.comboBox:SetSpacing(4)
    control.comboBox.tooltipText = data.tooltipText

    self.SetNameText(control, control.data.name)
    self.RepopulateDropdownOptions(control)
    self.SetActiveOrInactive(control)
end

function CBs_Settings_List:AppendRow_Slider(listType, data)
    data.listType = listType
    data.dataTypeId = 30
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_Slider(control, data)
    control.data = data
    ZO_SortFilterList.SetupRow(self, control, control.data)

    control.slider = GetControl(control, texts.Components.Slider)
    -- Need to override the existing value changed handler first so it doesn't run when we do the SetMinMax
    control.slider:SetHandler(texts.Action.OnValueChanged, nil)
    control.slider:SetMinMax(control.data.minValue, control.data.maxValue)
    control.slider:SetValueStep(control.data.valueStep or 1)
    control.slider:SetValue(data.funcGet())
    control.slider:SetHandler(texts.Action.OnValueChanged, control.data.funcSet)

    if data.default then
        if control.defaultMarkerControl == nil then
            local defaultMarker = texts.Components.Default .. texts.Components.Marker
            control.defaultMarkerControl = CreateControlFromVirtual(texts.Components.Parent .. defaultMarker, control.slider, texts.Components.ZOOptions .. defaultMarker)
        end
        local offsetX = zo_clampedPercentBetween(data.minValue, data.maxValue, data.default) * control.slider:GetWidth()
        control.defaultMarkerControl:SetAnchor(TOP, control.slider, LEFT, offsetX + .25, 6)

        control.defaultMarkerControl:SetHandler(texts.Action.OnClicked, function()
            PlaySound(SOUNDS.SINGLE_SETTING_RESET_TO_DEFAULT)
            control.slider:SetValue(data.default)
            control.data.funcSet(control.slider, data.default)
        end)
    end

    local valueLabelControl = GetControl(control, texts.Components.Value .. texts.Components.Label)
    if valueLabelControl and data.showValue then
        local shownVal = data.funcGet()
        if data.valueMin and data.valueMax and data.valueMax > data.valueMin then
            local range = data.maxValue - data.minValue
            local percentage = (shownVal - data.minValue) / range

            local shownRange = data.valueMax - data.valueMin
            shownVal = data.valueMin + percentage * shownRange
            shownVal = string.format(texts.Format.Decimal, shownVal)
        end
        valueLabelControl:SetText(shownVal)
    end

    self.SetNameText(control, control.data.name)
    self.SetActiveOrInactive(control)
end

function CBs_Settings_List:AppendRow_EditBox(listType, data)
    data.listType = listType
    data.dataTypeId = 40
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_EditBox(control, data)
    control.data = data
    ZO_SortFilterList.SetupRow(self, control, control.data)

    control.editBox = GetControl(control, texts.Components.EditBox)
    if control.editBox then
        ZO_EditDefaultText_Initialize(control.editBox)
        control.editBox:SetHandler(texts.Action.OnTextChanged, nil)
        control.editBox:SetText(data.funcGet())
        control.editBox:SetHandler(texts.Action.OnTextChanged, function() data.funcSet(control.editBox) end)
    end

    self.SetNameText(control, control.data.name)
    self.SetActiveOrInactive(control)
end

function CBs_Settings_List:AppendRow_Title(listType, data)
    data.listType = listType
    data.dataTypeId = 50
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_Title(control, data)
    control.data = data
    ZO_SortFilterList.SetupRow(self, control, data)

    local fontOverrides = nil
    if data.hasChildren then fontOverrides = {font = texts.Font.ZoFontWinH4, modifyTextType = MODIFY_TEXT_TYPE_NONE} end
    self.SetNameText(control, data.name, fontOverrides)
    self.SetActiveOrInactive(control)
end

function CBs_Settings_List:AppendRow_Button(listType, data)
    data.listType = listType
    data.dataTypeId = 60
    table.insert(self.masterList, data)
end

function CBs_Settings_List:SetupRow_Button(control, data)
    control.data = data
    ZO_SortFilterList.SetupRow(self, control, control.data)

    control.button = GetControl(control, texts.Components.Button)
    if control.button then
        control.button:SetText(control.data.buttonName or texts.Helpers.EmptyString)
        control.button:SetHandler(texts.Action.OnClicked, function() control.data.funcSet() end)
    end

    self.SetNameText(control, control.data.name)
    self.SetActiveOrInactive(control)
end

function CBs_Settings_List:AppendRow_Divider(listType, data)
    data.listType = listType
    data.dataTypeId = 100
    table.insert(self.masterList, data)
end

-------------------------------------------------------------------------------------------------
-- FUNCTIONS - SetupRowType - Helpers --
-------------------------------------------------------------------------------------------------
function CBs_Settings_List.RepopulateDropdownOptions(control)
    control.comboBox:ClearItems()

    local selectedValue = control.data.funcGet()
    local selectedEntry = nil
    for _, optionValue in pairs(control.data.choices or {}) do
        local entry = ZO_ComboBox:CreateItemEntry(optionValue, control.data.funcSet)
        control.comboBox:AddItem(entry)

        if optionValue == selectedValue then selectedEntry = entry end
    end
    control.comboBox:SelectItem(selectedEntry)
end

function CBs_Settings_List.SetNameText(control, text, fontOverrides)
    if control.label == nil then control.label = GetControl(control, texts.Components.Name) end
    if control.label ~= nil then
        if fontOverrides ~= nil then
            control.label:SetFont(fontOverrides.font)
            control.label:SetModifyTextType(fontOverrides.modifyTextType)
        end
        control.label:SetText(text or texts.Helpers.EmptyString)
    end
end

function CBs_Settings_List.SetupIcon(control, data)
    if control.icon == nil then control.icon = GetControl(control, texts.Components.Icon) end
    if control.icon ~= nil then
        local hasIcon = data.icon ~= nil
        control.icon:SetHidden(not hasIcon)
        control.icon:SetTexture(data.icon and data.icon[1])

        if data.icon[1] ~= nil and data.icon[3] ~= nil then
            control:SetHandler(texts.Action.OnMouseEnter, function() control.icon:SetTexture(data.icon[3]) end)
            control:SetHandler(texts.Action.OnMouseExit, function() control.icon:SetTexture(data.icon[1]) end)
        end
        return hasIcon
    end
end

function CBs_Settings_List.SetActiveOrInactive(control)
    local disabled = control.data.disabledFunc and control.data.disabledFunc()

    control.label = GetControl(control, texts.Components.Name)
    if control.label then
        if disabled then
            control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
        else
            control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
        end
    end

    control.valueLabelControl = GetControl(control, texts.Components.Value .. texts.Components.Label)
    if control.valueLabelControl then
        if disabled then
            control.valueLabelControl:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
        else
            control.valueLabelControl:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
        end
    end

    if control.button then control.button:SetEnabled(not disabled) end

    if control.comboBox then control.comboBox:SetEnabled(not disabled) end

    if control.slider then control.slider:SetEnabled(not disabled) end

    if control.editBox then ZO_DefaultEdit_SetEnabled(control.editBox, not disabled) end
end

-------------------------------------------------------------------------------------------------
-- FUNCTIONS - MasterList --
-------------------------------------------------------------------------------------------------
function CBs_Settings_List:BuildMasterList()
    self.masterList = {}

    base.AppendMasterListTypeGeneral(self, texts.Components.General)
    base.AppendMasterListTypeCategories(self, texts.Components.Categories)
    base.AppendMasterListTypeCombined(self, texts.Components.Combined)
    if self.category then
        base.AppendMasterListTypeCollectibles(self, texts.Components.Collectibles)
        base.AppendMasterListTypeCategory(self, texts.Components.Category)
    else
        base.AppendMasterListTypeNoCategory(self, texts.Components.Collectibles)
        base.AppendMasterListTypeNoCategory(self, texts.Components.Category)
    end
end

function CBs_Settings_List:FilterScrollList()
    local scrollData = ZO_ScrollList_GetDataList(self.list)
    ZO_ClearNumericallyIndexedTable(scrollData)

    for i = 1, #self.masterList do
        if self.masterListType == nil or self.masterListType == self.masterList[i].listType then
            if self.masterListType == texts.Components.Categories and self.masterList[i].parentKey ~= nil then
                local savedTypeData = base.Saved[self.masterList[i].parentKey]
                if savedTypeData ~= nil and savedTypeData.ShowChildren or savedTypeData == nil then
                    scrollData[#scrollData + 1] = ZO_ScrollList_CreateDataEntry(self.masterList[i].dataTypeId, self.masterList[i])
                end
            else
                scrollData[#scrollData + 1] = ZO_ScrollList_CreateDataEntry(self.masterList[i].dataTypeId, self.masterList[i])
            end
        end
    end
end

function CBs_Settings_List:SortScrollList() end