----------------------------------------------------------------------------------------
--  API of DarkUI
----------------------------------------------------------------------------------------
local T, C, L, _ = unpack(select(2, ...))

local backdrop_color = C.Media.backdrop_color
local border_color = C.Media.border_color
local overlay_color = C.Media.overlay_color

local mult =  768 / string.match(T.resolution, "%d+x(%d+)") / C.Module.General.uiScale

----------------------------------------------------------------------------------------
--  Kill object function
----------------------------------------------------------------------------------------
local hiddenFrame = CreateFrame("Frame")
hiddenFrame:Hide()
local kill = function(object)
    if object.UnregisterAllEvents then
        object:UnregisterAllEvents()
        object:SetParent(hiddenFrame)
    else
        object.Show = T.Dummy
    end
    object:Hide()
end

----------------------------------------------------------------------------------------
--  styles function
----------------------------------------------------------------------------------------

local function fadeIn(f)
    T.UIFrameFadeIn(f, 0.4, f:GetAlpha(), 1)
end

local function fadeOut(f)
    T.UIFrameFadeOut(f, 0.8, f:GetAlpha(), 0)
end

local function setTemplate(f, t)
    if not t then t = "Default" end

    local backdropr, backdropg, backdropb, backdropa = unpack(C.Media.backdrop_color)
    local borderr, borderg, borderb, bordera = unpack(C.Media.border_color)

    if t == "Shadow" then
        f:SetBackdrop({
            bgFile = nil,
            edgeFile = C.Media.Texture.shadow,
            tile = false, tileSize = 32, edgeSize = 6,
            insets = { left = 6, right = 6, top = 6, bottom = 6 },
        })

        borderr, borderg, borderb, bordera = unpack(C.Media.shadow_color)
    elseif t == "Border" then
        f:SetBackdrop({
            bgFile = nil,
            edgeFile = C.Media.Texture.outer_border,
            tile = false, tileSize = 32, edgeSize = 6,
            insets = { left = 6, right = 6, top = 6, bottom = 6 },
        })
    else
        f:SetBackdrop({
            bgFile = C.Media.Texture.blank, edgeFile = C.Media.Texture.blank, edgeSize = mult,
            insets = { left = -mult, right = -mult, top = -mult, bottom = -mult }
        })
    end

    if t == "Transparent" then
        backdropa = overlay_color[4]
        --f:CreateBorder(true, true)
        f:CreateBorder()
    elseif t == "Overlay" then
        backdropa = 1
        f:CreateOverlay()
    elseif t == "Invisible" then
        backdropa = 0
        bordera = 0
    else
        backdropa = backdrop_color[4]
    end

    f:SetBackdropBorderColor(borderr, borderg, borderb, bordera)

    if t ~= "Shadow" then
        f:SetBackdropColor(backdropr, backdropg, backdropb, backdropa)
    end
end

local function createOverlay(f)
    if f.overlay then return end

    local overlay = f:CreateTexture("$parentOverlay", "BORDER", f)
    overlay:SetPoint("TOPLEFT", 2, -2)
    overlay:SetPoint("BOTTOMRIGHT", -2, 2)
    overlay:SetTexture(C.Media.Texture.blank)
    overlay:SetVertexColor(0.1, 0.1, 0.1, 1)

    f.overlay = overlay
end

local function createPanel(f, t, w, h, a1, p, a2, x, y)
    if not t then t = "Default" end

    f:SetWidth(w)
    f:SetHeight(h)
    f:SetFrameLevel(1)
    f:SetFrameStrata("BACKGROUND")
    f:SetPoint(a1, p, a2, x, y)

    setTemplate(f, t)
end

local function createBorder(f, s)
    if f.border then return end

    local s = s or 1

    f.border = CreateFrame("Frame", nil, f)
    f.border:ClearAllPoints()
    f.border:SetPoint("TOPLEFT", f, "TOPLEFT", -s, s)
    f.border:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", s, -s)
    f.border:SetFrameLevel(f:GetFrameLevel() + 1)

    f.border:SetTemplate("Border")
    f.border:CreateShadow()
end

-- create Shadow
local createShadow = function(frame)
    local shadow = CreateFrame("Frame", nil, frame)

    shadow:SetPoint("TOPLEFT", frame, "TOPLEFT", -4, 4)
    shadow:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 4, -4)
    shadow:SetFrameLevel(frame:GetFrameLevel() == 0 and 0 or frame:GetFrameLevel() - 1)
    shadow:SetTemplate("Shadow")

    frame.shadow = shadow
end

-- create backdrop
local createBackdrop = function(frame, t, shadow)
    if not t then t = "Default" end

    local b = CreateFrame("Frame", "$parentBackdrop", frame)
    b:SetPoint("TOPLEFT", -2, 2)
    b:SetPoint("BOTTOMRIGHT", 2, -2)
    b:SetFrameLevel(frame:GetFrameLevel() == 0 and 0 or frame:GetFrameLevel() - 1)

    b:SetTemplate(t)

    frame.backdrop = b

    if shadow then createShadow(frame) end
end

-- create checkbox
local createCheckBox = function(frame, alpha)
    frame:SetNormalTexture("")
    frame:SetPushedTexture("")
    frame:SetHighlightTexture(C.Media.Texture.status)

    local hl = frame:GetHighlightTexture()
    hl:SetPoint("TOPLEFT", 5, -5)
    hl:SetPoint("BOTTOMRIGHT", -5, 5)
    hl:SetVertexColor(T.color.r, T.color.g, T.color.b, .2)

    local bd = CreateFrame("Frame", nil, frame)
    bd:SetPoint("TOPLEFT", 4, -4)
    bd:SetPoint("BOTTOMRIGHT", -4, 4)
    bd:SetFrameLevel(frame:GetFrameLevel() - 1)
    createBackdrop(bd, nil)

    local ch = frame:GetCheckedTexture()
    ch:SetDesaturated(true)
    ch:SetVertexColor(T.color.r, T.color.g, T.color.b)
end

local function stripTextures(object, kill)
    for i = 1, object:GetNumRegions() do
        local region = select(i, object:GetRegions())
        if region:GetObjectType() == "Texture" then
            if kill then
                region:Kill()
            else
                region:SetTexture(nil)
            end
        end
    end
end

local function createTwinkling(f)
    if f.twinkling then return end
    local twinkling = f:CreateAnimationGroup()
    local fadeIn = twinkling:CreateAnimation( "Alpha" );

    fadeIn:SetOrder(1)
    fadeIn:SetSmoothing("IN_OUT")
    --fadeIn:SetChange( -1 );
    fadeIn:SetDuration( .5 );

    local fadeOut = twinkling:CreateAnimation( "Alpha" );
    fadeOut:SetOrder( 2 );
   --fadeOut:SetChange( 1 );
    fadeOut:SetDuration( .5 );
    fadeOut:SetSmoothing("OUT")
    twinkling:SetScript("OnFinished", function(self) self:Play() end)

    f.twinkling = twinkling

    return twinkling
end

local function setTextureBorder(f)
    local border
    local fn = f:GetName()

    if f.border then return end

    if fn ~= nil then
        border = _G[fn.."Border"] or f:CreateTexture(fn.."Border", "BACKGROUND", nil, -7)
    else
        border = f:CreateTexture(nil, "BACKGROUND", nil, -7)
    end

    border:SetTexture(C.Media.Texture.border)
    border:SetTexCoord(0, 1, 0, 1)
    border:SetDrawLayer("BACKGROUND", -7)
    border:ClearAllPoints()
    border:SetAllPoints(f)
    
    f.border = border
end

----------------------------------------------------------------------------------------
--  apply api function
----------------------------------------------------------------------------------------
local function addapi(object)
    local mt = getmetatable(object).__index
    
    if not object.Kill then mt.Kill = kill end
    if not object.FadeIn then mt.FadeIn = fadeIn end
    if not object.FadeOut then mt.FadeOut = fadeOut end

    if not object.SetTextureBorder then mt.SetTextureBorder = setTextureBorder end
    if not object.CreateOverlay then mt.CreateOverlay = createOverlay end
    if not object.CreateShadow then mt.CreateShadow = createShadow end
    if not object.CreateBackdrop then mt.CreateBackdrop = createBackdrop end
    if not object.CreateCheckBox then mt.CreateCheckBox = createCheckBox end
    if not object.CreateBorder then mt.CreateBorder = createBorder end
    if not object.CreatePanel then mt.CreatePanel = createPanel end
    if not object.StripTextures then mt.StripTextures = stripTextures end
    if not object.SetTemplate then mt.SetTemplate = setTemplate end
    if not object.CreateTwinkling then mt.CreateTwinkling = createTwinkling end
end

local handled = {["Frame"] = true}
local object = CreateFrame("Frame")
addapi(object)
addapi(object:CreateTexture())
addapi(object:CreateFontString())

object = EnumerateFrames()
while object do
    if not handled[object:GetObjectType()] then
        addapi(object)
        handled[object:GetObjectType()] = true
    end

    object = EnumerateFrames(object)
end
