--========================================================--
--             Scorpio TabControl Widget                  --
--                                                        --
-- Author      :  kurapica125@outlook.com                 --
-- Create Date :  2020/04/26                              --
--========================================================--

--========================================================--
Scorpio           "Scorpio.Widget.TabControl"        "1.0.0"
--========================================================--

-----------------------------------------------------------
--                    TabControl Widget                    --
-----------------------------------------------------------
__Sealed__() class "TabButton" (function(_ENV)
    inherit "Button"

    local Next                  = Scorpio.Next

    local function OnClick(self)
        if not self.Selected then
            PlaySound(SOUNDKIT.IG_CHARACTER_INFO_TAB)
            self.Selected       = true
        end
    end

    local function OnDisable(self)
        self:GetFontString():SetTextColor(0.5, 0.5, 0.5)

        if self.Selected then
            for _, child in self:GetParent():GetChilds() do
                if child ~= self and Class.IsObjectType(child, TabButton) and child:IsEnabled() then
                    child.Selected = true
                    break
                end
            end
        end
    end

    local function OnEnable(self)
        self:GetFontString():SetTextColor(1, 0.82, 0)
    end

    --- Whether the tab is selected
    property "Selected"         {
        type                    = Boolean,
        handler                 = function(self, flag)
            self:GetChild("LeftDisabled"):SetShown(flag)
            self:GetChild("MiddleDisabled"):SetShown(flag)
            self:GetChild("RightDisabled"):SetShown(flag)
            self:GetChild("Left"):SetShown(not flag)
            self:GetChild("Middle"):SetShown(not flag)
            self:GetChild("Right"):SetShown(not flag)
            self.Container:SetShown(flag)

            local text      = self:GetFontString()
            if flag then
                text:SetTextColor(1, 1, 1)
                text:ClearAllPoints()
                text:SetPoint("CENTER", 0, 0)
                self:GetHighlightTexture():Hide()
            else
                self:GetFontString():SetTextColor(1,0.82,0)
                text:ClearAllPoints()
                text:SetPoint("CENTER", 0, -3)
                self:GetHighlightTexture():Show()
            end

            if flag then
                for _, child in self:GetParent():GetChilds() do
                    if child ~= self and Class.IsObjectType(child, TabButton) then
                        child.Selected = false
                    end
                end
            end
        end,
    }

    --- The Container of the tab page
    property "Container"        { type = Frame }

    --- Override the SetText method
    function SetText(self, text)
        Button.SetText(self, text)

        Next(function()
            local text          = self:GetFontString()
            local width         = text and text:GetStringWidth() or 0

            self:SetWidth(width + 36)
        end)
    end

    __Template__{
        LeftDisabled            = Texture,
        MiddleDisabled          = Texture,
        RightDisabled           = Texture,
        Left                    = Texture,
        Middle                  = Texture,
        Right                   = Texture,
    }
    function __ctor(self)
        self:SetWidth(115)
        self:InstantApplyStyle()

        self:SetFrameLevel(self:GetFrameLevel() + 4)

        self.OnClick            = self.OnClick + OnClick
        self.OnEnable           = self.OnEnable + OnEnable
        self.OnDisable          = self.OnDisable + OnDisable
    end
end)

__Sealed__()
class "TabControl" (function(_ENV)
    inherit "Frame"

    local function refreshHeaderScroll(self)
        local header            = self:GetChild("Header")
        local container         = header:GetChild("Container")

        if container:GetWidth() < self:GetWidth() then
            if self:GetChild("LeftScroll"):IsShown() then
                self:GetChild("LeftScroll"):Hide()
                self:GetChild("RightScroll"):Hide()

                header:ClearAllPoints()
                header:SetPoint("TOPLEFT")
                header:SetPoint("RIGHT")

                container:ClearAllPoints()
                container:SetPoint("TOPLEFT")
                container:SetPoint("BOTTOM")
            end
        else
            if not self:GetChild("LeftScroll"):IsShown() then
                self:GetChild("LeftScroll"):Show()
                self:GetChild("RightScroll"):Show()

                header:ClearAllPoints()
                header:SetPoint("TOPLEFT")
                header:SetPoint("RIGHT", self:GetChild("LeftScroll"), "LEFT")

                container:ClearAllPoints()
                container:SetPoint("TOPLEFT")
                container:SetPoint("BOTTOM")
            end

            local offset        = container.HorizontalOffset or 0

            if offset > (container:GetWidth() - header:GetWidth()) then
                container.HorizontalOffset = container:GetWidth() - header:GetWidth()
                container:ClearAllPoints()
                container:SetPoint("TOPLEFT", -container.HorizontalOffset, 0)
                container:SetPoint("BOTTOM")
            end
        end
    end

    local function HeaderContainer_Resize(self)
        local width             = 0
        local index             = 0

        repeat
            index               = index + 1
            local child         = self:GetChild("TabButton" .. index)
            if child then width = width + child:GetWidth() end
        until not child

        self:SetWidth(width)

        return refreshHeaderScroll(self:GetParent():GetParent())
    end

    local function LeftScroll_OnClick(self)
        self                    = self:GetParent()
        local header            = self:GetChild("Header")
        local container         = header:GetChild("Container")
        local offset            = container.HorizontalOffset or 0

        offset                  = offset - header:GetWidth() / 2
        if offset < 0 then offset = 0 end

        container.HorizontalOffset = offset
        container:ClearAllPoints()
        container:SetPoint("TOPLEFT", -offset, 0)
        container:SetPoint("BOTTOM")
    end

    local function RightScroll_OnClick(self)
        self                    = self:GetParent()
        local header            = self:GetChild("Header")
        local container         = header:GetChild("Container")
        local offset            = container.HorizontalOffset or 0
        local maxoff            = container:GetWidth() - header:GetWidth()

        offset                  = offset + header:GetWidth() / 2
        if offset > maxoff then offset = maxoff end

        container.HorizontalOffset = offset
        container:ClearAllPoints()
        container:SetPoint("TOPLEFT", -offset, 0)
        container:SetPoint("BOTTOM")
    end

    local function TabButton_OnSizeChanged(self)
        return HeaderContainer_Resize(self:GetParent())
    end

    local function OnSizeChanged(self)
        return refreshHeaderScroll(self)
    end

    --- Add a tab page and return the tab button
    __Arguments__{ NEString, UI/nil }
    function AddTabPage(self, name, frame)
        local header            = self:GetChild("Header"):GetChild("Container")
        local index             = 0

        repeat
            index               = index + 1
            local child         = header:GetChild("TabButton" .. index)
            if child and child:GetText() == name then return child end
        until not child

        local tabButton         = TabButton("TabButton" .. index, header)
        tabButton.OnSizeChanged = tabButton.OnSizeChanged + TabButton_OnSizeChanged

        tabButton:ClearAllPoints()

        if index == 1 then
            tabButton:SetPoint("BOTTOMLEFT")
        else
            local prev          = header:GetChild("TabButton" .. (index - 1))
            tabButton:SetPoint("BOTTOMLEFT", prev, "BOTTOMRIGHT")
        end

        tabButton:SetText(name)
        local container         = Frame("TabPageContainer" .. index, self:GetChild("Body"))
        container:SetPoint("TOPLEFT")
        container:SetPoint("BOTTOMRIGHT")
        tabButton.Container     = container

        if index == 1 then
            tabButton.Selected  = true
        else
            tabButton.Selected  = false
        end

        return tabButton
    end

    --- Get the tab button by name
    function GetTabPage(self, name)
        local header            = self:GetChild("Header"):GetChild("Container")
        local index             = 0

        repeat
            index               = index + 1
            local child         = header:GetChild("TabButton" .. index)
            if child and child:GetText() == name then return child end
        until not child
    end

    __Template__{
        Header                  = ScrollFrame,
        Body                    = Frame,
        LeftScroll              = Button,
        RightScroll             = Button,

        -- Child Tree
        {
            Header              = {
                Container       = Frame,
            }
        }
    }
    function __ctor(self)
        local header            = self:GetChild("Header")
        header:ClearAllPoints()
        header:SetPoint("TOPLEFT")
        header:SetPoint("RIGHT")
        header:SetHeight(32)

        local container         = header:GetChild("Container")
        header:SetScrollChild(container)
        container:ClearAllPoints()
        container:SetPoint("TOPLEFT")
        container:SetPoint("BOTTOM")
        container:SetWidth(1)

        local leftScroll        = self:GetChild("LeftScroll")
        local rightScroll       = self:GetChild("RightScroll")

        leftScroll:Hide()
        rightScroll:Hide()

        self.OnSizeChanged      = self.OnSizeChanged + OnSizeChanged
        leftScroll.OnClick      = leftScroll.OnClick + LeftScroll_OnClick
        rightScroll.OnClick     = rightScroll.OnClick + RightScroll_OnClick
    end
end)

-----------------------------------------------------------
--                   TabControl Style                    --
-----------------------------------------------------------
Style.UpdateSkin("Default",     {
    [TabButton]                 = {
        height                  = 24,

        LeftDisabled            = {
            drawLayer           = "BORDER",
            file                = [[Interface\OptionsFrame\UI-OptionsFrame-ActiveTab]],
            size                = Size(20, 24),
            location            = { Anchor("BOTTOMLEFT", 0, -3) },
            texCoords           = RectType(0, 0.15625, 0, 1.0),
        },
        MiddleDisabled          = {
            drawLayer           = "BORDER",
            file                = [[Interface\OptionsFrame\UI-OptionsFrame-ActiveTab]],
            location            = { Anchor("TOPLEFT", 0, 0, "LeftDisabled", "TOPRIGHT"), Anchor("BOTTOMRIGHT", 0, 0, "RightDisabled", "BOTTOMLEFT") },
            texCoords           = RectType(0.15625, 0.84375, 0, 1.0),
        },
        RightDisabled           = {
            drawLayer           = "BORDER",
            file                = [[Interface\OptionsFrame\UI-OptionsFrame-ActiveTab]],
            size                = Size(20, 24),
            location            = { Anchor("BOTTOMRIGHT", 0, -3) },
            texCoords           = RectType(0.84375, 1.0, 0, 1.0),
        },
        Left                    = {
            drawLayer           = "BORDER",
            file                = [[Interface\OptionsFrame\UI-OptionsFrame-InActiveTab]],
            size                = Size(20, 24),
            location            = { Anchor("TOPLEFT") },
            texCoords           = RectType(0, 0.15625, 0, 1.0),
        },
        Middle                  = {
            drawLayer           = "BORDER",
            file                = [[Interface\OptionsFrame\UI-OptionsFrame-InActiveTab]],
            location            = { Anchor("TOPLEFT", 0, 0, "Left", "TOPRIGHT"), Anchor("BOTTOMRIGHT", 0, 0, "Right", "BOTTOMLEFT") },
            texCoords           = RectType(0.15625, 0.84375, 0, 1.0),
        },
        Right                   = {
            drawLayer           = "BORDER",
            file                = [[Interface\OptionsFrame\UI-OptionsFrame-InActiveTab]],
            size                = Size(20, 24),
            location            = { Anchor("TOPRIGHT") },
            texCoords           = RectType(0.84375, 1.0, 0, 1.0),
        },
        ButtonText              = {
            fontObject          = GameFontNormalSmall,
        },

        HighlightTexture        = {
            file                = [[Interface\PaperDollInfoFrame\UI-Character-Tab-Highlight]],
            location            = { Anchor("TOPLEFT", 10, -4), Anchor("BOTTOMRIGHT", -10, 4) },
            alphamode           = "ADD",
        },

        normalFont              = GameFontNormalSmall,
        disabledFont            = GameFontDisableSmall,
        highlightFont           = GameFontHighlightSmall,
    },
    [TabControl]                = {
        RightScroll             = {
            location            = { Anchor("TOPRIGHT") },
            size                = Size(32, 32),

            NormalTexture       = {
                file            = [[Interface\Buttons\UI-SpellbookIcon-NextPage-Up]],
                setAllPoints    = true,
            },
            PushedTexture       = {
                file            = [[Interface\Buttons\UI-SpellbookIcon-NextPage-Down]],
                setAllPoints    = true,
            },
            DisabledTexture     = {
                file            = [[Interface\Buttons\UI-SpellbookIcon-NextPage-Disabled]],
                setAllPoints    = true,
            },
            HighlightTexture    = {
                file            = [[Interface\Buttons\UI-Common-MouseHilight]],
                setAllPoints    = true,
                alphamode       = "ADD",
            },
        },
        LeftScroll              = {
            location            = { Anchor("RIGHT", 0, 0, "RightScroll", "LEFT") },
            size                = Size(32, 32),

            NormalTexture       = {
                file            = [[Interface\Buttons\UI-SpellbookIcon-PrevPage-Up]],
                setAllPoints    = true,
            },
            PushedTexture       = {
                file            = [[Interface\Buttons\UI-SpellbookIcon-PrevPage-Down]],
                setAllPoints    = true,
            },
            DisabledTexture     = {
                file            = [[Interface\Buttons\UI-SpellbookIcon-PrevPage-Disabled]],
                setAllPoints    = true,
            },
            HighlightTexture    = {
                file            = [[Interface\Buttons\UI-Common-MouseHilight]],
                setAllPoints    = true,
                alphamode       = "ADD",
            },
        },
        Header                  = {
            height              = 24,
        },
        Body                    = {
            location            = { Anchor("TOPLEFT", 0, 0, "Header", "BOTTOMLEFT"), Anchor("BOTTOMRIGHT") },
            backdrop            = {
                edgeFile        = [[Interface\Tooltips\UI-Tooltip-Border]],
                tile            = true, tileSize = 16, edgeSize = 16,
                insets          = { left = 5, right = 5, top = 5, bottom = 5 }
            },
            backdropBorderColor = Color(0.6, 0.6, 0.6),
        }
    },
})