--[[--------------------------------------------------------------------------
	Boom - Modern Healing & Support Raid Frames
	Data/SpecArt.lua

	Specialization portrait artwork.

	Boom ships one full-body portrait per specialization in Media/Specs, named by
	specialization ID so the file and the code can never drift apart.

	Two things about the files are load-bearing and easy to get wrong later:

	  * They are 32-bit UNCOMPRESSED TGA. WoW cannot read PNG at all, and the
	    RLE-compressed TGA flavour is not reliably supported for addon art.
	  * The canvas is 256x512 because texture dimensions must be powers of two,
	    but the artwork is 2:3 and only fills the top 384 rows. Everything that
	    draws one must therefore apply TEX_COORD, or it renders with a quarter of
	    empty space underneath.

	Use CreatePortrait rather than wiring a texture up by hand - it handles the
	crop, the aspect ratio and the fade for you.
----------------------------------------------------------------------------]]

local ADDON_NAME, Boom = ...

local SpecArt = Boom:NewModule("SpecArt")

local Util = Boom.Util

-- Resolved lazily: this file lives in Data/ and therefore loads before UI/Skin,
-- so capturing Boom.Skin at file scope would capture nil.
local function skin()
	return Boom.Skin
end

SpecArt.PATH = "Interface\\AddOns\\Boom\\Media\\Specs\\"

-- Left, right, top, bottom. The artwork occupies rows 0..383 of a 512-row
-- canvas: 384 / 512 = 0.75.
SpecArt.TEX_COORD = { 0, 1, 0, 0.75 }

-- The aspect ratio of the visible part, for callers sizing a portrait.
SpecArt.ASPECT = 256 / 384

--- Specializations that actually have a file on disk. The "Initial" specs a
--- character carries before choosing one deliberately have none.
SpecArt.available = {}
for _, specID in ipairs({
	62, 63, 64, 65, 66, 70, 71, 72, 73,
	102, 103, 104, 105,
	250, 251, 252, 253, 254, 255,
	256, 257, 258, 259, 260, 261,
	262, 263, 264, 265, 266, 267,
	268, 269, 270,
	577, 581,
	1467, 1468, 1473, 1480,
}) do
	SpecArt.available[specID] = true
end

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

function SpecArt:Has(specID)
	return specID and self.available[specID] or false
end

--- Texture path for a spec, or nil when there is no art for it.
function SpecArt:GetTexture(specID)
	if not self:Has(specID) then return nil end
	return self.PATH .. specID .. ".tga"
end

function SpecArt:GetPlayerTexture()
	return self:GetTexture(Boom.Config:GetPlayerSpecID())
end

--- Is the user showing portraits at all?
function SpecArt:IsEnabled()
	local general = Boom.profile and Boom.profile.general
	return not general or general.showSpecArt ~= false
end

--- Point an existing texture at a spec. Returns false and hides the texture
--- when there is nothing to show, so callers can branch on one value.
function SpecArt:Apply(texture, specID)
	local path = self:IsEnabled() and self:GetTexture(specID) or nil
	if not path then
		texture:Hide()
		return false
	end

	texture:SetTexture(path)
	texture:SetTexCoord(unpack(self.TEX_COORD))
	texture:Show()
	return true
end

--------------------------------------------------------------------------------
-- Portrait widget
--------------------------------------------------------------------------------

--- A framed portrait that fades into the panel behind it.
--- opts = { width = 200, fade = true }
--- Returns a Frame with :SetSpec(specID) and :Refresh().
function SpecArt:CreatePortrait(parent, opts)
	opts = opts or {}

	local width = opts.width or 200
	local height = opts.height or math.floor(width / SpecArt.ASPECT + 0.5)

	local frame = CreateFrame("Frame", nil, parent)
	frame:SetSize(width, height)

	local art = frame:CreateTexture(nil, "ARTWORK")
	art:SetAllPoints()
	frame.art = art

	-- The figure stands on the bottom edge of the artwork, which reads as a
	-- hard cut against a flat panel. A short gradient in the panel's own colour
	-- dissolves the feet instead.
	if opts.fade ~= false then
		local fade = frame:CreateTexture(nil, "OVERLAY")
		fade:SetPoint("BOTTOMLEFT")
		fade:SetPoint("BOTTOMRIGHT")
		fade:SetHeight(math.max(12, math.floor(height * 0.18)))
		fade:SetTexture("Interface\\Buttons\\WHITE8X8")

		local Skin = skin()
		local r, g, b = Util.Unpack(Skin.colors.bg)
		Skin:SetGradient(fade, "VERTICAL", r, g, b, 1, r, g, b, 0)
		frame.fade = fade
	end

	function frame:SetSpec(specID)
		self.specID = specID
		local shown = SpecArt:Apply(self.art, specID)
		self:SetShown(shown)
		if self.fade then self.fade:SetShown(shown) end
		return shown
	end

	function frame:Refresh()
		return self:SetSpec(self.specID or Boom.Config:GetPlayerSpecID())
	end

	frame:SetSpec(opts.specID or Boom.Config:GetPlayerSpecID())
	return frame
end
