local MAJOR, MINOR = "S2KTools-1.0", 17

local lib, oldMinor = LibStub:NewLibrary(MAJOR, MINOR)
if not lib then return end

local DEFAULT_PAPERDOLL_NUM_TABS = 3

local SIMILAR_ITEMS = {
    [6948]   = { 64488 },   -- Hearthstone
    [64488]  = { 6948 },    -- The Innkeeper's Daughter
    [118922] = { 86569, 75525 },    -- Oralius' Whispering Crystal
    [86569]  = { 118922, 75525 },   -- Crystal of Insanity
    [75525]  = { 118922, 86569 },   -- Alchemist's Flask
}

local SIMILAR_SPELLS = {
    [152280] = { 43265 },   -- Defile
    [108194] = { 47476 },   -- Asphyxiate
}

function unpackByIndex(tab, ...)
    local indexes, res = {...}, {}

    local i, j = 0

    for _, j in ipairs(indexes) do
        i = i + 1
        res[i] = tab[j]
    end

    return unpack(res, 1, i)
end

function splitByRegexp(str, sep, maxParts)
    sep = sep or "%s"

    local res, i = {}, 1

    while str ~= "" do
        if maxParts and i >= maxParts then
            res[i] = str
            return unpack(res)
        end

        local p = { str:match("^(.-)" .. sep .. "(.-)$") }

        if #p < 1 then
            res[i] = str
            return unpack(res)
        end

        res[i], str = p[1], p[#p]
        i = i + 1
    end

    res[i] = str
    return unpack(res)
end

function tableIterator(tab, needUnpack)
    local index

    return function()
        local k, v = next(tab, index)

        if k then
            index = k

            if needUnpack then
                return k, unpack(v)
            end

            return k, v
        end
    end
end

function valuesIterator(tab, needUnpack)
    local index

    return function()
        local k, v = next(tab, index)

        if k then
            index = k

            if needUnpack then
                return unpack(v)
            end

            return v
        end
    end
end

function tableIsEmpty(tab)
    for _ in pairs(tab) do
        return false
    end
    return true
end

function tableLength(tab)
    local count = 0
    for _ in pairs(tab) do
        count = count + 1
    end
    return count
end

function lib:GetMountSpell(mount)
    return S2K_MOUNT_SPELLS[mount]
end

function lib:GetFactionalItem(faction, itemId)
    return S2K_FACTIONAL_ITEMS[faction][itemId]
end

function lib:GetSimilarItems(itemId)
    local ret = SIMILAR_ITEMS[itemId]
    if ret then
        return unpack(ret)
    end
end

function lib:GetSimilarSpells(spellId)
    local ret = SIMILAR_SPELLS[spellId]
    if ret then
        return unpack(ret)
    end
end

function lib:UnitInfoFromGuid(guid)
    local parts = {strsplit('-', guid)}
    local type = parts[1]

    if type == 'Creature' or type == 'Vehicle' then
        local id = tonumber(parts[6])
        return type, id
    end

    return type
end

function lib:InjectPaperDollSidebarTab(name, frame, icon, texCoords)
    self:Fix3rdPartyAddons()

    local tabIndex = #PAPERDOLL_SIDEBARS + 1
    local extraTabs = tabIndex - DEFAULT_PAPERDOLL_NUM_TABS

    PAPERDOLL_SIDEBARS[tabIndex] = { name = name, frame = frame, icon = icon, texCoords = texCoords }

    CreateFrame(
        "Button", "PaperDollSidebarTab" .. tabIndex, PaperDollSidebarTabs,
        "PaperDollSidebarTabTemplate", tabIndex
    )

    self:LineUpPaperDollSidebarTabs()

    if not self.prevSetLevel then
        self.prevSetLevel = PaperDollFrame_SetLevel

        PaperDollFrame_SetLevel = function(...)
            self.prevSetLevel(...)

            local extraTabs = #PAPERDOLL_SIDEBARS - DEFAULT_PAPERDOLL_NUM_TABS

            if CharacterFrameInsetRight:IsVisible() then
                local i
                for i = 1, CharacterLevelText:GetNumPoints() do
                    point, relativeTo, relativePoint, xOffset, yOffset = CharacterLevelText:GetPoint(i)

                    if point == "CENTER" then
                        CharacterLevelText:SetPoint(
                            point, relativeTo, relativePoint,
                            xOffset - (20 + 10 * extraTabs), yOffset
                        )
                    end
                end
            end
        end
    end

    if not self.prevOnUpdate then
        self.prevOnUpdate = PaperDollSidebarTabs:GetScript("OnUpdate") or function() end

        PaperDollSidebarTabs:SetScript("OnUpdate", function(...)
            self.prevOnUpdate(...)
            self:Fix3rdPartyAddons()
        end)
    end
end

function lib:LineUpPaperDollSidebarTabs()
    local extraTabs = #PAPERDOLL_SIDEBARS - DEFAULT_PAPERDOLL_NUM_TABS

    local i, prevTab

    for i = 1, #PAPERDOLL_SIDEBARS do
        local tab = _G["PaperDollSidebarTab" .. i]
        if tab then
            tab:ClearAllPoints()
            tab:SetPoint("BOTTOMRIGHT", (extraTabs < 2 and -30) or (extraTabs < 3 and -10) or 0, 0)

            if prevTab then
                prevTab:ClearAllPoints()
                prevTab:SetPoint("RIGHT", tab, "LEFT", -4, 0)
            end

            prevTab = tab
        end
    end
end

function lib:Fix3rdPartyAddons()
    self:FixZygorGuideViewer()
end

function lib:FixZygorGuideViewer()
    if ZGVCharacterGearFinderButton and not self.fixedZGV then
        local i
        for i = 1, #PAPERDOLL_SIDEBARS do
            if PAPERDOLL_SIDEBARS[i].frame == "ZygorGearFinderFrame" then
                ZGVCharacterGearFinderButton:SetID(i)

                ZGVCharacterGearFinderButton.Icon:SetTexture(PAPERDOLL_SIDEBARS[i].icon)
                ZGVCharacterGearFinderButton.Icon:SetTexCoord(unpack(PAPERDOLL_SIDEBARS[i].texCoords))

                _G["PaperDollSidebarTab" .. i] = ZGVCharacterGearFinderButton
            end
        end

        self:LineUpPaperDollSidebarTabs()
        self.fixedZGV = true
    end
end

local function HookPetJournal()
    local saved = { search = "" }

    hooksecurefunc(C_PetJournal, "ClearSearchFilter", function() saved.search = "" end)
    hooksecurefunc(C_PetJournal, "SetSearchFilter", function(text) saved.search = text end)

    C_PetJournal.GetSearchFilter = function() return saved.search end
end

if not oldMinor then
    HookPetJournal()
end
