--	ArcaneBar
--	 	Adds a second casting bar to the player frame.
--
--	By: Zlixar
--
--	Adds a second casting bar to the player frame.
--
--	Modified by Nymbia for Nymbia's Perl Unitframes

-----------------------------
-- Configuration Functions --
-----------------------------

local ArcaneBars = {}

-- Registers frame to spellcast events.

local XPerl_ArcaneBar_Colors = {
	main = {r = 1.0, g = 0.7, b = 0.0},
	channel = {r = 0.0, g = 1.0, b = 0.0},
	success = {r = 0.0, g = 1.0, b = 0.0},
	failure = {r = 1.0, g = 0.0, b = 0.0}
}

local events = {"UNIT_SPELLCAST_START", "UNIT_SPELLCAST_STOP", "UNIT_SPELLCAST_FAILED", "UNIT_SPELLCAST_INTERRUPTED",
		"UNIT_SPELLCAST_DELAYED", "UNIT_SPELLCAST_CHANNEL_START", "UNIT_SPELLCAST_CHANNEL_UPDATE",
		"UNIT_SPELLCAST_CHANNEL_STOP", "PLAYER_ENTERING_WORLD"}

function XPerl_ArcaneBar_Register(self)
	for i,event in pairs(events) do
		self:RegisterEvent(event)
	end
	self:SetScript("OnUpdate", XPerl_ArcaneBar_OnUpdate)
	if (self.unit == "target") then
		self:RegisterEvent("PLAYER_TARGET_CHANGED")
	elseif (self.unit == "focus") then
		self:RegisterEvent("PLAYER_FOCUS_CHANGED")
	elseif (strmatch(self.unit, "party")) then
		self:RegisterEvent("UNIT_TARGET")
	end
end

-- Unregisters from spellcast events.
function XPerl_ArcaneBar_Unregister(self)
	for i,event in pairs(events) do
		self:UnregisterEvent(event)
	end
	self:SetScript("OnUpdate", nil)
end

-- XPerl_ArcaneBar_EnableToggle
function XPerl_ArcaneBar_EnableToggle(self, value)
	if (value == 1) then
		if (self.Enabled ~= 1) then
			XPerl_ArcaneBar_Register(self)
			self.Enabled = 1
		end
	else
		if (self.Enabled == 1) then
			XPerl_ArcaneBar_Unregister(self)
			self.Enabled = 0
			self:Hide()
		end
	end
end

-- XPerl_ArcaneBar_OverrideToggle
function XPerl_ArcaneBar_OverrideToggle(value)
	if (value == 1) then
		if (ArcaneBars.player and ArcaneBars.player.bar.Overrided ~= 1) then
			for i,event in pairs(events) do
				CastingBarFrame:UnregisterEvent(event)
			end
			ArcaneBars.player.bar.Overrided = 1
		end
	else
		if (ArcaneBars.player and ArcaneBars.player.bar.Overrided == 1) then
			for i,event in pairs(events) do
				CastingBarFrame:RegisterEvent(event)
			end
			ArcaneBars.player.bar.Overrided = 0
		end
	end
end

--------------------------------------------------
--
-- Event/Update Handlers
--
--------------------------------------------------

-- XPerl_ArcaneBar_OnEvent
function XPerl_ArcaneBar_OnEvent(self, event, newarg1)
	if (event == "PLAYER_ENTERING_WORLD" or event == "PLAYER_TARGET_CHANGED" or event == "PLAYER_FOCUS_CHANGED" or (event == "UNIT_TARGET" and arg1 == self.unit)) then
		local nameChannel  = UnitChannelInfo(self.unit)
		local nameSpell  = UnitCastingInfo(self.unit)
		if ( nameChannel ) then
			event = "UNIT_SPELLCAST_CHANNEL_START"
			newarg1 = self.unit
		elseif ( nameSpell ) then
			event = "UNIT_SPELLCAST_START"
			newarg1 = self.unit
		else
			self:Hide()
			local castTimeText = getglobal(self:GetName().."_CastTime")
			local barParentName = getglobal(self:GetParent():GetName().."_NameBarText") or getglobal(self:GetParent():GetName().."Text")
			castTimeText:Hide()
			barParentName:SetAlpha(XPerlConfig.TextTransparency)
			barParentName:Show()
		end
	end

	if (newarg1 ~= self.unit) then
		return
	end

	local castTimeText = getglobal(self:GetName().."_CastTime")
	local barSpark = getglobal(self:GetName().."Spark")
	local spellText = getglobal(self:GetName().."_Spell")
	local barParentName = getglobal(self:GetParent():GetName().."_NameBarText") or getglobal(self:GetParent():GetName().."Text")
	local barFlash = getglobal(self:GetName().."Flash")

	if (event == "UNIT_SPELLCAST_START") then
		local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill = UnitCastingInfo(self.unit)
		if ( not name or (not self.showTradeSkills and isTradeSkill)) then
			self:Hide()
			return
		end

		self:SetStatusBarColor(XPerl_ArcaneBar_Colors.main.r, XPerl_ArcaneBar_Colors.main.g, XPerl_ArcaneBar_Colors.main.b, XPerlConfig.Transparency)
		spellText:SetText(name)
		barParentName:Hide()
		barSpark:Show()
		self.startTime = startTime / 1000
		self.maxValue = endTime / 1000
		self:SetMinMaxValues(self.startTime, self.maxValue)
		self:SetValue(self.startTime)
		self:SetAlpha(0.8)
		self.holdTime = 0
		self.casting = 1
		self.channeling = nil
		self.fadeOut = nil
		self.flash = nil
		self:Show()
		self.delaySum = 0
		if XPerlConfig.CastTime==1 then
			castTimeText:Show()
		else
			castTimeText:Hide()
		end

	elseif ((event == "UNIT_SPELLCAST_STOP" and self.casting) or (event == "UNIT_SPELLCAST_CHANNEL_STOP" and self.channeling)) then
		self.delaySum = 0
		self.sign = "+"
		if (not self.casting) then
			castTimeText:Hide()
		end
		if ( not self:IsVisible() ) then
			self:Hide()
		end
		if ( self:IsShown() ) then
			self:SetValue(self.maxValue)
			self:SetStatusBarColor(XPerl_ArcaneBar_Colors.success.r, XPerl_ArcaneBar_Colors.success.g, XPerl_ArcaneBar_Colors.success.b, XPerlConfig.Transparency)
			barSpark:Hide()
			barFlash:SetAlpha(0.0)
			barFlash:Show()
			self.casting = nil
			self.channeling = nil
			if (not self.fadeOut or event == "UNIT_SPELLCAST_CHANNEL_STOP") then
				self.flash = 1
			end
			self.fadeOut = 1
			self.holdTime = 0
		end

	elseif (event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED") then
		if (this:IsShown()) then
			if (event == "UNIT_SPELLCAST_FAILED") then
				spellText:SetText(FAILED)
			else
				spellText:SetText(SPELL_FAILED_INTERRUPTED)
			end

			self:SetValue(self.maxValue)
			self:SetStatusBarColor(XPerl_ArcaneBar_Colors.failure.r, XPerl_ArcaneBar_Colors.failure.g, XPerl_ArcaneBar_Colors.failure.b, XPerlConfig.Transparency)
			barSpark:Hide()
			self.casting = nil
			self.channeling = nil
			if (not self.fadeOut) then
				self.flash = 1
			end
			self.fadeOut = 1
			self.holdTime = GetTime() + CASTING_BAR_HOLD_TIME
		end

	elseif (event == "UNIT_SPELLCAST_DELAYED") then
		if (self:IsShown()) then
			local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill = UnitCastingInfo(self.unit)
			if ( not name or (not self.showTradeSkills and isTradeSkill)) then
				-- if there is no name, there is no bar
				self:Hide()
				return;
			end
			self.startTime = startTime / 1000
			self.maxValue = endTime / 1000
			self:SetMinMaxValues(self.startTime, self.maxValue)
		end

	elseif ( event == "UNIT_SPELLCAST_CHANNEL_START" ) then
		local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill = UnitChannelInfo(self.unit)
		if ( not name or (not self.showTradeSkills and isTradeSkill)) then
			-- if there is no name, there is no bar
			self:Hide()
			return
		end

		self:SetStatusBarColor(XPerl_ArcaneBar_Colors.channel.r, XPerl_ArcaneBar_Colors.channel.g, XPerl_ArcaneBar_Colors.channel.b, XPerlConfig.Transparency)
		barSpark:Show()
		barParentName:Hide()
		spellText:SetText(name)
		self.maxValue = 1
		self.startTime = startTime / 1000
		self.endTime = endTime / 1000
		this.duration = this.endTime - this.startTime
		self:SetMinMaxValues(self.startTime, self.endTime)
		self:SetValue(self.endTime)
		self:SetAlpha(1.0)
		self.holdTime = 0
		self.casting = nil
		self.channeling = 1
		self.fadeOut = nil
		self.flash = nil
		self:Show()
		self.delaySum = 0
		if XPerlConfig.CastTime==1 then
			castTimeText:Show()
		else
			castTimeText:Hide()
		end

	elseif ( event == "UNIT_SPELLCAST_CHANNEL_UPDATE" ) then
		if (self:IsShown()) then
			local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill = UnitChannelInfo(self.unit)
			if ( not name or (not self.showTradeSkills and isTradeSkill)) then
				-- if there is no name, there is no bar
				self:Hide()
				return;
			end
			self.startTime = startTime / 1000
			self.endTime = endTime / 1000
			self.maxValue = self.startTime
			self:SetMinMaxValues(self.startTime, self.endTime)
		end
	else
		self.delaySum = 0
		self.sign = "+"
		castTimeText:Hide()
	end

	if (not self:IsShown()) then
		castTimeText:Hide()
		barParentName:SetAlpha(XPerlConfig.TextTransparency)
		barParentName:Show()
	end
end

-- XPerl_ArcaneBar_OnUpdate
function XPerl_ArcaneBar_OnUpdate(self)
	local barSpark = getglobal(self:GetName().."Spark")
	local barFlash = getglobal(self:GetName().."Flash")
	local castTimeText = getglobal(self:GetName().."_CastTime")
	local barParentName = getglobal(self:GetParent():GetName().."_NameBarText") or getglobal(self:GetParent():GetName().."Text")

	local current_time = self.maxValue - GetTime()
	if (self.channeling) then
		current_time = self.endTime - GetTime()
	end

	local text = string.sub(math.max(current_time,0)+0.001,1,4)
	if (self.delaySum and self.delaySum ~= 0) then
		local delay = string.sub(math.max(self.delaySum/1000, 0)+0.001,1,4)

		if (self.channeling == 1) then
			self.sign = "-"
		else
			self.sign = "+"
		end
		text = "|cffcc0000"..self.sign..delay.."|r "..text
	end
	castTimeText:SetText(text)

	if ( self.casting ) then
		local status = GetTime()
		if ( status > self.maxValue ) then
			status = self.maxValue

			self.casting = nil
			barFlash:SetAlpha(0.0)
			barFlash:Show()
			if (not self.fadeOut) then
				self.flash = 1
			end
			self.holdTime = 0
			self.fadeOut = 1
			return
		end
		self:SetValue(status)
		barFlash:Hide()

		local sparkPosition = ((status - self.startTime) / (self.maxValue - self.startTime)) * self:GetWidth()
		if ( sparkPosition < 0 ) then
			sparkPosition = 0
		end
		barSpark:SetPoint("CENTER", self, "LEFT", sparkPosition, 1)

	elseif ( self.channeling ) then
		local time = GetTime()
		if ( time > self.endTime ) then
			time = self.endTime
		end
		if ( time == self.endTime ) then
			self.channeling = nil
			barFlash:SetAlpha(0.0)
			barFlash:Show()
			if (not self.fadeOut) then
				self.flash = 1
			end
			self.holdTime = 0
			self.fadeOut = 1
			return
		end
		local barValue = self.startTime + (self.endTime - time)
		self:SetValue( barValue )
		barFlash:Hide()

		local sparkPosition = ((barValue - self.startTime) / (self.endTime - self.startTime)) * self:GetWidth()
		barSpark:SetPoint("CENTER", self, "LEFT", sparkPosition, 1)

	elseif ( GetTime() < self.holdTime ) then
		return

	elseif ( self.flash ) then
		local alpha = barFlash:GetAlpha() + CASTING_BAR_FLASH_STEP
		if ( alpha < 1 ) then
			barFlash:SetAlpha(alpha)
		else
			self.flash = nil
		end
	elseif ( self.fadeOut ) then
		local alpha = self:GetAlpha() - CASTING_BAR_ALPHA_STEP
		if ( alpha > 0 ) then
			self:SetAlpha(alpha)
			barParentName:SetAlpha((1 - alpha) * XPerlConfig.TextTransparency)
			barParentName:Show()
		else
			self.fadeOut = nil
			self:Hide()
		end
	end

	if (not self:IsShown()) then
		castTimeText:Hide()
		barParentName:SetAlpha(XPerlConfig.TextTransparency)
		barParentName:Show()
	end
end

-- XPerl_ArcaneBar_OnLoad
function XPerl_ArcaneBar_OnLoad(self)
	local barFlashTex = getglobal(self:GetName().."FlashTex")
	local barTex = getglobal(self:GetName().."Tex")

	barFlashTex:SetTexture("Interface\\AddOns\\XPerl\\Images\\XPerl_ArcaneBarFlash")
	barTex:SetTexture("Interface\\AddOns\\XPerl\\Images\\XPerl_StatusBar")
	self.casting = nil
	self.holdTime = 0
	self.Enabled = 0
	self.Overrided = 0

	XPerl_RegisterBar(self)
end

-- XPerl_ArcaneBar_Set
function XPerl_ArcaneBar_Set()

	if (XPerlConfig) then
		for k,v in pairs(ArcaneBars) do
			XPerl_ArcaneBar_EnableToggle(v.bar, XPerlConfig[v.opt])
		end

		if (XPerlConfig.OldCastBar == 0) then
			XPerl_ArcaneBar_OverrideToggle(1)
		else
			XPerl_ArcaneBar_OverrideToggle(0)
		end
	end
end

-- XPerl_ArcaneBar_RegisterFrame
function XPerl_ArcaneBar_RegisterFrame(frame, unit, optionName)

	local function Setup(self, unit, sts)
		self.unit = unit
		self.showTradeSkills = sts

		self:SetPoint("TOPLEFT", 4, -4)
		self:SetPoint("BOTTOMRIGHT", -4, 4)
	end

	local frameName = "StatusBar"..frame:GetName().."ArcaneBar"
	local newFrame = getglobal(frameName)
	if (not newFrame) then
		newFrame = CreateFrame("StatusBar", frameName, frame, "XPerl_ArcaneBarTemplate")
	end

	Setup(newFrame, unit, true)

	ArcaneBars[unit] = {bar = newFrame, opt = optionName}

	XPerl_ArcaneBar_Set()
end
