-- [[ Chain ]]
function BtWQuestsChainItemPool_HideAndClearAnchors(framePool, frame)
    FramePool_HideAndClearAnchors(framePool, frame)
    
    frame.linePool:ReleaseAll()
    
    frame.IsNextAnim:Stop()
    frame.previousButtons = nil
    frame.status = nil
end

BtWQuestsExpansionItemMixin = {}


BtWQuestsChainItemMixin = {}
function BtWQuestsChainItemMixin:OnLoad()
    self.linePool = CreateFramePool("FRAME", self:GetParent(), "BtWQuestsLineTemplate");

    self.Name:SetText("Quest Name")
    self.Tick:SetShown(false)
    
    self.tooltip = BtWQuestsTooltip
end
function BtWQuestsChainItemMixin:Set(item)
    self.item = item

    self.ForgottenAnim:Stop()
    self.ForgottenAnimQuick:Stop()

    self.Name:SetText(item:GetName())

    local status = item:GetStatus()
    if item:IsBreadcrumb() and item:HasConnections() then
        local completed = false
        local index = 1
        local connection = item:GetConnection(index)
        while connection do
            if not connection:GetSkip() and connection:GetVisible() and connection:GetStatus() ~= nil then
                completed = true
                break
            end

            index = index + 1
            connection = item:GetConnection(index)
        end
        
        if completed then
            status = "complete"
        end
    end

    local tagID = item:GetTagID()
    local difficulty = item:GetDifficulty()
    if tagID and QUEST_TAG_TCOORDS[tagID] then
        self.TagTexture:SetTexCoord(unpack(QUEST_TAG_TCOORDS[tagID]))
        self.TagTexture:Show()

        if difficulty then
            self.TagTexture:SetPoint("BOTTOMRIGHT", -10, 6)
        else
            self.TagTexture:SetPoint("BOTTOMRIGHT", -10, 16)
        end
    else
        self.TagTexture:Hide()
    end

    self.HeroicTexture:SetShown(difficulty == "heroic" or difficulty == "normal" or difficulty == "lfr")
    self.MythicTexture:SetShown(difficulty == "mythic")

    local atlas = item.GetAtlas and item:GetAtlas()
    if atlas ~= nil then
        self.Icon:SetAtlas(atlas)
    end

    if status == "complete" then
        self.ForgottenAnimQuick:Play() -- Just setting the alpha doesnt always work, using a animation with a very short duration seems to solve this
    else
        self.Name:SetAlpha(1)
    end
    
    if status == "active" then
        self.ActiveTexture:Show()
        self.ActiveAnim:Play()
    else
        self.ActiveTexture:Hide()
    end
    
    self.Tick:SetShown(status == "complete")

    self:SetShown(item:GetVisible())
    self.status = status
end
function BtWQuestsChainItemMixin:Update(item)
    local status = item:GetStatus()
    if item:IsBreadcrumb() and item:HasConnections() then
        local completed = false
        local index = 1
        local connection = item:GetConnection(index)
        while connection do
            if not connection:GetSkip() and connection:GetVisible() and connection:GetStatus() ~= nil then
                completed = true
                break
            end

            index = index + 1
            connection = item:GetConnection(index)
        end
        
        if completed then
            status = "complete"
        end
    end

    self.ForgottenAnim:Stop()
    self.ForgottenAnimQuick:Stop()

    self.Name:SetText(item:GetName())
    
    if self.status ~= status then
        if status == "complete" then
            self.ForgottenAnim:Play()
        end
    
        if status == "active" then
            self.ActiveTexture:Show()
            self.ActiveAnim:Play()
        else
            self.ActiveTexture:Hide()
        end
    end
    
    self.Tick:SetShown(status == "complete")
    
    self:SetShown(item:GetVisible())
    self.status = status
end
function BtWQuestsChainItemMixin:SetChainView(value)
    self.chainView = value
end
function BtWQuestsChainItemMixin:GetChainView()
    return self.chainView
end
function BtWQuestsChainItemMixin:SetTooltip(value)
    self.tooltip = value
end
function BtWQuestsChainItemMixin:GetTooltip()
    return self.tooltip
end
function BtWQuestsChainItemMixin:OnClick()
    if self.item then
        return self.item:OnClick(self.item, self, self:GetChainView(), self:GetTooltip())
    end
end
function BtWQuestsChainItemMixin:OnEnter()
    if self.item then
        return self.item:OnEnter(self.item, self, self:GetChainView(), self:GetTooltip())
    end
end
function BtWQuestsChainItemMixin:OnLeave()
    if self.item then
        return self.item:OnLeave(self.item, self, self:GetChainView(), self:GetTooltip())
    end
end

BtWQuestsCategoryHeaderMixin = {}
function BtWQuestsCategoryHeaderMixin:Set(item)
    self.item = item

    self.Name:SetText(item:GetName())
    
    self.id = item:GetID();
end

BtWQuestsCategoryItemMixin = {}
function BtWQuestsCategoryItemMixin:Set(item)
    self.item = item

    self.Name:SetText(item:GetName())

    self.Background:SetTexture(item:GetButtonImage())
    self.Acive:SetShown(item:IsActive())
    self.Tick:SetShown(item:IsCompleted())
    self.Major:SetShown(item:IsMajor())
    
    self.id = item:GetID();
end
function BtWQuestsCategoryItemMixin:OnClick()
    return self.item:OnClick(self.item, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip)
end
function BtWQuestsCategoryItemMixin:OnEnter()
    return self.item:OnEnter(self.item, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip)
end
function BtWQuestsCategoryItemMixin:OnLeave()
    return self.item:OnLeave(self.item, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip)
end
function BtWQuestsCategoryItemMixin:OnMouseUp(button)
    if button == "RightButton" then
        local character = self.item.character
        if self.item:GetType() == "chain" then
            character:ToggleChainIgnored(self.item:GetID())
            self.Acive:SetShown(self.item:IsActive())
        elseif self.item:GetType() == "category" then
            character:ToggleCategoryIgnored(self.item:GetID())
        end
        BtWQuestsFrame:Refresh()
    end
end

BtWQuestsCategoryListItemMixin = Mixin({}, BtWQuestsCategoryItemMixin)
function BtWQuestsCategoryListItemMixin:Set(item)
    self.item = item

    local subtext = item:GetSubtext()

    self.Name:SetText(item:GetName())
    self.Subtext:SetText(subtext)

    self.Name:ClearAllPoints()
    if subtext == nil then
        self.Name:SetPoint("LEFT", 60, 0)
    else
        self.Name:SetPoint("TOPLEFT", 60, -13)
    end

    local texture, left, right, top, bottom = item:GetListImage()
    if texture ~= nil then
        self.Background:SetTexture(texture)
        self.Background:SetTexCoord(left, right, top, bottom)
    else
        self.Background:SetTexture("Interface\\Addons\\BtWQuests\\UI-CategoryButton")
        self.Background:SetTexCoord(0.0, 0.7353515625, 0.3515625, 0.46875)
    end
    self.Acive:SetShown(item:IsActive())
    self.Tick:SetShown(item:IsCompleted())
    self.Major:SetShown(item:IsMajor())
    
    self.id = item:GetID();
end
function BtWQuestsCategoryListItemMixin:OnEnter()
    BtWQuestsCategoryItemMixin.OnEnter(self)
    self.Ignore.texture:SetAlpha(0.75)
end
function BtWQuestsCategoryListItemMixin:OnLeave()
    BtWQuestsCategoryItemMixin.OnLeave(self)
    self.Ignore.texture:SetAlpha(0.0)
end
function BtWQuestsCategoryListItemMixin:OnMouseUp(button)
    if button == "RightButton" then
        BtWQuestsFrame:ZoomOut()
    end
end

BtWQuestsChainViewItemMixin = {}
function BtWQuestsChainViewItemMixin:OnLoad()
    BtWQuestsChainItemMixin.OnLoad(self)
    self:RegisterForDrag("LeftButton")
end
function BtWQuestsChainViewItemMixin:GetChainView()
    return self:GetParent():GetParent()
end
function BtWQuestsChainViewItemMixin:GetTooltip()
    return self:GetChainView():GetTooltip()
end
function BtWQuestsChainViewItemMixin:OnDragStart()
    self:GetChainView():OnDragStart()
end
function BtWQuestsChainViewItemMixin:OnDragStop()
    self:GetChainView():OnDragStop()
end

BtWQuestsChainViewMixin = {}
function BtWQuestsChainViewMixin:OnLoad()
    ScrollFrame_OnLoad(self)
    self.itemPool = CreateFramePool("BUTTON", self.Child, "BtWQuestsChainViewItemTemplate", BtWQuestsChainItemPool_HideAndClearAnchors);
    self:RegisterForDrag("LeftButton")
end
function BtWQuestsChainViewMixin:OnDragStart()
    self.scrollX, self.scrollY = self:GetHorizontalScroll(), self:GetVerticalScroll()
    self.mouseX, self.mouseY = GetCursorPosition()
    
    local scale = self:GetScrollChild():GetEffectiveScale()
    self.mouseX, self.mouseY = self.mouseX / scale, self.mouseY / scale

    self:SetScript("OnUpdate", BtWQuestsChainViewMixin.OnDrag)
end
function BtWQuestsChainViewMixin:OnDragStop()
    self:SetScript("OnUpdate", nil)
end
function BtWQuestsChainViewMixin:OnDrag()
    local mouseX, mouseY = GetCursorPosition()
    local scale = self:GetEffectiveScale()
    mouseX, mouseY = mouseX / scale, mouseY / scale
    
    local maxXScroll, maxYScroll = self:GetHorizontalScrollRange(), self:GetVerticalScrollRange()
    
    mouseX = min(max(mouseX - self.mouseX + self.scrollX, 0), maxXScroll)
    mouseY = min(max(mouseY - self.mouseY + self.scrollY, 0), maxYScroll)
    
    self:SetHorizontalScroll(mouseX)
    self:SetVerticalScroll(mouseY)
end
function BtWQuestsChainViewMixin:GetZoom()
    return 1
    -- return self:GetScrollChild():GetScale()
end
function BtWQuestsChainViewMixin:SetZoom(value)
    -- return self:GetScrollChild():SetScale(value)
end
function BtWQuestsChainViewMixin:SetCharacter(name, realm)
    if type(name) == "string" then
        if realm ~= nil then
            name = name .. "-" .. realm
        end

        self.Character = BtWQuestsCharacters:GetCharacter(name)
    else
        self.Character = name
    end
end
function BtWQuestsChainViewMixin:GetCharacter()
    return self.Character
end
function BtWQuestsChainViewMixin:GetTooltip()
    return BtWQuestsTooltip
end
function BtWQuestsChainViewMixin:SelectFromLink(...)
    -- return self:GetParent():GetParent():SelectFromLink(...)
end
function BtWQuestsChainViewMixin:SetChain(chainID, scrollTo, zoom)
    self.chainID = chainID

    self.itemPool:ReleaseAll()
    self.ItemButtons = {}

    self.scrollTo = scrollTo
    self.scrollToButton = nil
    self.scrollToButtonAside = nil

    self.lowestButton = nil
    self.lowestY = nil

    if zoom ~= nil then
        self:SetZoom(zoom)
    end

    local numItems = self:AddButtons(chainID, 0, 0)

    if self.lowestButton ~= nil then
        self:GetScrollChild().Bottom:SetPoint("TOP", 0, select(5, self.lowestButton:GetPoint("TOP")) - 23 - (self:GetHeight()/2))
    end

    self:UpdateScrollChildRect()
    if type(scrollTo) == "table" and scrollTo.type == "coords" then
        local scale = self:GetZoom()
        -- self:SetHorizontalScroll(scrollTo.x / scale)
        self:SetVerticalScroll(scrollTo.y / scale)
    elseif scrollTo ~= false then
        if self.scrollToButton == nil then
            self.scrollToButton = self.scrollToButtonAside
        end
        
        -- if self.scrollToButton == nil then
        --     local buttons = self.ItemButtons[chainID]
        --     local index = 1
        --     while buttons[index] and not buttons[index]:IsShown() do
        --         index = index + 1
        --     end
            
        --     self.scrollToButton = buttons[index]
        -- end
        
        if self.scrollToButton then
            local scale = self:GetZoom()
            local x, y = select(4, self.scrollToButton:GetPoint("TOP"))
            
            -- self:SetHorizontalScroll(x - (self:GetWidth() / scale) / 2)
            self:SetVerticalScroll(0 - y - (self:GetHeight() / scale) / 2 + 24)
        else
            self:SetVerticalScroll(0)
        end
    end
end
function BtWQuestsChainViewMixin:AddButtons(chainID, xOffset, yOffset, asideOverride)
    local character = self:GetCharacter()
    assert(character ~= nil, "Must set a character before setting a chain")

    self.ItemButtons[chainID] = {}
    local buttons = self.ItemButtons[chainID]

    local chain = BtWQuestsDatabase:GetChain(chainID, character)
    
    local previousX, previousY = nil, 0

    local index = 1
    local item = chain:GetItem(index)
    while item do
        if not item:GetSkip() then
            local x = item:GetX()
            local y = item:GetY()
            
            if x == nil then
                if y == nil then
                    if previousX == nil then
                        x = 0
                        y = 0

                        while x >= 8 do
                            x = x - 8
                            y = y + 1
                        end
                    else
                        x = previousX + 2
                        y = previousY

                        if x > 6 then
                            x = x - 8
                            y = y + 1
                        end
                    end
                else
                    x = previousX
                    y = y + yOffset
                end
            elseif y == nil then
                x = x + xOffset
                if previousX ~= nil and x <= previousX then
                    y = previousY + 1
                else
                    y = previousY
                end
            else
                x = x + xOffset
                y = y + yOffset
            end
            
            previousX = x
            previousY = y

            if item:IsEmbed() then
                if item:GetType() == "chain" then
                    self:AddButtons(item:GetID(), x or 0, y or 0, item:IsAside())
                end
            else
                local itemButton = buttons[index] or self.itemPool:Acquire();
                buttons[index] = itemButton

                itemButton:Set(item)

                -- Check if the item should be next
                itemButton.IsNextAnim:Stop()
                if itemButton.status == nil and itemButton.previousButtons ~= nil then
                    local available = true
                    for i,previous in ipairs(itemButton.previousButtons) do
                        if previous.status ~= "complete" then
                            available = false
                            break
                        end
                    end

                    if available then
                        itemButton.ActiveTexture:Show()
                        itemButton.IsNextAnim:Play()
                    end

                    itemButton.previousButtons = nil
                end

                -- local frameX = (item:GetX()) * BTWQUESTS_CHAIN_ITEM_WIDTH
                -- local frameY = (item:GetY()) * BTWQUESTS_CHAIN_ITEM_HEIGHT
            
                itemButton:SetPoint("TOP", 0, -(y * 80) - (self:GetHeight()/2) + 24);
                itemButton:SetPoint("LEFT", 95 * x + 12, 0);
                -- itemButton:SetPoint("CENTER", self:GetScrollChild(), "TOPLEFT", frameX, -frameY)

                local connectionIndex = 1
                local connectionItem = item:GetConnection(connectionIndex)
                while connectionItem do
                    if not connectionItem:GetSkip() then
                        local connectionButton = buttons[connectionItem:GetIndex()] or self.itemPool:Acquire();
                        buttons[connectionItem:GetIndex()] = connectionButton

                        -- Storing this so the connected items can check if they should be next
                        if connectionButton.previousButtons == nil then
                            connectionButton.previousButtons = {}
                        end
                        table.insert(connectionButton.previousButtons, itemButton)
                        
                        local lineContainer = itemButton.linePool:Acquire();
                        
                        lineContainer.Background:SetStartPoint("CENTER", itemButton);
                        lineContainer.Background:SetEndPoint("CENTER", connectionButton);
                        
                        lineContainer.Active:SetStartPoint("CENTER", itemButton);
                        lineContainer.Active:SetEndPoint("CENTER", connectionButton);
                        
                        lineContainer.Complete:SetStartPoint("CENTER", itemButton);
                        lineContainer.Complete:SetEndPoint("CENTER", connectionButton);
                        
                        -- lineContainer:SetAlpha(1)
                        
                        lineContainer.PulseAlpha:Stop()
                            
                        lineContainer.Active:Hide()
                        lineContainer.Complete:Hide()
                        
                        if itemButton.status == "complete" then
                            lineContainer.Complete:Show()
                        elseif itemButton.status == "active" then
                            -- lineContainer.Active:Show()
                        end
                        
                        lineContainer.connection = connectionButton
                        lineContainer:SetShown(itemButton:IsShown() and connectionItem:GetVisible());
                    end
                    
                    connectionIndex = connectionIndex + 1
                    connectionItem = item:GetConnection(connectionIndex)
                end

                if item:GetVisible() then
                    if self.lowestY == nil or y > self.lowestY then
                        self.lowestY = y
                        self.lowestButton = itemButton
                    end

                    if self.scrollTo == nil and itemButton.status ~= "complete" then
                        if asideOverride or item:IsAside() then
                            if self.scrollToButtonAside == nil then
                                self.scrollToButtonAside = itemButton
                            end
                        elseif self.scrollToButton == nil then
                            self.scrollToButton = itemButton
                        end
                    elseif type(self.scrollTo) == "number" and index == self.scrollTo then
                        self.scrollToButton = itemButton
                    elseif type(self.scrollTo) == "table" and item:EqualsItem(self.scrollTo) then
                        self.scrollToButton = itemButton
                    end
                end
            end
        end

        index = index + 1
        item = chain:GetItem(index)
    end

    return chain:GetNumItems()
end
function BtWQuestsChainViewMixin:Update()
    self:UpdateChain(self.chainID)
end
function BtWQuestsChainViewMixin:UpdateChain(chainID)
    local character = self:GetCharacter()

    local buttons = self.ItemButtons[chainID]
    assert(buttons ~= nil, "Cannot update a chain that was never added")

    local chain = BtWQuestsDatabase:GetChain(chainID, character)

    local index = 1
    local item = chain:GetItem(index)
    while item do
        if not item:GetSkip() then
            if item:IsEmbed() then
                if item:GetType() == "chain" then
                    self:UpdateChain(item:GetID())
                end
            else
                local itemButton = buttons[index]
                assert(itemButton, "Chain item was never added in the first place")
                
                local status = itemButton.status

                itemButton:Update(item)

                -- Check if the item should be next
                itemButton.IsNextAnim:Stop()
                if itemButton.status == nil and itemButton.previousButtons ~= nil then
                    local available = true
                    for i,previous in ipairs(itemButton.previousButtons) do
                        if previous.status ~= "complete" then
                            available = false
                            break
                        end
                    end

                    if available then
                        itemButton.ActiveTexture:Show()
                        itemButton.IsNextAnim:Play()
                    end

                    itemButton.previousButtons = nil
                end

                local connectionIndex = 1
                local connectionItem = item:GetConnection(connectionIndex)
                while connectionItem do
                    if not connectionItem:GetSkip() then
                        local connectionButton = buttons[connectionItem:GetIndex()]

                        -- Storing this so the connected items can check if they should be next
                        if connectionButton.previousButtons == nil then
                            connectionButton.previousButtons = {}
                        end
                        table.insert(connectionButton.previousButtons, itemButton)
                    end
                    
                    connectionIndex = connectionIndex + 1
                    connectionItem = item:GetConnection(connectionIndex)
                end
                
                for lineContainer in itemButton.linePool:EnumerateActive() do
                    if itemButton.status == "complete" and status ~= "complete" then
                        lineContainer.DefaultToCompleteAnim:Play()
                    end
                    lineContainer:SetShown(itemButton:IsShown() and lineContainer.connection:IsShown())
                end
            end
    end

        index = index + 1
        item = chain:GetItem(index)
    end
    
    return chain:GetNumItems()
end

-- [[ Expansions View ]]
BtWQuestsExpansionButtonMixin = {}
function BtWQuestsExpansionButtonMixin:OnClick()
    return self.item:OnClick(self.item, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip)
end
function BtWQuestsExpansionButtonMixin:Set(item)
    self.item = item
    
    self:SetText(item:GetName())
    self.Subtext:SetText(item:GetSubtext(true))
    self.Active:SetShown(item:IsActive())
end

BtWQuestsExpansionMixin = {}
function BtWQuestsExpansionMixin:OnLoad()
    self.buttonPool = CreateFramePool("BUTTON", self, "BtWQuestsExpansionButtonTemplate")
end
function BtWQuestsExpansionMixin:Set(item)
    self.item = item

    self.Name:SetText(item:GetName())

    local texture, left, right, top, bottom = item:GetImage()
    if texture ~= nil then
        self.Background:SetTexture(texture)
        self.Background:SetTexCoord(left, right, top, bottom)
    else
        self.Background:SetTexture("Interface\\Addons\\BtWQuests\\UI-Expansion")
        self.Background:SetTexCoord(0.43359375, 0.66015625, 0.0, 0.8125)
    end

    self.buttonPool:ReleaseAll()

    local items = item:GetMajorItems()
    local previous = self.ViewAll
    for i=#items,1,-1 do
        local button = self.buttonPool:Acquire()
        button:Set(items[i])
        button:SetPoint("BOTTOM", previous, "TOP", 0, 5)
        button:Show()
        previous = button
    end
end

-- [[ Navbar ]]
BtWQuestsNavBarMixin = {}
function BtWQuestsNavBarMixin:OnShow()
    if not self.Initialized then
        local homeData = {
            name = HOME,
            OnClick = BtWQuestsNavBarButtonMixin.OnClick
        }
        self.dropDown = CreateFrame("Frame", nil, self, "BtWQuestsNavBarDropDownTemplate")
        NavBar_Initialize(self, "BtWQuestsNavBarButtonTemplate", homeData, self.home, self.overflow)
        self.overflow:SetScript("OnClick", function (self, button)
            local dropDown = self:GetParent().dropDown
            if ( dropDown.buttonOwner ~= self ) then
                CloseDropDownMenus();
            end
            dropDown.buttonOwner = self;
            dropDown:Toggle(self, 20, 3)
        end)
        self.Initialized = true
    end
end
function BtWQuestsNavBarMixin:EnableExpansions(value)
    self.enableExpansions = value
end
function BtWQuestsNavBarMixin:Reset()
    NavBar_Reset(self)
end
function BtWQuestsNavBarMixin:SetExpansion(id)
    local character = self:GetParent():GetCharacter()

    NavBar_Reset(self)
    self:AddButtons("expansion", id, character)
end
function BtWQuestsNavBarMixin:SetCategory(id)
    local character = self:GetParent():GetCharacter()

    NavBar_Reset(self)
    self:AddButtons("category", id, character)
end
function BtWQuestsNavBarMixin:SetChain(id)
    local character = self:GetParent():GetCharacter()

    NavBar_Reset(self)
    self:AddButtons("chain", id, character)
end
function BtWQuestsNavBarMixin:AddButtons(type, id, character)
    local id, name, expansion, parent, _ = tonumber(id)
    if type == "expansion" then
        if not self.enableExpansions then
            return
        end

        name = BtWQuestsDatabase:GetExpansionByID(id, character)
    elseif type == "category" then
        _, name, _, expansion, parent = BtWQuestsDatabase:GetCategoryByID(id, character)
    elseif type == "chain" then
        _, name, _, expansion, parent = BtWQuestsDatabase:GetChainByID(id, character)
    end

    if parent then
        self:AddButtons("category", parent, character)
        
        parent = {
            type = "category",
            id = parent,
        }
    elseif expansion then
        self:AddButtons("expansion", expansion, character)
        
        parent = {
            type = "expansion",
            id = expansion,
        }
    end

    self:AddButton(type, id, name, parent, character)
end
function BtWQuestsNavBarMixin:AddButton(type, id, name, parent)
    local buttonData = {
        type = type,
        id = tonumber(id),
        name = name,
        parent = parent,
        OnClick = BtWQuestsNavBarButtonMixin.OnClick,
        listFunc = BtWQuestsNavBarButtonMixin.GetList,
    }
    NavBar_AddButton(self, buttonData);
end
function BtWQuestsNavBarMixin:GoToItem(item)
    local BtWQuestsFrame = self:GetParent()

    if item.type == nil then
        if self.enableExpansions then
            BtWQuestsFrame:SelectExpansion()
        else
            BtWQuestsFrame:SelectExpansion(item.id)
        end
    elseif item.type == "expansion" then
        BtWQuestsFrame:SelectExpansion(item.id)
    elseif item.type == "category" then
        BtWQuestsFrame:SelectCategory(item.id)
    elseif item.type == "chain" then
        BtWQuestsFrame:SelectChain(item.id)
    end
end
function BtWQuestsNavBarMixin:GetCharacter()
    return self:GetParent():GetCharacter()
end

BtWQuestsNavBarButtonMixin = {}
function BtWQuestsNavBarButtonMixin:GetList()
    local character = self:GetParent():GetCharacter()

    local item = self.data.parent

    local sisters = {}
    if item == nil then
        for i=0,LE_EXPANSION_LEVEL_CURRENT do
            if BtWQuestsDatabase:HasExpansion(i) then
                table.insert(sisters, {
                    id = {
                        type = "expansion",
                        id = i
                    },
                    text = BtWQuestsDatabase:GetExpansionByID(i),
                    func = function(button, item)
                        self:GetParent():GoToItem(item)
                    end,
                })
            end
        end
    elseif item.type == "expansion" then
        local items = BtWQuestsDatabase:GetExpansion(item.id, character):GetItemList(true, false, false)
        for _,item in ipairs(items) do
            table.insert(sisters, {
                id = {
                    type = item:GetType(),
                    id = item:GetID()
                },
                text = item:GetName(),
                func = function(button, item)
                    self:GetParent():GoToItem(item)
                end,
            })
        end
    elseif item.type == "category" then
        local items = BtWQuestsDatabase:GetCategory(item.id, character):GetItemList(true, false, false)
        for _,item in ipairs(items) do
            table.insert(sisters, {
                id = {
                    type = item:GetType(),
                    id = item:GetID()
                },
                text = item:GetName(),
                func = function(button, item)
                    self:GetParent():GoToItem(item)
                end,
            })
        end
    elseif item.type == "chain" then
    end
    return sisters
end
function BtWQuestsNavBarButtonMixin:OnClick()
    self:GetParent():GoToItem(self.data)
end

BtWQuestsNavBarDropDownMenuMixin = {}
function BtWQuestsNavBarDropDownMenuMixin:OnLoad()
	self.displayMode = "MENU"
end
function BtWQuestsNavBarDropDownMenuMixin:Initialize()
	local navButton = self.buttonOwner;
	if not navButton or not navButton.listFunc then
		return;
	end

	local info = self:CreateInfo();
	info.func = NavBar_DropDown_Click;
	info.owner = navButton;
	info.notCheckable = true;
	local list = navButton:listFunc();
	if ( list ) then
        for i, entry in ipairs(list) do
			info.text = entry.text;
			info.arg1 = entry.id;
			info.arg2 = entry.func;
			self:AddButton(info);
		end
	end
end

-- [[ DropDown Menu ]]
-- This is a simplified replacement for the built in drop down menus to prevent taint
-- Most of this is a copy and paste from the built in system
BtWQuestsDropDownMenuMixin = {}
function BtWQuestsDropDownMenuMixin:SetDropDownWidth(width, padding)
	-- self.Middle:SetWidth(width)
    -- self:SetWidth(self.Left:GetWidth() + self.Right:GetWidth() + self.Middle:GetWidth())
    
	self.Middle:SetWidth(width);
	local defaultPadding = 25;
	if ( padding ) then
		self:SetWidth(width + padding);
	else
		self:SetWidth(width + defaultPadding + defaultPadding);
	end
	if ( padding ) then
		self.Text:SetWidth(width);
	else
		self.Text:SetWidth(width - defaultPadding);
	end
	-- frame.noResize = 1;
end
function BtWQuestsDropDownMenuMixin:SetText(text)
	self.Text:SetText(text)
end
function BtWQuestsDropDownMenuMixin:GetText()
	return self.Text:GetText()
end
function BtWQuestsDropDownMenuMixin:JustifyText(justification)
	local text = self.Text
	text:ClearAllPoints()
	if justification == "LEFT" then
		text:SetPoint("LEFT", self.Left, "LEFT", 27, 2)
		text:SetJustifyH("LEFT")
	elseif justification == "RIGHT" then
		text:SetPoint("RIGHT", self.Right, "RIGHT", -43, 2)
		text:SetJustifyH("RIGHT")
	elseif justification == "CENTER" then
		text:SetPoint("CENTER", self.Middle, "CENTER", -5, 2)
		text:SetJustifyH("CENTER")
	end
end
function BtWQuestsDropDownMenuMixin:GetListFrame()
    local list = self.list

    if list == nil then
		list = CreateFrame("Button", nil, nil, "BtWQuestsDropDownListTemplate")
		list:SetFrameStrata("FULLSCREEN_DIALOG")
		list:SetToplevel(true)
		list:Hide()
		list:SetWidth(180)
        list:SetHeight(10)
        self.list = list
        self.buttonPool = CreateFramePool("BUTTON", list, "BtWQuestsDropDownButtonTemplate")
        
        local menu = self
        hooksecurefunc("ToggleDropDownMenu", function ()
            menu:Close()
        end)
        hooksecurefunc("CloseDropDownMenus", function ()
            menu:Close()
        end)
    end

    return list
end
function BtWQuestsDropDownMenuMixin:CreateInfo()
    local prefix = self.prefix or "BtWQuestsDropDown"
    local info = _G[prefix .. 'Info']
    if info == nil then
        _G[prefix .. 'Info'] = {}
        return _G[prefix .. 'Info']
    end

    table.wipe(info)
    return info
end
function BtWQuestsDropDownMenuMixin:GetButtonWidth(button)
    local minWidth = button.minWidth or 0;
    if button.customFrame and button.customFrame:IsShown() then
        return math.max(minWidth, button.customFrame:GetPreferredEntryWidth());
    end

    if not button:IsShown() then
        return 0;
    end

    local width;
    local icon = button.Icon;
    local normalText = button.NormalText

    if ( button.iconOnly and icon ) then
        width = icon:GetWidth();
    elseif ( normalText and normalText:GetText() ) then
        width = normalText:GetWidth() + 40;

        if ( button.icon ) then
            -- Add padding for the icon
            width = width + 10;
        end
    else
        return minWidth;
    end

    -- Add padding if has and expand arrow or color swatch
    if ( button.hasArrow or button.hasColorSwatch ) then
        width = width + 10;
    end
    if ( button.notCheckable ) then
        width = width - 30;
    end
    if ( button.padding ) then
        width = width + button.padding;
    end

    return math.max(minWidth, width);
end
function BtWQuestsDropDownMenuMixin:AddButton(info)
    local listFrame = self:GetListFrame()
    local button = self.buttonPool:Acquire()
    local index = self.buttonPool:GetNumActive()

	local normalText = button.NormalText
	local icon = button.Icon
	-- This button is used to capture the mouse OnEnter/OnLeave events if the dropdown button is disabled, since a disabled button doesn't receive any events
	-- This is used specifically for drop down menu time outs
    -- local invisibleButton = button.InvisibleButton
    
    button:SetWidth(listFrame:GetWidth() - 30)

	-- Default settings
	button:SetDisabledFontObject(GameFontDisableSmallLeft);
	-- invisibleButton:Hide();
	button:Enable();

	-- If not clickable then disable the button and set it white
	if ( info.notClickable ) then
		info.disabled = true;
		button:SetDisabledFontObject(GameFontHighlightSmallLeft);
	end

	-- Set the text color and disable it if its a title
	if ( info.isTitle ) then
		info.disabled = true;
		button:SetDisabledFontObject(GameFontNormalSmallLeft);
	end

	-- Disable the button if disabled and turn off the color code
	if ( info.disabled ) then
		button:Disable();
		-- invisibleButton:Show();
		info.colorCode = nil;
	end

	-- If there is a color for a disabled line, set it
	if( info.disablecolor ) then
		info.colorCode = info.disablecolor;
	end

	-- Configure button
	if ( info.text ) then
		-- look for inline color code this is only if the button is enabled
		if ( info.colorCode ) then
			button:SetText(info.colorCode..info.text.."|r");
		else
			button:SetText(info.text);
		end

		-- Set icon
		if ( info.icon or info.mouseOverIcon ) then
			icon:SetSize(16,16);
			icon:SetTexture(info.icon);
			icon:ClearAllPoints();
			icon:SetPoint("RIGHT");

			if ( info.tCoordLeft ) then
				icon:SetTexCoord(info.tCoordLeft, info.tCoordRight, info.tCoordTop, info.tCoordBottom);
			else
				icon:SetTexCoord(0, 1, 0, 1);
			end
			icon:Show();
		else
			icon:Hide();
		end

		-- Check to see if there is a replacement font
		if ( info.fontObject ) then
			button:SetNormalFontObject(info.fontObject);
			button:SetHighlightFontObject(info.fontObject);
		else
			button:SetNormalFontObject(GameFontHighlightSmallLeft);
			button:SetHighlightFontObject(GameFontHighlightSmallLeft);
		end
	else
		button:SetText("");
		icon:Hide();
	end

	button.iconOnly = nil;
	button.icon = nil;
	button.iconInfo = nil;

	if (info.iconInfo) then
		icon.tFitDropDownSizeX = info.iconInfo.tFitDropDownSizeX;
	else
		icon.tFitDropDownSizeX = nil;
	end
	if (info.iconOnly and info.icon) then
		button.iconOnly = true;
		button.icon = info.icon;
		button.iconInfo = info.iconInfo;

		UIDropDownMenu_SetIconImage(icon, info.icon, info.iconInfo);
		icon:ClearAllPoints();
		icon:SetPoint("LEFT");
	end

	-- Pass through attributes
	button.func = info.func;
	button.owner = info.owner;
	button.hasOpacity = info.hasOpacity;
	button.opacity = info.opacity;
	button.opacityFunc = info.opacityFunc;
	button.cancelFunc = info.cancelFunc;
	button.swatchFunc = info.swatchFunc;
	button.keepShownOnClick = info.keepShownOnClick;
	button.tooltipTitle = info.tooltipTitle;
	button.tooltipText = info.tooltipText;
	button.tooltipInstruction = info.tooltipInstruction;
	button.tooltipWarning = info.tooltipWarning;
	button.arg1 = info.arg1;
	button.arg2 = info.arg2;
	button.hasArrow = info.hasArrow;
	button.hasColorSwatch = info.hasColorSwatch;
	button.notCheckable = info.notCheckable;
	button.menuList = info.menuList;
	button.tooltipWhileDisabled = info.tooltipWhileDisabled;
	button.noTooltipWhileEnabled = info.noTooltipWhileEnabled;
	button.tooltipOnButton = info.tooltipOnButton;
	button.noClickSound = info.noClickSound;
	button.padding = info.padding;
	button.icon = info.icon;
    button.mouseOverIcon = info.mouseOverIcon;
    button.deleteFunc = info.deleteFunc
    button.hasDelete = info.hasDelete

	if ( info.value ) then
		button.value = info.value;
	elseif ( info.text ) then
		button.value = info.text;
	else
		button.value = nil;
	end

	-- If not checkable move everything over to the left to fill in the gap where the check would be
	local xPos = 5;
	local yPos = -((index - 1) * UIDROPDOWNMENU_BUTTON_HEIGHT) - UIDROPDOWNMENU_BORDER_HEIGHT;
	local displayInfo = normalText;
	if (info.iconOnly) then
		displayInfo = icon;
	end

	displayInfo:ClearAllPoints();
	if ( info.notCheckable ) then
		if ( info.justifyH and info.justifyH == "CENTER" ) then
			displayInfo:SetPoint("CENTER", button, "CENTER", -7, 0);
		else
			displayInfo:SetPoint("LEFT", button, "LEFT", 0, 0);
		end
		xPos = xPos + 10;

	else
		xPos = xPos + 12;
		displayInfo:SetPoint("LEFT", button, "LEFT", 20, 0);
	end

	if ( info.leftPadding ) then
		xPos = xPos + info.leftPadding;
	end
	button:SetPoint("TOPLEFT", button:GetParent(), "TOPLEFT", xPos, yPos)

	if not info.notCheckable then
		local check = button.Check
		local uncheck = button.UnCheck
		if ( info.disabled ) then
			check:SetDesaturated(true);
			check:SetAlpha(0.5);
			uncheck:SetDesaturated(true);
			uncheck:SetAlpha(0.5);
		else
			check:SetDesaturated(false);
			check:SetAlpha(1);
			uncheck:SetDesaturated(false);
			uncheck:SetAlpha(1);
		end
		
		if info.customCheckIconAtlas or info.customCheckIconTexture then
			check:SetTexCoord(0, 1, 0, 1);
			uncheck:SetTexCoord(0, 1, 0, 1);
			
			if info.customCheckIconAtlas then
				check:SetAtlas(info.customCheckIconAtlas);
				uncheck:SetAtlas(info.customUncheckIconAtlas or info.customCheckIconAtlas);
			else
				check:SetTexture(info.customCheckIconTexture);
				uncheck:SetTexture(info.customUncheckIconTexture or info.customCheckIconTexture);
			end
		elseif info.isNotRadio then
			check:SetTexCoord(0.0, 0.5, 0.0, 0.5);
			check:SetTexture("Interface\\Common\\UI-DropDownRadioChecks");
			uncheck:SetTexCoord(0.5, 1.0, 0.0, 0.5);
			uncheck:SetTexture("Interface\\Common\\UI-DropDownRadioChecks");
		else
			check:SetTexCoord(0.0, 0.5, 0.5, 1.0);
			check:SetTexture("Interface\\Common\\UI-DropDownRadioChecks");
			uncheck:SetTexCoord(0.5, 1.0, 0.5, 1.0);
			uncheck:SetTexture("Interface\\Common\\UI-DropDownRadioChecks");
		end

		-- Checked can be a function now
		local checked = info.checked;
		if ( type(checked) == "function" ) then
			checked = checked(button);
		end

		-- Show the check if checked
		if ( checked ) then
			button:LockHighlight();
			check:Show();
			uncheck:Hide();
		else
			button:UnlockHighlight();
			check:Hide();
			uncheck:Show();
		end
	else
		button.Check:Hide();
		button.UnCheck:Hide();
	end
	button.checked = info.checked;

	-- If has a colorswatch, show it and vertex color it
	local colorSwatch = button.ColorSwatch
	if ( info.hasColorSwatch ) then
		button.ColorSwatch.NormalTexture:SetVertexColor(info.r, info.g, info.b);
		button.r = info.r;
		button.g = info.g;
		button.b = info.b;
		colorSwatch:Show();
	else
		colorSwatch:Hide();
    end
    
	local deleteButton = button.DeleteButton
    if info.hasDelete then
        deleteButton:Show()
    else
        deleteButton:Hide()
    end

	UIDropDownMenu_CheckAddCustomFrame(listFrame, button, info);

	button:SetShown(button.customFrame == nil);

	button.minWidth = info.minWidth;

	width = max(self:GetButtonWidth(button), info.minWidth or 0);
	--Set maximum button width
	if ( width > listFrame.maxWidth ) then
		listFrame.maxWidth = width;
    end

    -- Set the height of the listframe
	listFrame:SetHeight((index * UIDROPDOWNMENU_BUTTON_HEIGHT) + (UIDROPDOWNMENU_BORDER_HEIGHT * 2));
    
    button:Show()
end
function BtWQuestsDropDownMenuMixin:Toggle(anchorName, xOffset, yOffset)
    local list = self:GetListFrame()
    if list:IsShown() and self.anchorName == anchorName then
        self:Close()
    else
        self.anchorName = anchorName
        self:Open(anchorName, xOffset, yOffset)
    end
end
function BtWQuestsDropDownMenuMixin:Open(anchorName, xOffset, yOffset)
    CloseDropDownMenus()

    local list = self:GetListFrame()
    -- Set the dropdownframe scale
    local uiScale;
    local uiParentScale = UIParent:GetScale();
    if GetCVar("useUIScale") == "1" then
        uiScale = tonumber(GetCVar("uiscale"))
        if uiParentScale < uiScale then
            uiScale = uiParentScale
        end
    else
        uiScale = uiParentScale
    end
    list:SetScale(uiScale)

    list:ClearAllPoints()
    local point, relativeTo, relativePoint
    
    if ( not anchorName ) then
        -- See if the anchor was set manually using setanchor
        if ( self.xOffset ) then
            xOffset = self.xOffset;
        end
        if ( self.yOffset ) then
            yOffset = self.yOffset;
        end
        if ( self.point ) then
            point = self.point;
        end
        if ( self.relativeTo ) then
            relativeTo = self.relativeTo;
        else
            relativeTo = self.Left
        end
        if ( self.relativePoint ) then
            relativePoint = self.relativePoint;
        end
    elseif ( anchorName == "cursor" ) then
        relativeTo = nil;
        local cursorX, cursorY = GetCursorPosition();
        cursorX = cursorX/uiScale;
        cursorY =  cursorY/uiScale;

        if ( not xOffset ) then
            xOffset = 0;
        end
        if ( not yOffset ) then
            yOffset = 0;
        end
        xOffset = cursorX + xOffset;
        yOffset = cursorY + yOffset;
    else
        -- See if the anchor was set manually using setanchor
        if ( self.xOffset ) then
            xOffset = self.xOffset;
        end
        if ( self.yOffset ) then
            yOffset = self.yOffset;
        end
        if ( self.point ) then
            point = self.point;
        end
        if ( self.relativeTo ) then
            relativeTo = self.relativeTo;
        else
            relativeTo = anchorName;
        end
        if ( self.relativePoint ) then
            relativePoint = self.relativePoint;
        end
    end
            
    if not point then
        point = "TOPLEFT"
    end
    if not relativePoint then
        relativePoint = "BOTTOMLEFT"
    end
    if not xOffset or not yOffset then
        xOffset = 8
        yOffset = 22
    end

    list:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset);

    if self.displayMode == "MENU" then
        list.Backdrop:Hide()
        list.MenuBackdrop:Show()
    else
        list.Backdrop:Show()
        list.MenuBackdrop:Hide()
    end

    list.maxWidth = 0

    self.buttonPool:ReleaseAll()
    self:Initialize()
    
    list:SetWidth(list.maxWidth + 25)
    
    for button in self.buttonPool:EnumerateActive() do
        button:SetWidth(list.maxWidth);
    end

    list:Show()
end
function BtWQuestsDropDownMenuMixin:Close()
    self:GetListFrame():Hide()
end

-- [[ Character Dropdown ]]
BtWQuestsCharacterDropDownMixin = {}
function BtWQuestsCharacterDropDownMixin:OnLoad()
    self:SetDropDownWidth(156, 23 * 2);
    self.xOffset = 8
    self.yOffset = 15
    -- self:JustifyText("LEFT");
    -- if not self.Initialized then
    --     UIDropDownMenu_SetWidth(self, 156, 23 * 2);
	-- 	UIDropDownMenu_SetInitializeFunction(self, self.Initialize);
    --     -- UIDropDownMenu_Initialize(self, self.Initialize);
    --     self.xOffset = 8
    --     self.yOffset = 15

    --     self.Initialized = true
    -- end
end
function BtWQuestsCharacterDropDownMixin:Initialize()
    local function Select (button)
        self:GetParent():SelectCharacter(button.value)
    end

    local name = UnitName("player")
    local realm = GetRealmName()
    local player = name .. "-" .. realm

    local currentName, currentRealm = self:GetParent():GetCharacter():GetFullName()
    local current = currentName .. "-" .. currentRealm

    local info = self:CreateInfo();
    info.text = RAID_CLASS_COLORS[select(2,UnitClass("player"))]:WrapTextInColorCode(player .. " (" .. UnitLevel("player") .. ")")
    -- info.text = player
    info.value = player
    info.func = Select
    info.checked = player == current
    info.deleteFunc = function (button, ...)
       BtWQuestsCharacters:RemoveCharacter(button.value)
    end
    self:AddButton(info)

    info.hasDelete = true

    for _,character,data in BtWQuestsCharacters:ipairs() do
        if character ~= player then
            info.text = RAID_CLASS_COLORS[data:GetClassString()]:WrapTextInColorCode(character .. " (" .. data:GetLevel() .. ")")
            -- info.text = character
            info.value = character
            info.func = Select
            info.checked = character == current
            self:AddButton(info)
        end
    end
end

-- [[ Expansion Dropdown ]]
BtWQuestsExpansionDropDownMixin = {}
function BtWQuestsExpansionDropDownMixin:OnLoad()
    self:SetDropDownWidth(156);
    self:JustifyText("LEFT");
    -- if not self.Initialized then
    --     UIDropDownMenu_SetWidth(self, 156);
    --     UIDropDownMenu_JustifyText(self, "LEFT");
	-- 	UIDropDownMenu_SetInitializeFunction(self, self.Initialize);
    --     -- UIDropDownMenu_Initialize(self, self.Initialize);

    --     self.Initialized = true
    -- end
end
function BtWQuestsExpansionDropDownMixin:Initialize(level)
    local function Select (button)
        self:GetParent():SelectExpansion(button.value)
    end

    local info = self:CreateInfo()
    local current = self:GetParent():GetExpansion()
    for i=0,LE_EXPANSION_LEVEL_CURRENT do
        if BtWQuestsDatabase:HasExpansion(i) then
            info.text = BtWQuestsDatabase:GetExpansionByID(i)
            info.value = i;
            info.func = Select
            info.checked = i == current;

            self:AddButton(info)
        elseif i == current then
            info.text = _G['BTWQUESTS_EXPANSION_NAME' .. i]
            info.value = i;
            info.func = Select
            info.checked = i == current;

            self:AddButton(info)
        end
    end
end

-- [[ Tooltip ]]
BtWQuestsTooltipMixin = {}
function BtWQuestsTooltipMixin:OnLoad()
    self:SetScript("OnTooltipSetQuest", self.OnSetQuest)
    
    self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
    self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
end
function BtWQuestsTooltipMixin:OnSetQuest()
    local quest = BtWQuestsDatabase:GetQuest(self.questID, self.character)
    if quest == nil then
        return
    end

    self:AddRewards(quest)
end
function BtWQuestsTooltipMixin:AddRewards(item)
    local rewards = item:GetRewards()
    if not rewards or #rewards == 0 then
        return
    end
    
    local addedRewards
    for _,reward in ipairs(rewards) do
        if not reward:GetSkip() and reward:GetVisible() then
            if not addedRewards then
                self:AddLine(" ")
                self:AddLine("Rewards:")
                addedRewards = true
            end

            self:AddLine(" - " .. reward:GetName("reward"), 1, 1, 1)
        end
	end
end
function BtWQuestsTooltipMixin:SetChain(chainID, character)
    local chainID = tonumber(chainID)
    
    local _, name, _, _, _, _, numPrerequisites = BtWQuestsDatabase:GetChainByID(chainID, character)
    
    self:ClearLines()
    self:AddDoubleLine(name)
    
    if BtWQuestsDatabase:IsChainActive(chainID, character) then
        self:AddLine(BTWQUESTS_QUEST_CHAIN_ACTIVE)
    end
    
    local addedPrerequisite
    local i = 1
	for index = 1, numPrerequisites do
        local name, visible, skip, completed = BtWQuestsDatabase:GetChainPrerequisiteByID(chainID, index, character);
        if visible and not skip then
            if not addedPrerequisite then
                self:AddLine(" ")
                self:AddLine(BTWQUESTS_TOOLTIP_PREREQUISITES)
                addedPrerequisite = true
            end

            if completed then
                self:AddLine(" - " .. name, 0.5, 0.5, 0.5)
            else
                self:AddLine(" - " .. name, 1, 1, 1)
            end
        end
	end

    self:AddRewards(BtWQuestsDatabase:GetChain(chainID, character))
    
    self:Show();
end
-- Custom function for displaying an active quest showing completed requirements
function BtWQuestsTooltipMixin:SetActiveQuest(id, character)
    local id = tonumber(id)
    
    local _, name = BtWQuestsDatabase:GetQuestByID(id, character)
    local questLogIndex = GetQuestLogIndexByID(id)
    local _, objectiveText = GetQuestLogQuestText(questLogIndex);
    
    self:ClearLines()
    self:AddDoubleLine(name)
    
    self:AddLine(GREEN_FONT_COLOR_CODE..QUEST_TOOLTIP_ACTIVE..FONT_COLOR_CODE_CLOSE)

    if objectiveText then
        self:AddLine(" ")
        self:AddLine(objectiveText, 1, 1, 1)
    end
    
    local requiredMoney = GetQuestLogRequiredMoney(questLogIndex);
    local numRequirements = GetNumQuestLeaderBoards(questLogIndex);

    local addedTitle
	for index = 1,numRequirements do
        local name, _, completed = GetQuestLogLeaderBoard(index, questLogIndex);
        if name then
            if not addedTitle then
                self:AddLine(" ")
                self:AddLine(QUEST_TOOLTIP_REQUIREMENTS)
                addedTitle = true
            end

            if completed then
                self:AddLine(" - " .. name, 0.5, 0.5, 0.5)
            else
                self:AddLine(" - " .. name, 1, 1, 1)
            end
        end
    end
    
    self:OnSetQuest()
    self:Show()
end
-- Doing this because TSM and Auctioneer tainted GameTooltip.SetHyperlink without checking if their variables exist
local dummpGameTooltip = CreateFrame("GameTooltip", "BtWQuestsDummyTooltip", UIParent, "GameTooltipTemplate")
dummpGameTooltip:Hide()
function BtWQuestsTooltipMixin:SetHyperlink(link, character)
    local _, _, color, type, text, name = string.find(link, "|?c?f?f?(%x*)|?H?([^:]+):([^|]+)|?h?%[?([^%[%]]*)%]?|?h?|?r?")
    
    if type == "quest" and character:IsPlayer() then
        local _, _, id = string.find(text, "^(%d+)")
        if GetQuestLogIndexByID(id) > 0 then
            self.character = character
            self.questID = id

            self:SetActiveQuest(id, character)
        else
            self.character = character
            self.questID = id

            dummpGameTooltip.SetHyperlink(self, link)
        end
    elseif type == "btwquests" then
        local _, _, subtype, id = string.find(text, "^([^:]*):(%d+)")
        
        assert(subtype == "chain")
        
        self:SetChain(id, character)
    else
        dummpGameTooltip.SetHyperlink(self, link)
    end
end