local Loc = LibStub ("AceLocale-3.0"):GetLocale ("Details")

--> Main Plugin Object
local DpsTuningPlugin = _detalhes:NewPluginObject ("Details_DpsTuning")
--> Main Frame
local SDF = DpsTuningPlugin.Frame

--> global pointers
local ClockTime = time --> lua library local
local ipairs = ipairs --> lua library local
local pairs = pairs --> lua library local
local floor = floor --> lua library local
local _cstr = string.format --> lua library local

local GetSpellBonusDamage = GetSpellBonusDamage
local UnitAura = UnitAura --> wow api local
local GetTime = GetTime --> wow api local

local _GetSpellInfo =_detalhes.getspellinfo --> details api local

DpsTuningPlugin:SetPluginDescription ("Tool for testing your Dps showing detailed information for each spell, buffs and also graphical charts for abilities.")

local function CreatePluginFrames()

	--> get the framework
	local fw = _detalhes:GetFramework()
	
	--> player damage done chart code
	local string_player_damage_done = [[
	
		-- the goal of this script is get the current combat then get your character and extract your damage done.
		-- the first thing to do is get the combat, so, we use here the command "_detalhes:GetCombat ( "overall" "current" or "segment number")"
		
		local current_combat = _detalhes:GetCombat ("current") --> getting the current combat
		
		-- the next step is request your character from the combat
		-- to do this, we take the combat which here we named "current_combat" and tells what we want inside parentheses.
		
		local my_self = current_combat (DETAILS_ATTRIBUTE_DAMAGE, _detalhes.playername)
		
		-- _detalhes.playername holds the name of your character.
		-- DETAILS_ATTRIBUTE_DAMAGE means we want the damage table, _HEAL _ENERGY _MISC is the other 3 tables.
		
		-- before we proceed, the result needs to be checked to make sure its a valid result.
		
		if (not my_self) then
			return 0 -- the combat doesnt have *you*, this happens when you didn't deal any damage in the combat yet.
		end
		
		-- now its time to get the total damage.
		
		local my_damage = my_self.total
		
		-- then finally return the amount to the capture.
		
		return my_damage
		
	]]
	
	--> color for spell dps bars
	DpsTuningPlugin.BarColor = {.4, .4, .4, .7}
	
	function DpsTuningPlugin:OnDetailsEvent (event, ...)

		if (event == "SHOW") then --> plugin shown on screen, actived
		
			SDF:SetResizable (false) --> cant resize, this is a fixed size
			SDF:SetSize (300, 300) --> need to be 300x300 to fit details window

			--> create the frames on the first shown
			if (not DpsTuningPlugin.frames_created) then
				DpsTuningPlugin:BuildHeader()
				DpsTuningPlugin:BuildSpellBars()
				DpsTuningPlugin:BuildSummaryPanel()
				DpsTuningPlugin:BuildBuffBlocks()
				DpsTuningPlugin:BuildChartPanels()
				
				DpsTuningPlugin.frames_created = true
				DpsTuningPlugin.Frame:Show()
				
				--tricky, localize members inside the plugin, so it doesn't need to lookup on _detalhes object every time
				DpsTuningPlugin.playername = DpsTuningPlugin.playername
				DpsTuningPlugin.comma_value = DpsTuningPlugin.comma_value
				DpsTuningPlugin.ToK2 = DpsTuningPlugin.ToK2
				DpsTuningPlugin.Sort2 = DpsTuningPlugin.Sort2
				DpsTuningPlugin.Sort3 = DpsTuningPlugin.Sort3
			end
			
			--> we only want register the player damage done when the plugin is active
			DpsTuningPlugin:TimeDataRegister ("Player Damage Done", string_player_damage_done, nil, "Spell Details", "v1.0", "Interface\\Icons\\INV_Fabric_Spellweave", true, true)
			
		elseif (event == "HIDE") then --> plugin hidded, disabled
		
			--> plugin is gone, unregister the chart
			DpsTuningPlugin:TimeDataUnregister ("Player Damage Done")
		
		elseif (event == "DETAILS_STARTED") then
		
			--> triggered right after details finish run all ADDON_LOADED functions
			local power = {}
			for i = 1, 7 do
				power [i] = {i, GetSpellBonusDamage (i)}
			end
			table.sort (power, DpsTuningPlugin.Sort2)
			DpsTuningPlugin.PowerType = power [1][1]
		
		elseif (event == "REFRESH") then --> requested a refresh window
			--> refresh window happens when there is a invalid combat, like a combat with less then 5 seconds.
			--DpsTuningPlugin:Refresh()
		
		elseif (event == "COMBAT_PLAYER_ENTER") then
			DpsTuningPlugin:OnCombatStart (...)
			
		elseif (event == "COMBAT_INVALID") then
			--DpsTuningPlugin:Reset()
			--print ("eh invalido...")
			
		elseif (event == "COMBAT_PLAYER_LEAVE") then
			DpsTuningPlugin:OnCombatEnd (...)

		elseif (event == "PLUGIN_DISABLED") then
			--> plugin got disabled on details options panel
		
		elseif (event == "PLUGIN_ENABLED") then
			--> plugin got enabled on details options panel
		
		end
	end
	
	function DpsTuningPlugin.GetActivityTime (thisspell, time)
		if (thisspell.tempo_end) then --> o tempo do jogador esta trancado
			local t = thisspell.tempo_end - thisspell.start
			if (t < 6) then
				t = 6
			end
			return t
		elseif (thisspell.onhold) then
			local t = thisspell.delay - thisspell.start
			if (t < 6) then
				t = 6
			end
			return t
		else
			if (thisspell.start == 0) then
				return 6
			end
			local t = time - thisspell.start
			if (t < 6) then
				if (DpsTuningPlugin.in_combat) then
					local combat_time = DpsTuningPlugin.CurCombat:GetCombatTime()
					if (combat_time < 6) then
						return combat_time
					end
				end
				t = 6
			end
			return t
		end
	end
	
	local spells = {cur = 0}
	local spell_activity = {}
	local buff_activity = {}
	local buff_graphic_data = {}
	local spell_graphic_data = {}
	local power_amount_chart_table = {}
	power_amount_chart_table.max_value = 0
	
	DpsTuningPlugin.FinishedAt = 0
	
	function DpsTuningPlugin.RefreshSpells()
	
		if (DpsTuningPlugin.db.SpellBarsShowType == 1) then --> execution activity dps
	
			local now = ClockTime()
			for spellid, spelltable in pairs (DpsTuningPlugin.CurPlayer:GetActorSpells()) do

				local this = spell_activity [spellid]
				if (not this) then
					local t = {}
					t.total = spelltable.total
					t.time = ClockTime()
					t.start = t.time
					t.tempo_end = nil
					t.lastevent = t.time
					spell_activity [spellid] = t
					this = t
				else
					local lastdamage = this.total
					if (lastdamage ~= spelltable.total) then
						this.lastevent = now
					end
					
					if (this.lastevent+6 < now) then
						--hold
						if (not this.onhold) then
							this.delay = this.lastevent
							if (this.delay < this.start) then
								this.delay = this.start
							end
							this.onhold = true
						end
					else
						--exec
						if (this.onhold) then
							local diff = now - this.delay - 2
							if (diff > 0) then
								this.start = this.start + diff
							end
							this.onhold = nil
						end
					end
					
					this.total = spelltable.total
				end
			end

			local i = 0
			for spellid, spelltable in pairs (spell_activity) do
				i = i + 1
				
				if (not spells [i]) then
					spells [i] = {}
				end
				
				spells [i][1] = spellid
				spells [i][2] = spelltable.total
				spells [i][3] = DpsTuningPlugin.GetActivityTime (spelltable, now)
				spells [i][4] = spells [i][2] / spells [i][3] --adps
			end
			
			spells.cur = i
			for o = #spells, i+1, -1 do
				spells [o][1] = 0
				spells [o][2] = 0
				spells [o][3] = 0
				spells [o][4] = 0
			end
			
			table.sort (spells, DpsTuningPlugin.Sort4)
			
			DpsTuningPlugin.SpellList = spells
			DpsTuningPlugin.SpellScroll:Update()
			
		elseif (DpsTuningPlugin.db.SpellBarsShowType == 2) then --> player activity dps
			
			local player_time = DpsTuningPlugin.CurPlayer:Tempo()
			local i = 0
			
			for spellid, spelltable in pairs (DpsTuningPlugin.CurPlayer:GetActorSpells()) do
				i = i + 1
				
				if (not spells [i]) then
					spells [i] = {}
				end
				
				spells [i][1] = spellid
				spells [i][2] = spelltable.total
				spells [i][3] = spelltable.total/player_time
			end
			
			spells.cur = i
			for o = #spells, i+1, -1 do
				spells [o][1] = 0
				spells [o][2] = 0
				spells [o][3] = 0
				spells [o][4] = 0
			end
			
			table.sort (spells, DpsTuningPlugin.Sort3)
			
			DpsTuningPlugin.SpellList = spells
			DpsTuningPlugin.SpellScroll:Update()
			
		elseif (DpsTuningPlugin.db.SpellBarsShowType == 3) then --> spell damage
			
			local i = 0
			for spellid, spelltable in pairs (DpsTuningPlugin.CurPlayer:GetActorSpells()) do
				i = i + 1
			
				if (not spells [i]) then
					spells [i] = {}
				end
				
				spells [i][1] = spellid
				spells [i][2] = spelltable.total
			end
			
			spells.cur = i
			for o = #spells, i+1, -1 do
				spells [o][1] = 0
				spells [o][2] = 0
				spells [o][3] = 0
				spells [o][4] = 0
			end
			
			table.sort (spells, DpsTuningPlugin.Sort2)
			
			DpsTuningPlugin.SpellList = spells
			DpsTuningPlugin.SpellScroll:Update()
			
		end

	end
	
	function update_scroll (self)
	
		local spells = DpsTuningPlugin.SpellList
		if (not spells) then
			for bar_index = 1, 9 do 
				local bar = DpsTuningPlugin.SpellBars [bar_index]
				bar:Hide()
			end
			return
		end
	
		local offset = FauxScrollFrame_GetOffset (self)
		local amt = 0
		for index, spell in ipairs (spells) do
			if (spell[2] > 0) then
				amt = amt + 1
			end
		end
		
		for bar_index = 1, 9 do 
			local data = spells [bar_index + offset]
			local bar = DpsTuningPlugin.SpellBars [bar_index]

			if (DpsTuningPlugin.db.SpellBarsShowType == 1) then --> execution activity dps
			
				if (data and data[3] > 0) then
					local name, _, icon = _GetSpellInfo (data [1])
					bar.icon = icon
					bar.lefttext = name
					bar.righttext = DpsTuningPlugin:comma_value (data [2]) .. " (" .. data [3] .. ", " .. DpsTuningPlugin:ToK2 (floor (data [4])) .. ")"
					bar.spellid = data [1]
					bar:Show()
				else
					bar:Hide()
				end
				
			elseif (DpsTuningPlugin.db.SpellBarsShowType == 2) then --> player activity dps

				if (data and data[2] > 0) then
					local name, _, icon = _GetSpellInfo (data [1])
					bar.icon = icon
					bar.lefttext = name
					bar.righttext = DpsTuningPlugin:comma_value (data [2]) .. " (" .. DpsTuningPlugin:ToK2 (floor (data [3])) .. ")"
					bar.spellid = data [1]
					bar:Show()
				else
					bar:Hide()
				end
			
			elseif (DpsTuningPlugin.db.SpellBarsShowType == 3) then --> spell damage
			
				local total = DpsTuningPlugin.CurPlayer.total
			
				if (data and data[2] > 0) then
					local name, _, icon = _GetSpellInfo (data [1])
					bar.icon = icon
					bar.lefttext = name
					bar.righttext = DpsTuningPlugin:comma_value (data [2]) .. " (" .. floor (data[2] / total * 100) .. "%)"
					bar.spellid = data [1]
					bar:Show()
				else
					bar:Hide()
				end
				
			end
		end
		
		FauxScrollFrame_Update (self, amt, 9, 15)
		
	end
	
	function DpsTuningPlugin:BuildSummaryPanel()
	
		--total damage
		local damage1 = fw:CreateLabel (SDF, "Damage:")
		local damage2 = fw:CreateLabel (SDF, "")
		damage1:SetPoint ("topleft", SDF, "topleft", 2, -165)
		damage2:SetPoint ("left", damage1, "right", 2, 0)
		DpsTuningPlugin.total_damage = damage2
	
		--activity dps
		local a_dps1 = fw:CreateLabel (SDF, "Dps:")
		local a_dps2 = fw:CreateLabel (SDF, "")
		a_dps1:SetPoint ("topleft", SDF, "topleft", 2, -180)
		a_dps2:SetPoint ("left", a_dps1, "right", 2, 0)
		DpsTuningPlugin.activity_dps = a_dps2
		
		--timer
		local timer1 = fw:CreateLabel (SDF, "Time:")
		local timer2 = fw:CreateLabel (SDF, "")
		timer1:SetPoint ("topleft", SDF, "topleft", 2, -195)
		timer2:SetPoint ("left", timer1, "right", 2, 0)
		DpsTuningPlugin.time_elapsed = timer2
		
		--power
		local power1 = fw:CreateLabel (SDF, "Power:")
		local power2 = fw:CreateLabel (SDF, "", 15, "orange")
		power1:SetPoint ("topleft", SDF, "topleft", 2, -215)
		power2:SetPoint ("left", power1, "right", 2, 0)
		DpsTuningPlugin.power_amount = power2
	end
	
	function DpsTuningPlugin:BuildHeader()
		
		local on_select_spell_type = function (_, _, type_number)
			DpsTuningPlugin.db.SpellBarsShowType = type_number
			DpsTuningPlugin:UpdateTick()
		end
		
		local icon = [[Interface\COMMON\friendship-FistOrc]]
		
		local spell_type_options = {
			{value = 1, label = "Execution Activity Dps", desc = "Oder and show the dps following the spell individual activity time.", onclick = on_select_spell_type, icon = icon},
			{value = 2, label = "Player Activity Dps", desc = "Order the spells using your activity time to measure the dps for each spell.", onclick = on_select_spell_type, icon = icon},
			{value = 3, label = "Damage", desc = "Order the spells following the damage done by each one.", onclick = on_select_spell_type, icon = icon},
		}
		
		local select_spell_type = function()
			return spell_type_options
		end
		
		local dropdown = fw:CreateDropDown (SDF, select_spell_type, DpsTuningPlugin.db.SpellBarsShowType, 160, 18)
		local label = fw:CreateLabel (SDF, "Dps Format:")
		label:SetPoint (2, -4)
		dropdown:SetPoint ("left", label, "right", 2, -1)
	end
	
	DpsTuningPlugin.AuraBlocks = {}
	
	local aura_onenter = function (self, capsule)
		self:SetBackdropBorderColor (1, 1, 0, 1)
		capsule.icontexture.alpha = 1
		local buff = capsule.buff
		if (buff) then
			GameCooltip:Reset()
			GameCooltip:SetOwner (self)
			GameCooltip:SetType ("tooltip")
			DpsTuningPlugin:CooltipPreset (2)
			
			local name, _, icon = _GetSpellInfo (buff.spellid)
			
			GameCooltip:AddLine (name, "", 1, "orange", nil, 13, "Arrial Narrow")
			GameCooltip:AddIcon (icon)
			
			GameCooltip:AddLine ("")

			local minutos, segundos = floor (buff.uptime/60), floor (buff.uptime%60)
			GameCooltip:AddLine ("Uptime:", minutos .. "m " .. segundos .. "s", 1, "white", nil, 10, "Arrial Narrow")
			GameCooltip:AddLine ("Percent:", _cstr ("%.1f", buff.uptime/DpsTuningPlugin.CurPlayer:Tempo()*100) .. "%", 1, "white", nil, 10, "Arrial Narrow")
			
			GameCooltip:SetOption ("AlignAsBlizzTooltip", true)
			GameCooltip:Show()
		end
	end
	local aura_onleave = function (self, capsule)
		self:SetBackdropBorderColor (1, 1, 1, 1)
		capsule.icontexture.alpha = 0.9
		GameCooltip:Hide()
	end
	
	local aura_onenter2 = function (self, capsule)
		aura_onenter (capsule.block.widget, capsule.block)
	end
	local aura_onleave2 = function (self, capsule)
		aura_onleave (capsule.block.widget, capsule.block)
	end
	
	local AuraOnClick = function (block)
		if (block.buff) then
			block.buff.disabled = not block.buff.disabled
			if (block.buff.disabled) then
				block.X:Show()
			else
				block.X:Hide()
			end
		end
	end
	
	function DpsTuningPlugin:BuildBuffBlocks()
		
		local auras = fw:CreateLabel (SDF, "Auras (click to disable):")
		auras:SetPoint (170, -165)
		
		local coords = {0.1, 0.9, 0.1, 0.9}
		local size = 26
		local color = {.7, .7, .7}
		
		for i = 1, 3 do
			local block = fw:CreatePanel (SDF, 32, 32)
			block:SetFrameLevel (SDF:GetFrameLevel()+2)
			block:SetPoint (170 + ((i-1) * 36), -180)
			block:SetHook ("OnEnter", aura_onenter)
			block:SetHook ("OnLeave", aura_onleave)
			block.icontexture = fw:CreateImage (block, nil, size, size, "border", coords)
			block.icontexture:SetPoint ("center", block, "center")
			block.icontexture.alpha = 0.9
			block.icontexture:SetVertexColor (unpack (color))
			block.texttime = fw:CreateLabel (block, "", 16, "yellow", "GameFontNormal", nil, nil, "artwork")
			block.texttime:SetPoint ("center", block, "center")
			
			block.X = fw:CreateImage (block, [[Interface\Glues\LOGIN\Glues-CheckBox-Check]], size*1.1, size*1.1, "overlay")
			block.X:SetPoint ("center", block, "center")
			block.X:Hide()
			
			block.button = fw:CreateButton (block, AuraOnClick, 32, 32, "", block)
			block.button:SetPoint ("center", box, "center")
			block.button:SetHook ("OnEnter", aura_onenter2)
			block.button:SetHook ("OnLeave", aura_onleave2)
			block.button.block = block
			
			tinsert (DpsTuningPlugin.AuraBlocks, block)
		end
		
		for i = 1, 3 do
			local block = fw:CreatePanel (SDF, 32, 32)
			block:SetFrameLevel (SDF:GetFrameLevel()+2)
			block:SetPoint (170 + ((i-1) * 36), -220)
			block:SetHook ("OnEnter", aura_onenter)
			block:SetHook ("OnLeave", aura_onleave)
			block.icontexture = fw:CreateImage (block, nil, size, size, "border", coords)
			block.icontexture:SetPoint ("center", block, "center")
			block.icontexture.alpha = 0.9
			block.icontexture:SetVertexColor (unpack (color))
			block.texttime = fw:CreateLabel (block, "", 16, "yellow", "GameFontNormal", nil, nil, "artwork")
			block.texttime:SetPoint ("center", block, "center")
			
			block.X = fw:CreateImage (block, [[Interface\Glues\LOGIN\Glues-CheckBox-Check]], size*1.1, size*1.1, "overlay")
			block.X:SetPoint ("center", block, "center")
			block.X:Hide()
			
			block.button = fw:CreateButton (block, AuraOnClick, 32, 32, "", block)
			block.button:SetPoint ("center", box, "center")
			block.button:SetHook ("OnEnter", aura_onenter2)
			block.button:SetHook ("OnLeave", aura_onleave2)
			block.button.block = block
			
			tinsert (DpsTuningPlugin.AuraBlocks, block)
		end
		
		for i = 1, 3 do
			local block = fw:CreatePanel (SDF, 32, 32)
			block:SetFrameLevel (SDF:GetFrameLevel()+2)
			block:SetPoint (170 + ((i-1) * 36), -260)
			block:SetHook ("OnEnter", aura_onenter)
			block:SetHook ("OnLeave", aura_onleave)
			block.icontexture = fw:CreateImage (block, nil, size, size, "border", coords)
			block.icontexture:SetPoint ("center", block, "center")
			block.icontexture.alpha = 0.9
			block.icontexture:SetVertexColor (unpack (color))
			block.texttime = fw:CreateLabel (block, "", 16, "yellow", "GameFontNormal", nil, nil, "artwork")
			block.texttime:SetPoint ("center", block, "center")
			
			block.X = fw:CreateImage (block, [[Interface\Glues\LOGIN\Glues-CheckBox-Check]], size*1.1, size*1.1, "overlay")
			block.X:SetPoint ("center", block, "center")
			block.X:Hide()
			
			block.button = fw:CreateButton (block, AuraOnClick, 32, 32, "", block)
			block.button:SetPoint ("center", box, "center")
			block.button:SetHook ("OnEnter", aura_onenter2)
			block.button:SetHook ("OnLeave", aura_onleave2)
			block.button.block = block
			
			tinsert (DpsTuningPlugin.AuraBlocks, block)
		end
		
	end
	
	function DpsTuningPlugin:ClearBuffBlocks()
		for index, block in ipairs (DpsTuningPlugin.AuraBlocks) do
			block.buff = nil
			block.icontexture.texture = nil
			block.texttime.text = ""
		end
	end
	
	function DpsTuningPlugin:UpdateBuffBlocks()
		for index, block in ipairs (DpsTuningPlugin.AuraBlocks) do
			if (block.buff) then
				if (block.buff.actived) then
					block.texttime.text = block.buff.uptime + (ClockTime() - block.buff.actived_at)
				else
					block.texttime.text = block.buff.uptime
				end
			end
		end
	end
	
	function DpsTuningPlugin:EnableAuraBlock (block_number, buff_table)
		if (block_number <= 9) then
			local block = DpsTuningPlugin.AuraBlocks [block_number]
			block.icontexture.texture = select (3, _GetSpellInfo (buff_table.spellid))
			block.buff = buff_table
		end
	end
	
	function DpsTuningPlugin:TrackBuffsAtEnd()
		for buffIndex = 1, 41 do
			local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellid  = UnitAura ("player", buffIndex, nil, "HELPFUL")
			local buff_table = buff_activity [spellid]
			if (buff_table) then
				if (buff_table.actived_at and buff_table.actived) then
					buff_table.uptime = buff_table.uptime + ClockTime() - buff_table.actived_at
				end
				buff_table.actived = false
				buff_table.actived_at = nil
				DpsTuningPlugin:BuffChartEnd (spellid)
			end
		end
	end
	
	function DpsTuningPlugin:BuffChartStart (spellid)
		local buff_chart = buff_graphic_data [spellid]
		if (not buff_chart) then
			buff_chart = {}
			buff_graphic_data [spellid] = buff_chart
		end
		local bufftime = {time_start = DpsTuningPlugin.CurTick, time_end = 0}
		tinsert (buff_chart, bufftime)
	end
	
	function DpsTuningPlugin:BuffChartEnd (spellid)
		local buff_chart = buff_graphic_data [spellid]
		if (buff_chart) then
			local bufftime = buff_chart [#buff_chart]
			bufftime.time_end = DpsTuningPlugin.CurTick
		end
	end
	
	function DpsTuningPlugin:TrackBuffsAtStart()
		for buffIndex = 1, 41 do
			local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellid  = UnitAura ("player", buffIndex, nil, "HELPFUL")
			
			if (name and unitCaster == "player" and duration > 0 and expirationTime > 0 and not shouldConsolidate) then
				local buff_table = buff_activity [spellid]
				if (not buff_table) then
					buff_table = {uptime = 0, actived = false, activedamt = 0, block = buff_activity.next, spellid = spellid, procs = {}}
					buff_activity.next = buff_activity.next + 1
					buff_activity [spellid] = buff_table
				end
				
				buff_table.actived = true
				buff_table.activedamt = 1
				buff_table.actived_at = ClockTime()
				tinsert (buff_table.procs, DpsTuningPlugin.CurCombat:GetCombatTime())

				DpsTuningPlugin:BuffChartStart (spellid)
				DpsTuningPlugin:EnableAuraBlock (buff_table.block, buff_table)
			end
		end
	end
	
	
	function DpsTuningPlugin:AuraApplied (time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spellschool, tipo, amount)
		if (tipo == "BUFF") then
		
			local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellid  = UnitAura ("player", spellname, nil, "HELPFUL")
			
			if (name and unitCaster == "player" and duration > 0 and expirationTime > 0 and not shouldConsolidate) then

				local buff_table = buff_activity [spellid]
				if (not buff_table) then
					buff_table = {uptime = 0, actived = false, activedamt = 0, block = buff_activity.next, spellid = spellid, procs = {}}
					buff_activity.next = buff_activity.next + 1
					buff_activity [spellid] = buff_table
				end
				
				buff_table.actived = true
				buff_table.activedamt = buff_table.activedamt + 1
				buff_table.actived_at = ClockTime()
				tinsert (buff_table.procs, DpsTuningPlugin.CurCombat:GetCombatTime())
				
				DpsTuningPlugin:BuffChartStart (spellid)
				DpsTuningPlugin:EnableAuraBlock (buff_table.block, buff_table)
			
			end
		end
	end

	function DpsTuningPlugin:AuraRefresh (time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spellschool, tipo, amount)
		if (tipo == "BUFF") then
			local buff_table = buff_activity [spellid]
			if (buff_table) then
				if (buff_table.actived_at and buff_table.actived) then
					buff_table.uptime = buff_table.uptime + ClockTime() - buff_table.actived_at
				end
				buff_table.actived_at = ClockTime()
				buff_table.actived = true
			end
		end
	end

	function DpsTuningPlugin:AuraRemoved (time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spellschool, tipo, amount)
		if (tipo == "BUFF") then
			local buff_table = buff_activity [spellid]
			if (buff_table) then
				if (buff_table.actived_at and buff_table.actived) then
					buff_table.uptime = buff_table.uptime + ClockTime() - buff_table.actived_at
				end
				buff_table.actived = false
				buff_table.actived_at = nil
				tinsert (buff_table.procs, DpsTuningPlugin.CurCombat:GetCombatTime())
				DpsTuningPlugin:BuffChartEnd (spellid)
			end
		end
	end
	
	local misscolor = {1, 0.3, 0.3}
	
	local bar_onenter_script = function (self, capsule)
	
		if (not DpsTuningPlugin.CurPlayer or not capsule.spellid) then
			return
		end
	
		GameCooltip:Reset()
		GameCooltip:SetOwner (self)
		GameCooltip:SetType ("tooltip")
		DpsTuningPlugin:CooltipPreset (2)
		
		local spell = DpsTuningPlugin.CurPlayer:GetSpell (capsule.spellid)
		local name, _, icon = _GetSpellInfo (capsule.spellid)
		
		GameCooltip:AddLine (name, "", 1, "orange", nil, 13, "Arrial Narrow")
		GameCooltip:AddIcon (icon)
		
		GameCooltip:AddLine ("")
		
		GameCooltip:AddLine ("Damage:", DpsTuningPlugin:comma_value (spell.total), 1, "white", nil, 10, "Arrial Narrow")
		GameCooltip:AddLine ("Hits:", spell.counter, 1, "white", nil, 10, "Arrial Narrow")
		GameCooltip:AddLine ("Dps:", DpsTuningPlugin:ToK2 (floor (spell.total / DpsTuningPlugin.CurPlayer:Tempo())), 1, "white", nil, 10, "Arrial Narrow")
		GameCooltip:AddLine ("Percent:", _cstr ("%.1f", spell.total / DpsTuningPlugin.CurPlayer.total_without_pet * 100) .. "%", 1, "white", nil, 10, "Arrial Narrow")
		
		GameCooltip:AddLine ("")
		
		GameCooltip:AddLine ("Average Damage:", DpsTuningPlugin:comma_value (floor (spell.total / spell.counter)), 1, "white", nil, 10, "Arrial Narrow")
		GameCooltip:AddLine ("Min Hit:", DpsTuningPlugin:comma_value (spell.n_min), 1, "white", nil, 10, "Arrial Narrow")
		GameCooltip:AddLine ("Max Hit:", DpsTuningPlugin:comma_value (math.max (spell.n_max, spell.c_max)), 1, "white", nil, 10, "Arrial Narrow")
		
		GameCooltip:AddLine ("")
		
		GameCooltip:AddLine ("Critical Hits:", _cstr ("%.1f", spell.c_amt / spell.counter * 100) .. "%", 1, "white", nil, 10, "Arrial Narrow")
		if (spell.c_amt > 0) then
			GameCooltip:AddLine ("Critical Average Damage:", DpsTuningPlugin:comma_value (floor (spell.c_dmg / spell.c_amt)), 1, "white", nil, 10, "Arrial Narrow")
		else
			GameCooltip:AddLine ("Critical Average Damage:", "0", 1, "white", nil, 10, "Arrial Narrow")
		end
		
		--uptime
		local misc = DpsTuningPlugin.CurCombat (DETAILS_ATTRIBUTE_MISC, DpsTuningPlugin.playername)
		if (misc) then
			local debuff_uptime = misc.debuff_uptime
			if (debuff_uptime) then
				local this_spell = misc.debuff_uptime_spells._ActorTable [capsule.spellid]
				if (this_spell) then
					GameCooltip:AddLine ("")
					local uptime = this_spell.uptime
					local minutos, segundos = floor (uptime/60), floor (uptime%60)
					GameCooltip:AddLine ("Uptime:", minutos .. "m " .. segundos .. "s", 1, "white", nil, 10, "Arrial Narrow")
				end
			end
		end
		
		--miss 
		GameCooltip:AddLine ("")
		
		local miss = spell ["MISS"]
		local parry = spell ["PARRY"]
		local dodge = spell ["DODGE"]
		
		if (miss) then
			GameCooltip:AddLine ("Miss:", miss .. " (" .. _cstr ("%.1f", miss / spell.counter * 100) .. "%)", 1, misscolor, nil, 10, "Arrial Narrow")
		end
		if (parry) then
			GameCooltip:AddLine ("Parry:", parry .. " (" .. _cstr ("%.1f", parry / spell.counter * 100) .. "%)", 1, misscolor, nil, 10, "Arrial Narrow")
		end
		if (dodge) then
			GameCooltip:AddLine ("Dodge:", dodge .. " (" .. _cstr ("%.1f", dodge / spell.counter * 100) .. "%)", 1, misscolor, nil, 10, "Arrial Narrow")
		end
		if (spell.g_amt > 0) then
			GameCooltip:AddLine ("Glancing:", spell.g_amt .. " (" .. _cstr ("%.1f", spell.g_amt / spell.counter * 100) .. "%)", 1, misscolor, nil, 10, "Arrial Narrow")
		end

		GameCooltip:SetOption ("AlignAsBlizzTooltip", true)
		GameCooltip:Show()
	end
	
	local bar_onleanve_script = function (self)
		GameCooltip:Hide()
	end
	
	function DpsTuningPlugin:BuildSpellBars()
		DpsTuningPlugin.SpellBars = {}
		
		local scrollbar = CreateFrame ("scrollframe", "DpsTuningPluginSpellsFauxScroll", DpsTuningPlugin.Frame, "FauxScrollFrameTemplate")
		scrollbar:SetSize (275, 150)
		scrollbar:SetPoint ("topleft", DpsTuningPlugin.Frame, "topleft", 1, 0)
		scrollbar:SetScript ("OnVerticalScroll", function (self, offset) FauxScrollFrame_OnVerticalScroll (self, offset, 15, update_scroll) end)
		scrollbar.Update = update_scroll
		DpsTuningPlugin.SpellScroll = scrollbar
		
		for i = 1, 9 do
			local bar = fw:CreateBar (DpsTuningPlugin.Frame, "Skyline", 275, 14, 100)
			bar.color = DpsTuningPlugin.BarColor
			bar.textfont = "Arial Narrow"
			bar.textsize = 10
			bar:SetPoint ("topleft", DpsTuningPlugin.Frame, "topleft", 1, ((i-1) * -15) - 20)
			
			bar:SetHook ("OnEnter", bar_onenter_script)
			bar:SetHook ("OnLeave", bar_onleanve_script)
			
			tinsert (DpsTuningPlugin.SpellBars, bar)
		end
	end
	
	local colors = {
		{1, 1, 1}, --white
		{1, 0.8, .1}, --orange
		{.3, .3, 1}, --blue
		{1, .3, .3}, --red
		{.3, 1, .3}, --green
		{.3, 1, 1}, --cyan
		{1, 0.75, 0.79}, --pink
		{0.98, 0.50, 0.44}, --salmon
		{0.75, 0.75, 0.75}, --silver
		{0.60, 0.80, 0.19}, --yellow
		{1, .3, 1}, --magenta
	}
	
	local linetypes = {"line", "smallline", "thinline"}
	
	function DpsTuningPlugin:BuildChartPanels()

		local chart_panel = fw:CreateChartPanel (UIParent, GetScreenWidth()-200, 500)
		chart_panel:SetPoint ("topleft", UIParent, "topleft", 100, -100)
		chart_panel:SetTitle ("Dps Tuning")
		chart_panel:SetFrameStrata ("DIALOG")
		chart_panel:CanMove (true)
		tinsert (UISpecialFrames, chart_panel:GetName())

		chart_panel:Hide()
		
		local open_chart_panel = function()
			chart_panel:Reset()
		
			local player_dps = DpsTuningPlugin.CurCombat:GetTimeData ("Player Damage Done")
			
			local combat_time = DpsTuningPlugin.CurCombat:GetCombatTime()
			chart_panel:SetTime (combat_time)
			chart_panel:SetScale (player_dps.max_value)
			
			chart_panel:AddLine (player_dps, {1, 1, 1, 1}, "Your Damage", combat_time, "line")
			chart_panel:AddLine (power_amount_chart_table, {1, .4, .4, 1}, "Spell/Attack Power (x3)", combat_time)

			chart_panel:Show()
		end
		
		local open_chart_panel2 = function()

			chart_panel:Reset()
			
			local GraphicSmoothLevel = 1
			
			--> we need to copy because of the addition of spells with the same icon.
			local spell_graphic_data = table_deepcopy (spell_graphic_data)
			
			local consolidate = {}
			for spellid, data in pairs (spell_graphic_data) do
				local spellname, _, spellicon = _GetSpellInfo (spellid)
				if (consolidate [spellicon]) then
				
					local data2 = consolidate [spellicon][3]
					local new_max_value = consolidate [spellicon][4]
					
					for i = 1, #data do
						data2[i] = data2[i] + data[i] --can be the same table as the default one or it just will add and add over again.
						if (data2[i] > new_max_value) then
							new_max_value = data2[i]
						end
					end
					
					consolidate [spellicon][4] = new_max_value
					
					local spelldamage = DpsTuningPlugin.CurPlayer:GetSpell (spellid).total
					consolidate [spellicon][5] = consolidate [spellicon][5] + spelldamage
					
					if (string.len (spellname) < string.len (consolidate [spellicon][2])) then
						consolidate [spellicon][2] = spellname
					end

				else
					consolidate [spellicon] = {spellid, spellname, data, data.max_value, DpsTuningPlugin.CurPlayer:GetSpell (spellid).total}
				end
			end

			local order = {}
			for spellid, data in pairs (consolidate) do
				tinsert (order, data)
			end
			
			table.sort (order, DpsTuningPlugin.Sort1)

			local player_total_damage = DpsTuningPlugin.CurPlayer.total
			
			local max = 0
			
			for index, data in ipairs (order) do
				local spellid = data[1]
				local spellname = data[2]
				local chart_data = data[3]
				local max_value = data[4]
				if (max_value > max) then
					max = max_value
				end
				local spelldamage = data[5]
				
				if (spelldamage/player_total_damage*100 > 5) then
					if (colors [index]) then
						chart_panel:AddLine (chart_data, colors [index], spellname, DpsTuningPlugin.CurCombat:GetCombatTime(), nil, GraphicSmoothLevel)
					end
				end
			end

			chart_panel:SetTime (DpsTuningPlugin.CurCombat:GetCombatTime())
			chart_panel:SetScale (max)
			
			chart_panel:Show()
		end
		
		local open_chart_panel3 = function()
			
			chart_panel:Reset()
		
			local player_dps = DpsTuningPlugin.CurCombat:GetTimeData ("Player Damage Done")
			chart_panel:AddLine (player_dps, {1, 1, 1, 1}, "Your Damage", DpsTuningPlugin.CurCombat:GetCombatTime(), "line")

			chart_panel:SetTime (DpsTuningPlugin.CurCombat:GetCombatTime())
			chart_panel:SetScale (player_dps.max_value)

			local index = 1
			for spellid, bufftable in pairs (buff_activity) do
				if (type (bufftable) == "table") then
					if (not bufftable.disabled) then
						local proctable = bufftable.procs
						
						local spellname, _, spellicon = _GetSpellInfo (spellid)
						
						chart_panel:AddOverlay (bufftable.procs, colors [index], spellname, spellicon)
						index = index + 1
					end
				end
			end
			
			chart_panel:Show()
			
		end

		local button_open = fw:CreateButton (SDF, open_chart_panel, 120, 18, "Damage x Power", nil, nil, nil, "OpenGraphicButton")
		button_open:InstallCustomTexture (nil, nil, nil, nil, true)
		button_open:SetPoint ("bottomleft", SDF, "bottomleft", 2, 3)
		button_open:Disable()
		
		local button_open2 = fw:CreateButton (SDF, open_chart_panel2, 120, 18, "All Spells", nil, nil, nil, "OpenGraphicButton2")
		button_open2:InstallCustomTexture (nil, nil, nil, nil, true)
		button_open2:SetPoint ("bottom", button_open, "top", 0, 3)
		button_open2:Disable()
		
		local button_open3 = fw:CreateButton (SDF, open_chart_panel3, 120, 18, "Aura Procs", nil, nil, nil, "OpenGraphicButton3")
		button_open3:InstallCustomTexture (nil, nil, nil, nil, true)
		button_open3:SetPoint ("bottom", button_open2, "top", 0, 3)
		button_open3:Disable()

	end

	
	function DpsTuningPlugin:UpdateSummary()
		if (DpsTuningPlugin.CurPlayer) then
			DpsTuningPlugin.total_damage.text = DpsTuningPlugin:comma_value (floor (DpsTuningPlugin.CurPlayer.total))
			DpsTuningPlugin.activity_dps.text = DpsTuningPlugin:ToK2 (floor (DpsTuningPlugin.CurPlayer.total / DpsTuningPlugin.CurPlayer:Tempo()))
			DpsTuningPlugin.time_elapsed.text = _cstr ("%.1f", GetTime() - DpsTuningPlugin.StartTime)
			DpsTuningPlugin.power_amount.text = DpsTuningPlugin:comma_value (GetSpellBonusDamage (DpsTuningPlugin.PowerType))
		end
	end
	
	function DpsTuningPlugin:UpdateMiliTick()
		DpsTuningPlugin:UpdateSummary()
	end
	
	function DpsTuningPlugin:UpdateTick()
	
		--check for current player
		if (not DpsTuningPlugin.CurPlayer) then
			if (not DpsTuningPlugin.CurCombat) then
				return
			end
			DpsTuningPlugin.CurPlayer = DpsTuningPlugin.CurCombat (DETAILS_ATTRIBUTE_DAMAGE, DpsTuningPlugin.playername)
			if (not DpsTuningPlugin.CurPlayer) then
				return
			end
			
			if (DpsTuningPlugin.CurPlayer and not DpsTuningPlugin.MiliSecTick) then
				DpsTuningPlugin.MiliSecTick = DpsTuningPlugin:ScheduleRepeatingTimer ("UpdateMiliTick", 0.1)
			end
		end
		
		DpsTuningPlugin.CurTick = DpsTuningPlugin.CurTick + 1
		
		--refresh bars
		DpsTuningPlugin.RefreshSpells()
		
		--refresh buff blocks
		DpsTuningPlugin:UpdateBuffBlocks()
		
		--get spells damages
		DpsTuningPlugin:ChartDataTick()

	end
	
	function DpsTuningPlugin:ChartDataTick()
	
		local power = math.max (GetSpellBonusDamage (1), GetSpellBonusDamage (2)) * 3
		tinsert (power_amount_chart_table, power)
		if (power_amount_chart_table.max_value < power) then
			power_amount_chart_table.max_value = power
		end
	
		for spellid, spelltable in pairs (DpsTuningPlugin.CurPlayer:GetActorSpells()) do 
			if (spelltable.total > 0) then
				
				local chart_table = spell_graphic_data [spelltable.id]
				
				if (not chart_table) then
					local new_chart_data = {}
					new_chart_data.last_value = 0
					new_chart_data.max_value = 0
					
					for i = 1, DpsTuningPlugin.CurTick-1 do
						tinsert (new_chart_data, 0)
					end
					spell_graphic_data [spelltable.id] = new_chart_data
					chart_table = new_chart_data
				end
				
				local cvalue = spelltable.total - chart_table.last_value
				if (chart_table.max_value < cvalue) then
					chart_table.max_value = cvalue
				end
				tinsert (chart_table, cvalue)
				chart_table.last_value = spelltable.total
				
			end
		end
	end
	
	function DpsTuningPlugin:OnCombatStart (...)
	
		if (DpsTuningPlugin.FinishedAt+10 > ClockTime()) then
			DpsTuningPlugin:Msg ("Ignoring combat start: a combat just finished.")
			DpsTuningPlugin.FinishedAt = ClockTime()
			return
		end
		
		DpsTuningPlugin.CurCombat = ...
		DpsTuningPlugin.CurPlayer = DpsTuningPlugin.CurCombat (DETAILS_ATTRIBUTE_DAMAGE, DpsTuningPlugin.playername)
	
		table.wipe (spell_activity)
		table.wipe (buff_activity)
		table.wipe (spell_graphic_data)
		table.wipe (buff_graphic_data)
		table.wipe (power_amount_chart_table)
	
		buff_activity.next = 1
		power_amount_chart_table.max_value = 0
		
		DpsTuningPlugin:ClearBuffBlocks()
		DpsTuningPlugin:TrackBuffsAtStart()
		
		--> enable buff parser
		SDF:RegisterEvent ("COMBAT_LOG_EVENT_UNFILTERED")
		
		DpsTuningPlugin.LastDps = 0
		DpsTuningPlugin.CurTick = 0
		DpsTuningPlugin.StartTime = GetTime()
		
		DpsTuningPlugin.TimerTick = DpsTuningPlugin:ScheduleRepeatingTimer ("UpdateTick", 1)
		
		if (DpsTuningPlugin.CurPlayer and not DpsTuningPlugin.MiliSecTick) then
			DpsTuningPlugin.MiliSecTick = DpsTuningPlugin:ScheduleRepeatingTimer ("UpdateMiliTick", 0.1)
		end
		
		SDF.OpenGraphicButton:Disable()
		SDF.OpenGraphicButton2:Disable()
		SDF.OpenGraphicButton3:Disable()
	
	end
	
	function DpsTuningPlugin:OnCombatEnd (...)
		local combat = ...
		
		if (DpsTuningPlugin.CurCombat and DpsTuningPlugin.CurCombat == combat) then
			local now = ClockTime()
			
			DpsTuningPlugin.FinishedAt = now
			
			--> close spells 
			for spellid, spelltable in pairs (spell_activity) do
				if (spelltable.onhold) then
					local diff = now - spelltable.delay - 2
					if (diff > 0) then
						spelltable.start = spelltable.start + diff
					end
					spelltable.onhold = nil
				end
				
				spelltable.tempo_end = now
			end
			
			--> close buffs
			DpsTuningPlugin:TrackBuffsAtEnd()
			
			--> turn off buff parser
			SDF:UnregisterEvent ("COMBAT_LOG_EVENT_UNFILTERED")
			
			--> cancel tick
			DpsTuningPlugin:CancelTicker()
			
			SDF.OpenGraphicButton:Enable()
			SDF.OpenGraphicButton2:Enable()
			SDF.OpenGraphicButton3:Enable()
		end
	end
	
	function DpsTuningPlugin:CancelTicker()
		if (DpsTuningPlugin.TimerTick) then
			DpsTuningPlugin:CancelTimer (DpsTuningPlugin.TimerTick)
			DpsTuningPlugin.TimerTick = nil
		end
		if (DpsTuningPlugin.MiliSecTick) then
			DpsTuningPlugin:CancelTimer (DpsTuningPlugin.MiliSecTick)
			DpsTuningPlugin.MiliSecTick = nil
		end
	end

end

function DpsTuningPlugin:OnEvent (_, event, ...)

	if (event == "COMBAT_LOG_EVENT_UNFILTERED") then
	
		local time1, token, hidding, who_serial, who_name, who_flags, who_flags2, alvo_serial, alvo_name, alvo_flags, alvo_flags2, spellid, spellname, spellschool, tipo, amount = select (1, ...)
		
		if (who_name == DpsTuningPlugin.playername and alvo_name == DpsTuningPlugin.playername) then
			if (token == "SPELL_AURA_APPLIED") then
				DpsTuningPlugin:AuraApplied (time1, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spellschool, tipo, amount)
			elseif (token == "SPELL_AURA_REMOVED") then
				DpsTuningPlugin:AuraRemoved (time1, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spellschool, tipo, amount)
			elseif (token == "SPELL_AURA_REFRESH") then
				DpsTuningPlugin:AuraRefresh (time1, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, spellid, spellname, spellschool, tipo, amount)
			end
		end

	elseif (event == "ADDON_LOADED") then
		local AddonName = select (1, ...)
		if (AddonName == "Details_DpsTuning") then
			
			if (_G._detalhes) then
				
				--> create main plugin object
				CreatePluginFrames()
				
				local MINIMAL_DETAILS_VERSION_REQUIRED = 28
				
				local default_settings = {
					SpellBarsShowType = 1,
				}
				
				--> Install plugin inside details
				local install = _G._detalhes:InstallPlugin ("SOLO", "Dps Tuning", "Interface\\Icons\\Ability_Racial_RocketBarrage", DpsTuningPlugin, "DETAILS_PLUGIN_DPS_TUNING", MINIMAL_DETAILS_VERSION_REQUIRED, "Details! Team", "v1.01", default_settings)
				if (type (install) == "table" and install.error) then
					print (install.error)
				end
				
				--> Register needed events
				_G._detalhes:RegisterEvent (DpsTuningPlugin, "COMBAT_PLAYER_ENTER")
				_G._detalhes:RegisterEvent (DpsTuningPlugin, "COMBAT_PLAYER_LEAVE")
				_G._detalhes:RegisterEvent (DpsTuningPlugin, "DETAILS_DATA_RESET")
				_G._detalhes:RegisterEvent (DpsTuningPlugin, "COMBAT_INVALID")
				
			end
		end

	end
end
