--[[iconpickerData = {
    type = "iconpicker",
    name = "My Icon Picker", -- or string id or function returning a string
    choices = {"texture path 1", "texture path 2", "texture path 3"},
    getFunc = function() return db.var end,
    setFunc = function(var) db.var = var doStuff() end,
    tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional)
    choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional)
    maxColumns = 5, -- number of icons in one row (optional)
    visibleRows = 4.5, -- number of visible rows (optional)
    iconSize = 28, -- size of the icons (optional)
    defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional)
    width = "full", --or "half" (optional)
    beforeShow = function(control, iconPicker) return preventShow end, --(optional)
    disabled = function() return db.someBooleanSetting end, --or boolean (optional)
    warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional)
    requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional)
    default = defaults.var, -- default value or function that returns the default value (optional)
    reference = "MyAddonIconPicker" -- unique global reference to control (optional)
} ]]

local widgetVersion = 8
local LAM = LibStub("LibAddonMenu-2.0")
if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end

local wm = WINDOW_MANAGER

local IconPickerMenu = ZO_Object:Subclass()
local iconPicker
LAM.util.GetIconPickerMenu = function()
    if not iconPicker then
        iconPicker = IconPickerMenu:New("LAMIconPicker")
        local sceneFragment = LAM:GetAddonSettingsFragment()
        ZO_PreHook(sceneFragment, "OnHidden", function()
            if not iconPicker.control:IsHidden() then
                iconPicker:Clear()
            end
        end)
    end
    return iconPicker
end

function IconPickerMenu:New(...)
    local object = ZO_Object.New(self)
    object:Initialize(...)
    return object
end

function IconPickerMenu:Initialize(name)
    local control = wm:CreateTopLevelWindow(name)
    control:SetDrawTier(DT_HIGH)
    control:SetHidden(true)
    self.control = control

    local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer")
    -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count
    scrollContainer:SetAnchorFill()
    ZO_Scroll_SetUseFadeGradient(scrollContainer, false)
    ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false)
    ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value
    local scroll = GetControl(scrollContainer, "ScrollChild")
    self.scroll = scroll
    self.scrollContainer = scrollContainer

    local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP)
    bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3)
    bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5)
    bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
    bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
    bg:SetInsets(16, 16, -16, -16)

    local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
    mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
    mungeOverlay:SetDrawLevel(1)
    mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
    mungeOverlay:SetAnchorFill()

    local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE)
    mouseOver:SetDrawLevel(2)
    mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds")
    mouseOver:SetHidden(true)

    local function IconFactory(pool)
        local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE)
        icon:SetMouseEnabled(true)
        icon:SetDrawLevel(3)
        icon:SetHandler("OnMouseEnter", function()
            mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0)
            mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0)
            mouseOver:SetHidden(false)
            if self.customOnMouseEnter then
                self.customOnMouseEnter(icon)
            else
                self:OnMouseEnter(icon)
            end
        end)
        icon:SetHandler("OnMouseExit", function()
            mouseOver:ClearAnchors()
            mouseOver:SetHidden(true)
            if self.customOnMouseExit then
                self.customOnMouseExit(icon)
            else
                self:OnMouseExit(icon)
            end
        end)
        icon:SetHandler("OnMouseUp", function(control, ...)
            PlaySound("Click")
            icon.OnSelect(icon, icon.texture)
            self:Clear()
        end)
        return icon
    end

    local function ResetFunction(icon)
        icon:ClearAnchors()
    end

    self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction)
    self:SetMaxColumns(1)
    self.icons = {}
    self.color = ZO_DEFAULT_ENABLED_COLOR

    EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function()
        if self.refCount ~= nil then
            local moc = wm:GetMouseOverControl()
            if(moc:GetOwningWindow() ~= control) then
                self.refCount = self.refCount - 1
                if self.refCount <= 0 then
                    self:Clear()
                end
            end
        end
    end)
end

function IconPickerMenu:OnMouseEnter(icon)
    InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT)
    SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip))
    InformationTooltipTopLevel:BringWindowToTop()
end

function IconPickerMenu:OnMouseExit(icon)
    ClearTooltip(InformationTooltip)
end

function IconPickerMenu:SetMaxColumns(value)
    self.maxCols = value ~= nil and value or 5
end

local DEFAULT_SIZE = 28
function IconPickerMenu:SetIconSize(value)
    local iconSize = DEFAULT_SIZE
    if value ~= nil then iconSize = math.max(iconSize, value) end
    self.iconSize = iconSize
end

function IconPickerMenu:SetVisibleRows(value)
    self.visibleRows = value ~= nil and value or 4.5
end

function IconPickerMenu:SetMouseHandlers(onEnter, onExit)
    self.customOnMouseEnter = onEnter
    self.customOnMouseExit = onExit
end

function IconPickerMenu:UpdateDimensions()
    local iconSize = self.iconSize
    local width = iconSize * self.maxCols + 20
    local height = iconSize * self.visibleRows
    self.control:SetDimensions(width, height)

    local icons = self.icons
    for i = 1, #icons do
        local icon = icons[i]
        icon:SetDimensions(iconSize, iconSize)
    end
end

function IconPickerMenu:UpdateAnchors()
    local iconSize = self.iconSize
    local col, maxCols = 1, self.maxCols
    local previousCol, previousRow
    local scroll = self.scroll
    local icons = self.icons

    for i = 1, #icons do
        local icon = icons[i]
        icon:ClearAnchors()
        if i == 1 then
            icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0)
            previousRow = icon
        elseif col == 1 then
            icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0)
            previousRow = icon
        else
            icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0)
        end
        previousCol = icon
        col = col >= maxCols and 1 or col + 1
    end
end

function IconPickerMenu:Clear()
    self.icons = {}
    self.iconPool:ReleaseAllObjects()
    self.control:SetHidden(true)
    self.color = ZO_DEFAULT_ENABLED_COLOR
    self.refCount = nil
    self.parent = nil
    self.customOnMouseEnter = nil
    self.customOnMouseExit = nil
end

function IconPickerMenu:AddIcon(texturePath, callback, tooltip)
    local icon, key = self.iconPool:AcquireObject()
    icon:SetTexture(texturePath)
    icon:SetColor(self.color:UnpackRGBA())
    icon.texture = texturePath
    icon.tooltip = tooltip
    icon.OnSelect = callback
    self.icons[#self.icons + 1] = icon
end

function IconPickerMenu:Show(parent)
    if #self.icons == 0 then return false end
    if not self.control:IsHidden() then self:Clear() return false end
    self:UpdateDimensions()
    self:UpdateAnchors()

    local control = self.control
    control:ClearAnchors()
    control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8)
    control:SetHidden(false)
    control:BringWindowToTop()
    self.parent = parent
    self.refCount = 2

    return true
end

function IconPickerMenu:SetColor(color)
    local icons = self.icons
    self.color = color
    for i = 1, #icons do
        local icon = icons[i]
        icon:SetColor(color:UnpackRGBA())
    end
end

-------------------------------------------------------------

local function UpdateChoices(control, choices, choicesTooltips)
    local data = control.data
    if not choices then
        choices, choicesTooltips = data.choices, data.choicesTooltips or {}
    end
    local addedChoices = {}

    local iconPicker = LAM.util.GetIconPickerMenu()
    iconPicker:Clear()
    for i = 1, #choices do
        local texture = choices[i]
        if not addedChoices[texture] then -- remove duplicates
            iconPicker:AddIcon(choices[i], function(self, texture)
                control.icon:SetTexture(texture)
                data.setFunc(texture)
                LAM.util.RequestRefreshIfNeeded(control)
            end, LAM.util.GetStringFromValue(choicesTooltips[i]))
        addedChoices[texture] = true
        end
    end
end

local function IsDisabled(control)
    if type(control.data.disabled) == "function" then
        return control.data.disabled()
    else
        return control.data.disabled
    end
end

local function SetColor(control, color)
    local icon = control.icon
    if IsDisabled(control) then
        icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
    else
        icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR
        icon:SetColor(icon.color:UnpackRGBA())
    end

    local iconPicker = LAM.util.GetIconPickerMenu()
    if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
        iconPicker:SetColor(icon.color)
    end
end

local function UpdateDisabled(control)
    local disable = IsDisabled(control)

    control.dropdown:SetMouseEnabled(not disable)
    control.dropdownButton:SetEnabled(not disable)

    local iconPicker = LAM.util.GetIconPickerMenu()
    if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
        iconPicker:Clear()
    end

    SetColor(control, control.icon.color)
    if disable then
        control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
    else
        control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
    end
end

local function UpdateValue(control, forceDefault, value)
    if forceDefault then --if we are forcing defaults
        value = LAM.util.GetDefaultValue(control.data.default)
        control.data.setFunc(value)
        control.icon:SetTexture(value)
    elseif value then
        control.data.setFunc(value)
        --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
        LAM.util.RequestRefreshIfNeeded(control)
    else
        value = control.data.getFunc()
        control.icon:SetTexture(value)
    end
end

local MIN_HEIGHT = 26
local HALF_WIDTH_LINE_SPACING = 2
local function SetIconSize(control, size)
    local icon = control.icon
    icon.size = size
    icon:SetDimensions(size, size)

    local height = size + 4
    control.dropdown:SetDimensions(size + 20, height)
    height = math.max(height, MIN_HEIGHT)
    control.container:SetHeight(height)
    if control.lineControl then
        control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING)
    else
        control:SetHeight(height)
    end

    local iconPicker = LAM.util.GetIconPickerMenu()
    if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
        iconPicker:SetIconSize(size)
        iconPicker:UpdateDimensions()
        iconPicker:UpdateAnchors()
    end
end

function LAMCreateControl.iconpicker(parent, iconpickerData, controlName)
    local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName)

    local function ShowIconPicker()
        local iconPicker = LAM.util.GetIconPickerMenu()
        if iconPicker.parent == control.container then
            iconPicker:Clear()
        else
            iconPicker:SetMaxColumns(iconpickerData.maxColumns)
            iconPicker:SetVisibleRows(iconpickerData.visibleRows)
            iconPicker:SetIconSize(control.icon.size)
            UpdateChoices(control)
            iconPicker:SetColor(control.icon.color)
            if iconpickerData.beforeShow then
                if iconpickerData.beforeShow(control, iconPicker) then
                    iconPicker:Clear()
                    return
                end
            end
            iconPicker:Show(control.container)
        end
    end

    local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE
    control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL)
    local dropdown = control.dropdown
    dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0)
    dropdown:SetMouseEnabled(true)
    dropdown:SetHandler("OnMouseUp", ShowIconPicker)
    dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
    dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)

    control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE)
    local icon = control.icon
    icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0)
    icon:SetDrawLevel(2)

    local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton")
    dropdownButton:SetDimensions(16, 16)
    dropdownButton:SetHandler("OnClicked", ShowIconPicker)
    dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0)
    control.dropdownButton = dropdownButton

    control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP)
    local bg = control.bg
    bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3)
    bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5)
    bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16)
    bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds")
    bg:SetInsets(16, 16, -16, -16)
    local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
    mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
    mungeOverlay:SetDrawLevel(1)
    mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
    mungeOverlay:SetAnchorFill()

    if iconpickerData.warning ~= nil or iconpickerData.requiresReload then
        control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
        control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0)
        control.UpdateWarning = LAM.util.UpdateWarning
        control:UpdateWarning()
    end

    control.UpdateChoices = UpdateChoices
    control.UpdateValue = UpdateValue
    control:UpdateValue()
    control.SetColor = SetColor
    control:SetColor()
    control.SetIconSize = SetIconSize
    control:SetIconSize(iconSize)

    if iconpickerData.disabled ~= nil then
        control.UpdateDisabled = UpdateDisabled
        control:UpdateDisabled()
    end

    LAM.util.RegisterForRefreshIfNeeded(control)
    LAM.util.RegisterForReloadIfNeeded(control)

    return control
end
