
local _
local CUI = CUI
local A = CreateFrame("Frame")

local CUI_AURA_SIZE, CUI_AURA_MARGIN, CUI_BUFF_PER_ROW, CUI_BUFF_NUM_PLAYER, CUI_DEBUFF_NUM_PLAYER, CUI_AURA_TYPES

CUI_AURA_SIZE 				= 32 -- X and Y size
CUI_AURA_MARGIN 			= 5 -- Margin between buffs in px
CUI_BUFF_PER_ROW 			= 8
CUI_BUFF_NUM_PLAYER 		= 32
CUI_DEBUFF_NUM_PLAYER 		= 16
CUI_AURA_TYPES 				= {"Buff", "Debuff"}

local function UpdateAuraBorderColor(self, r, g, b)

	local ButtonName, ButtonBorder, Button
	
	ButtonName = E:GetFullFrameName(self)
	Button = _G[ButtonName]
	
	Button.border:SetVertexColor(r,g,b)
end

function A:InitializeAnchors()
	local Frame = E:NewFrame("Frame", "BuffAnchor", "LOW", 300,120, {"TOPRIGHT", E.Parent, "TOPRIGHT"}, E.Parent)
	E:MoveFrame(Frame, -200, -50)
	local Frame = E:NewFrame("Frame", "DebuffAnchor", "LOW", 300,120, {"TOPRIGHT", E.Parent, "TOPRIGHT"}, E.Parent)
	E:MoveFrame(Frame, -200, -180)
	local Frame = E:NewFrame("Frame", "TargetAuraAnchor", "LOW", 300,120, {"TOPRIGHT", E.Parent, "TOPRIGHT"}, E.Parent)
	E:MoveFrame(Frame, -200, -180)
end

local function AuraAttributeChanged(button, value)
	if value == "index" and button.auraIndex then
		
		local header = button:GetParent()
		local filter = header:GetAttribute("filter")
		if not filter then filter = _ end
		--local name, rank, icon, count = UnitBuff("player", self.index)
		local name, _, texture, count, dtype, duration, expirationTime = UnitAura(button.unit, button.auraIndex, filter)
		button.texture:SetTexture(texture)
		
		if filter == "HARMFUL" then
				UpdateAuraBorderColor(button,0.85,0,0)
				button.border:Show()
			else
				button.border:Hide()
				UpdateAuraBorderColor(button,1,1,1)
			end
			
		local font = "FRIZQT__.TTF"
		
		
		button.time:ClearAllPoints()
		button.time:SetPoint("BOTTOM", button, 'BOTTOM', header:GetAttribute("xTimeOffset"), header:GetAttribute("yTimeOffset"))
		
		if duration == 0 then
			button.time:SetText("")
		end
		
		button:SetScript("OnUpdate", function(self, elapsed)
			local rangeTimer = self.rangeTimer;
			local timeLeftBase, timeLeft
			
	
			if ( rangeTimer ) then
				rangeTimer = rangeTimer - elapsed;

				if ( rangeTimer <= 0 ) then
					--------------------------------------------------------------
					-- OnUpdate Code BEGIN
					
					if duration ~= 0 and expirationTime ~= nil then
						local timeLeftBase = E:Round(GetTime() - expirationTime)
						local suffix = "s"
						if timeLeftBase < 0 then
							timeLeftBase = timeLeftBase * -1
						end
						if timeLeftBase > 60 then
							suffix = "m"
							timeLeft = timeLeftBase / 60
						end
						if timeLeftBase > 3600 then
							suffix = "h"
							timeLeft = timeLeftBase / 3600
						end
						if timeLeftBase > (3600*24) then
							suffix = "d"
							timeLeft = timeLeftBase / (3600*24)
						end
						
						if not timeLeft then timeLeft = timeLeftBase end
						
						self.time:SetText(E:Round(timeLeft) .. suffix)
					end
				
					if tonumber(count) and tonumber(count) <= 0 then count = "" end
					self.count:SetText(count)
					
					-- OnUpdate Code END
					--------------------------------------------------------------
					rangeTimer = 0.1;
				end

				self.rangeTimer = rangeTimer;
			end
		end)
	end
end


function CUI:CreateIcon(button)

	-- This method gets called when a new button was created automatically by the "SecureAuraHeaderTemplate" attribute "template".
	-- The template is simply an XML construct with several initial data for the frame.
	-- Right here, we can do all sort of "post-processing" for that frame(s).
	-- @TODO
	-- 		Make the method more dynamic and allow aura bars to be created through it.
	--		Maybe a simple bool?

	local font = "FRIZQT__.TTF"
	
	button.texture = button:CreateTexture(nil, "BORDER")
	button.texture:SetTexCoord(0,1,0,1)
	
	button.texture:SetAllPoints(button)

	button.count = button:CreateFontString(nil, "ARTWORK")
	E:InitializeFontFrame(button.count, "ARTWORK", font, 14, {1,1,1}, 1, {0,0}, "", 32, 32, button, "BOTTOMRIGHT", {1,1})
	button.count:ClearAllPoints()
	button.count:SetPoint("BOTTOMRIGHT", button, 'BOTTOMRIGHT', 5, -5)

	button.time = button:CreateFontString(nil, "ARTWORK")
	E:InitializeFontFrame(button.time, "ARTWORK", font, 11, {1,0.96,0.41}, 1, {0,-100}, "", 32, 32, button, "CENTER", {1,1})
	button.time:ClearAllPoints()
	
	button.time:SetPoint("BOTTOM", button, 'BOTTOM', 0, -20)
	button:SetScript("OnUpdate", function() end)
	button.rangeTimer = 0

	button.highlight = button:CreateTexture(nil, "HIGHLIGHT")
	button.highlight:SetColorTexture(1, 1, 1, 0.45)

	-- This Script gets called every time a aura changed/was added or removed.
	-- We can use this to update the whole thing and its children.
	button:SetScript("OnAttributeChanged", AuraAttributeChanged)
	button.border:Hide()
	-- Unfortunately, we have already created the button. Now, there's a aura that wants to be shown.
	-- But this would happen just when the next "OnAttributeChanged" fires. So we have to force the update.
	-- We'll do this in the UpdateHeaderAuras method.
end

-- Target to store auras in
local auraframes = {}

function A:UpdateHeader(header)
	-- By setting the template, everything starts.
	-- The buttons are being created by the secure aura header
	-- To be exact, it reads the set filter and calculates the number of total auras to display.
	-- Based on that, A:CreateIcon() gets called by the OnLoad handler of the template.
	-- This way, we can modify the auras however we want to.
	-- We simply need different headers for multiple aura bars.
	-- That said, a frame with the "SecureAuraHeaderTemplate" simply needs to be created. Followed by the SetAttribute("template") or SetAttribute("weaponTemplate")
	-- Maybe XML proves to be not that bad.
	
	header:SetAttribute("consolidateTo", 0)
	header:SetAttribute('weaponTemplate', ("CUIAuraTemplate%d"):format(self.db.size))

	header:SetAttribute("separateOwn", 1)
	header:SetAttribute("sortMethod", "INDEX")
	header:SetAttribute("sortDirection", "+")
	header:SetAttribute("maxWraps", 5)
	header:SetAttribute("wrapAfter", 10)

	header:SetAttribute("point", "TOPRIGHT")

		header:SetAttribute("minWidth", 32)
		header:SetAttribute("minHeight", 32)
		header:SetAttribute("xOffset", -35)
		header:SetAttribute("yOffset", 0)
		header:SetAttribute("wrapXOffset", 0)
		header:SetAttribute("wrapYOffset", -50)

	header:SetAttribute("template", ("CUIAuraTemplate%d"):format(self.db.size))
end

function A:UpdateHeaderAuras(header)
	
	-- Run Update two times, since one isn't enough for auras...
	local unit = header:GetAttribute("unit")
	local filter = header:GetAttribute("filter")
	
	header:SetAttribute("template", ("CUIAuraTemplate%d"):format(self.db.size))
	local index = 1
	local child = select(index, header:GetChildren())
	while(child) do
		if((floor(child:GetWidth() * 100 + 0.5) / 100) ~= self.db.size) then
			child:SetSize(self.db.size, self.db.size)
		end
		
		child:SetAttribute("index", index)
		child.auraIndex = index
		child.unit = unit
		
		-- We have to force an update for the current child...
		-- Otherwise, there would be an empty box until the next event fires
		AuraAttributeChanged(child, "index")
		
		index = index + 1
		child = select(index, header:GetChildren())
	end
	
	-- If unit is enemy and we actually have created aura buttons
	if index ~= 1 and unit ~= "player" then
		if filter == "HELPFUL" then
			header:SetAttribute("hasBuffs", true)
			if not UnitIsFriend(unit, "player") and index ~= 1 then
				header:SetPoint("TOPRIGHT", E.Frames["TargetMainFrame"], "TOPRIGHT", 40, 20)
			else
				header:SetPoint("TOPRIGHT", E.Frames["TargetMainFrame"], "TOPRIGHT", 40, -30)
			end
		else
			header:SetAttribute("hasDebuffs", true)
			if not UnitIsFriend(unit, "player") and index ~= 1 then
				header:SetPoint("TOPRIGHT", E.Frames["TargetMainFrame"], "TOPRIGHT", 40, -30)
			else
				header:SetPoint("TOPRIGHT", E.Frames["TargetMainFrame"], "TOPRIGHT", 40, 20)
			end
		end
	end
end

local function CreatePlayerAuraHeader(filter)
	local name = "CUIPlayerDebuffs"
	if filter == "HELPFUL" then name = "CUIPlayerBuffs" end
	
	local header = CreateFrame("Frame", name, E.Parent, "SecureAuraHeaderTemplate")
	header:SetClampedToScreen(true)
	header:SetAttribute("unit", "player")
	header:SetAttribute("filter", filter)
	RegisterStateDriver(header, "visibility", "[petbattle] hide; show")
	RegisterAttributeDriver(header, "unit", "[vehicleui] vehicle; player")

	if filter == "HELPFUL" then
		header:SetAttribute('consolidateDuration', -1)
		header:SetAttribute("includeWeapons", 1)
	end
	
	header:SetAttribute("xTimeOffset", 0)
	header:SetAttribute("yTimeOffset", -20)
	
	A:UpdateHeader(header)

	return header
end

local function CreateUnitAuraHeader(unit, filter)
	local name = "CUIUnitDebuffs"
	if filter == "HELPFUL" then name = "CUIUnitBuffs" end
	
	local header = CreateFrame("Frame", name, E.Parent, "SecureAuraHeaderTemplate")
	header:SetClampedToScreen(true)
	header:SetAttribute("unit", unit)
	header:SetAttribute("filter", filter)
	--RegisterUnitWatch(header)
	RegisterStateDriver(header, "visibility", "show")
	RegisterAttributeDriver(header, "unit", unit)

	header:SetAttribute('consolidateDuration', -1)
	header:SetAttribute("includeWeapons", 1)
	
	header:SetAttribute("xTimeOffset", 0)
	header:SetAttribute("yTimeOffset", 20)
	
	A:UpdateHeader(header)

	return header
end

function A:InitializeAuras()
	self.BuffFrame = CreatePlayerAuraHeader("HELPFUL")
	self.BuffFrame:SetPoint("TOPRIGHT", E.Parent, "TOPRIGHT", -185, -35)

	self.DebuffFrame = CreatePlayerAuraHeader("HARMFUL")
	self.DebuffFrame:SetPoint("TOPRIGHT", E.Parent, "TOPRIGHT", -185, -120)
	
	self.UnitBuffFrame = CreateUnitAuraHeader("target", "HELPFUL")
	self.UnitBuffFrame:SetPoint("TOPRIGHT", E.Frames["TargetMainFrame"], "TOPRIGHT", 40, -30)
	
	self.UnitDebuffFrame = CreateUnitAuraHeader("target", "HARMFUL")
	self.UnitDebuffFrame:SetPoint("TOPRIGHT", E.Frames["TargetMainFrame"], "TOPRIGHT", 40, 20)
end

function A:Init()
	
	self.db = CUI.db.profile.auras
	
	A:InitializeAuras()
end

A:RegisterEvent("UNIT_AURA")
A:RegisterEvent("PLAYER_ENTERING_WORLD")
A:RegisterEvent("PLAYER_TARGET_CHANGED")

A:SetScript("OnEvent", function(self, event, ...)
	if event == "UNIT_AURA" or event == "PLAYER_ENTERING_WORLD" then A:UpdateHeaderAuras(_G["CUIPlayerBuffs"]); A:UpdateHeaderAuras(_G["CUIPlayerDebuffs"]); A:UpdateHeaderAuras(_G["CUIUnitBuffs"]); A:UpdateHeaderAuras(_G["CUIUnitDebuffs"]) end
	if event == "PLAYER_TARGET_CHANGED" then A:UpdateHeaderAuras(_G["CUIUnitBuffs"]); A:UpdateHeaderAuras(_G["CUIUnitDebuffs"]) end
end)

CUI:AddModule("Auras", A)