Quantcast
local addonName, addon = ...
local castingBar = addon:NewModule("CastingBar")

local CASTINGBAR_WIDTH = 256
local CASTINGBAR_HEIGHT = 64

local CUT_WIDTH = 40
local FRAGMENT_WIDTH = CUT_WIDTH / CASTINGBAR_WIDTH
local RIGHT_EDGE_START = (CASTINGBAR_WIDTH - CUT_WIDTH) / CASTINGBAR_WIDTH

castingBar.frame = CreateFrame("StatusBar", "CastingBarTest", UIParent, "CastingBarFrameTemplate")
CastingBarFrame_OnLoad(castingBar.frame, "player", true, false)

local function createTexture(fileName, left, right, width)
	local texture = castingBar.frame:CreateTexture()
	texture:SetTexture(fileName);
	texture:SetTexCoord(left, right, 0, 1)
	texture:SetSize(width, CASTINGBAR_HEIGHT)
	return texture
end

local function buildTexture(fileName, width)
	local middle = createTexture(fileName, FRAGMENT_WIDTH, FRAGMENT_WIDTH, width)
	middle:SetPoint("TOP", 0, 28)

	local left = createTexture(fileName, 0, FRAGMENT_WIDTH, CUT_WIDTH)
	left:SetPoint("RIGHT", middle, "LEFT")
	middle.Left = left

	local right = createTexture(fileName, RIGHT_EDGE_START, 1, CUT_WIDTH)
	right:SetPoint("LEFT", middle, "RIGHT")
	middle.Right = right

	return middle
end

local function updateVisibility(source, ...)
	for i = 1, select('#', ...) do
		local dest = select(i, ...)
		if source:IsVisible() then
			dest:Show()
		else
			dest:Hide()
		end
		dest:SetAlpha(source:GetAlpha())
	end
end

local function setStatusBarColor()
	local useClassColors = addon.db.profile.useClassColors
	if not useClassColors:find("None") then
		local _, class
		if useClassColors:find("or") then
			_, class = UnitClass("target")
			if not class then
				_, class = UnitClass("player")
			end
		elseif useClassColors:find("Target") then
			_, class = UnitClass("target")
		elseif useClassColors:find("Player") then
			_, class = UnitClass("player")
		end
		if class then
			local color = RAID_CLASS_COLORS[class]
			castingBar.frame:SetStatusBarColor(color.r, color.g, color.b)
		end
	end
end

local function setIconAndTimePositions(frame, position)
	frame:ClearAllPoints()

	local parent, x, y = castingBar.frame, -10, 3
	local isTime = frame == parent.Time

	if isTime then
		if not position:find("Outer") then
			x = addon.db.profile.hideTotalTime and 30 or 60
			y = position:find("Bottom") and -18 or position:find("Top") and 20 or y
		elseif not addon.db.profile.hideIcon and not addon.db.profile.hideTime then
			local isPosEqual = addon.db.profile.timePosition:find(addon.db.profile.iconPosition)
			if isPosEqual then
				parent, x, y = parent.icon, -5, 0
			end
		end
	end

	if position:find("Left") then
		frame:SetPoint("RIGHT", parent, "LEFT", x, y)
	elseif position:find("Right") then
		frame:SetPoint("LEFT", parent, "RIGHT", x * -1, y)
	end
end

local function setIcon(castingBar, texture)
	if texture and not addon.db.profile.hideIcon then
		castingBar.Icon:SetTexture(texture)
		setIconAndTimePositions(castingBar.Icon, addon.db.profile.iconPosition)
		castingBar.Icon:Show()
	else
		castingBar.Icon:Hide()
	end
end

local function setTime(castingBar)
	if not addon.db.profile.hideTime then
		setIconAndTimePositions(castingBar.Time, addon.db.profile.timePosition)
		castingBar.Time:Show()
	else
		castingBar.Time:Hide()
	end
end

local function getWidth()
	return addon.db.profile.width, addon.db.profile.width - CUT_WIDTH/2
end

local function setWidth(castingBar)
	local width, textWidth = getWidth()
	castingBar.Border:SetWidth(textWidth)
	castingBar.Flash:SetWidth(textWidth)
	castingBar:SetWidth(width)
end

local function onEvent(self, event, ...)
	setWidth(self)

	self.BorderShield:Hide()

	CastingBarFrame_OnEvent(self, event, ...)

	updateVisibility(self.Border, self.Border.Left, self.Border.Right)
	updateVisibility(self.Flash, self.Flash.Left, self.Flash.Right)

	if self.casting or self.channeling then
		setStatusBarColor()
	end

	if self.unit then
		local texture
		if self.casting then
			texture = select(4, UnitCastingInfo(self.unit))
		elseif self.channeling then
			texture = select(4, UnitChannelInfo(self.unit))
		end
		setIcon(self, texture)
		setTime(self)
	end

	DefaultCastingBar_DragFrame:Hide()
end

local function onUpdate(self, elapsed)
	CastingBarFrame_OnUpdate(self, elapsed)

	updateVisibility(self.Border, self.Border.Left, self.Border.Right)
	updateVisibility(self.Flash, self.Flash.Left, self.Flash.Right)

	if self.casting then
		local value = self.maxValue - self.value
		if not addon.db.profile.hideTotalTime then
			self.Time:SetFormattedText("%.1f/%.1f", value, self.maxValue)
		else
			self.Time:SetFormattedText("%.1f", value)
		end
	elseif self.channeling then
		self.Time:SetFormattedText("%.1f", self.value)
	end
end

function castingBar:OnInitialize()
	local name = self.frame:GetName()

	local width, textWidth = getWidth()

	self.frame.Border:Hide()
	self.frame.Border:ClearAllPoints()

	self.frame.BorderShield:Hide()
	self.frame.BorderShield:ClearAllPoints()

	self.frame.Flash:Hide()
	self.frame.Flash:ClearAllPoints()

	local border = buildTexture([[Interface\CastingBar\UI-CastingBar-Border]], textWidth)
	self.frame.Border = border

	local flash = buildTexture([[Interface\CastingBar\UI-CastingBar-Flash]], textWidth)
	flash:SetBlendMode("ADD")
	self.frame.Flash = flash

	self.frame.Time = self.frame:CreateFontString(nil, "ARTWORK", "GameFontHighlight")

	self.frame.Icon:SetSize(22, 22)
	self.frame.Icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)

	self.frame:SetPoint("CENTER", DefaultCastingBar_DragFrame)
	self.frame:SetSize(width, addon.barMaxHeight)
	self.frame:Hide()

	self.frame:SetScript("OnUpdate", onUpdate)
	self.frame:SetScript("OnEvent", onEvent)
end

CastingBarFrame:UnregisterAllEvents()
CastingBarFrame:Hide()