--[[--------------------------------------------------------------------------
	Boom - Modern Healing & Support Raid Frames
	Core/Media.lua

	Texture and font registry.

	Boom ships NO art files. Everything resolves to assets that are guaranteed
	to exist in the retail client, so the addon is a pure-Lua drop-in. If the
	user happens to have LibSharedMedia-3.0 loaded (ElvUI, WeakAuras, Details,
	almost every UI pack) we transparently absorb its lists as well.

	    Boom.Media:Texture("Boom Flat")  -> path
	    Boom.Media:Font("Boom Default")  -> path
	    Boom.Media:List("statusbar")     -> sorted array of names
----------------------------------------------------------------------------]]

local ADDON_NAME, Boom = ...

local Media = Boom:NewModule("Media")

local floor = math.floor

--------------------------------------------------------------------------------
-- Built-in assets
--------------------------------------------------------------------------------

-- A solid white 8x8 texture is the cleanest possible bar fill: it takes a
-- colour exactly, tiles without artefacts and stays crisp at any size.
local WHITE = "Interface\\Buttons\\WHITE8X8"

local statusbars = {
	["Boom Flat"]     = WHITE,
	["Boom Smooth"]   = "Interface\\TargetingFrame\\UI-StatusBar",
	["Boom Raid"]     = "Interface\\RaidFrame\\Raid-Bar-Hp-Fill",
	["Blizzard"]      = "Interface\\TargetingFrame\\UI-StatusBar",
	["Solid"]         = WHITE,
}

local borders = {
	["Boom Thin"] = WHITE,
	["None"]      = nil,
}

-- Resolved at load: whatever the client actually uses for its default font is
-- by definition a valid, glyph-complete path for this locale.
local DEFAULT_FONT = (GameFontNormal and GameFontNormal:GetFont()) or "Fonts\\FRIZQT__.TTF"
local NUMBER_FONT  = (NumberFontNormal and NumberFontNormal:GetFont()) or DEFAULT_FONT

local fonts = {
	["Boom Default"]   = DEFAULT_FONT,
	["Boom Numbers"]   = NUMBER_FONT,
	["Friz Quadrata"]  = "Fonts\\FRIZQT__.TTF",
	["Arial Narrow"]   = "Fonts\\ARIALN.TTF",
	["Skurri"]         = "Fonts\\skurri.TTF",
	["Morpheus"]       = "Fonts\\MORPHEUS.TTF",
}

Media.WHITE = WHITE

-- The addon's own emblem. The one piece of art Boom draws that is not a unit
-- frame: the minimap button, the settings window and the setup wizard all show
-- it, so it lives here rather than being spelled out at three call sites.
--
-- 256x256 32-bit uncompressed TGA with a soft circular alpha edge, so it drops
-- into a round minimap ring and onto a flat title bar equally well.
Media.LOGO = "Interface\\AddOns\\Boom\\Media\\Logo.tga"

--------------------------------------------------------------------------------
-- LibSharedMedia bridge (entirely optional)
--------------------------------------------------------------------------------

local LSM

local function fetchLSM()
	if LSM ~= nil then return LSM end
	if _G.LibStub then
		local ok, lib = pcall(_G.LibStub, "LibSharedMedia-3.0", true)
		LSM = (ok and lib) or false
	else
		LSM = false
	end
	return LSM
end

local LSM_TYPE = {
	statusbar = "statusbar",
	font      = "font",
	border    = "border",
}

--------------------------------------------------------------------------------
-- Lookup
--------------------------------------------------------------------------------

--- Ask LibSharedMedia for a path.
---
--- Isolated because it is the one lookup Boom does not own: the library belongs
--- to whichever addon shipped it, its Fetch has been rewritten across versions,
--- and a name that came out of a saved profile may be one no addon registers any
--- more. A throw in here would take a whole frame relayout with it.
local function fetchFromLSM(mediaType, name)
	if type(name) ~= "string" or name == "" then return nil end

	local lib = fetchLSM()
	if not lib or not lib.Fetch then return nil end

	local ok, path = pcall(lib.Fetch, lib, mediaType, name, true)
	if ok and type(path) == "string" and path ~= "" then return path end
	return nil
end

--- Resolve a status bar texture name to a path. Always returns something usable.
function Media:Texture(name)
	if name ~= nil and statusbars[name] then return statusbars[name] end
	return fetchFromLSM(LSM_TYPE.statusbar, name) or WHITE
end

--- Resolve a font name to a path. Always returns something usable.
function Media:Font(name)
	if name ~= nil and fonts[name] then return fonts[name] end
	return fetchFromLSM(LSM_TYPE.font, name) or DEFAULT_FONT
end

function Media:Border(name)
	if name == "None" then return nil end
	if name ~= nil and borders[name] then return borders[name] end
	return fetchFromLSM(LSM_TYPE.border, name) or WHITE
end

--- Sorted list of every available name for a media type, built-ins first.
function Media:List(mediaType)
	local own =
		(mediaType == "statusbar" and statusbars) or
		(mediaType == "font" and fonts) or
		(mediaType == "border" and borders) or {}

	local seen, out = {}, {}
	for name in pairs(own) do
		seen[name] = true
		out[#out + 1] = name
	end

	local lib = fetchLSM()
	if lib and LSM_TYPE[mediaType] then
		for _, name in ipairs(lib:List(LSM_TYPE[mediaType])) do
			if not seen[name] then
				seen[name] = true
				out[#out + 1] = name
			end
		end
	end

	table.sort(out)
	return out
end

--------------------------------------------------------------------------------
-- Convenience accessors that read straight from the active profile
--------------------------------------------------------------------------------

--- The appearance block, or nil while the profile is still being built. Every
--- accessor below goes through this: `Boom.profile and Boom.profile.appearance.x`
--- still indexes a nil `appearance` the moment a profile exists but has not been
--- back-filled yet, which is exactly the window these are called in at login.
local function appearance()
	return Boom.profile and Boom.profile.appearance or nil
end

function Media:GetBarTexture()
	local app = appearance()
	return self:Texture(app and app.barTexture or "Boom Flat")
end

function Media:GetBackgroundTexture()
	local app = appearance()
	return self:Texture(app and app.bgTexture or "Boom Flat")
end

function Media:GetFont()
	local app = appearance()
	return self:Font(app and app.font or "Boom Default")
end

function Media:GetFontSize()
	local app = appearance()
	return (app and tonumber(app.fontSize)) or 12
end

--- Returns the flags string the profile holds, NOT nil for "none" - Util.SetFont
--- normalises it, and nil is the one value the client's SetFont rejects outright.
function Media:GetFontOutline()
	local app = appearance()
	return (app and app.fontOutline) or "OUTLINE"
end

--------------------------------------------------------------------------------
-- Shared icon paths
--------------------------------------------------------------------------------

Media.ICONS = {
	roleTank    = "Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES",
	roleHealer  = "Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES",
	roleDamager = "Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES",
	leader      = "Interface\\GroupFrame\\UI-Group-LeaderIcon",
	assistant   = "Interface\\GroupFrame\\UI-Group-AssistantIcon",
	masterLoot  = "Interface\\GroupFrame\\UI-Group-MasterLooter",
	raidTargets = "Interface\\TargetingFrame\\UI-RaidTargetingIcons",
	readyCheck  = "Interface\\RaidFrame\\ReadyCheck-Ready",
	notReady    = "Interface\\RaidFrame\\ReadyCheck-NotReady",
	waiting     = "Interface\\RaidFrame\\ReadyCheck-Waiting",
	resurrect   = "Interface\\RaidFrame\\Raid-Icon-Rez",
	summon      = "Interface\\RaidFrame\\Raid-Icon-SummonPending",
	glow        = "Interface\\SpellActivationOverlay\\IconAlert",
	question    = "Interface\\ICONS\\INV_Misc_QuestionMark",
}

--- Texture coordinates inside UI-LFG-ICON-PORTRAITROLES for each role.
Media.ROLE_COORDS = {
	TANK    = { 0,     19/64, 22/64, 41/64 },
	HEALER  = { 20/64, 39/64, 1/64,  20/64 },
	DAMAGER = { 20/64, 39/64, 22/64, 41/64 },
}

--- Texture coordinates for the eight raid target markers (1 = star .. 8 = skull).
--- Returns nil for a secret index - the caller must use
--- Boom.ClassData:SetRaidTargetTexture, which hands the value to Blizzard
--- instead of doing arithmetic on it.
function Media:GetRaidTargetCoords(index)
	if _G.issecretvalue and _G.issecretvalue(index) then return nil end
	if not index or index < 1 or index > 8 then return nil end
	local left  = ((index - 1) % 4) * 0.25
	local top   = floor((index - 1) / 4) * 0.25
	return left, left + 0.25, top, top + 0.25
end
