local GlobalAddonName, ExRT = ...

if ExRT.isMN then
	return
end

local max = max
local ceil = ceil
local UnitCombatlogname = ExRT.F.UnitCombatlogname
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
local UnitGetTotalAbsorbs = UnitGetTotalAbsorbs or ExRT.NULLfunc
local UnitPower = UnitPower
local UnitPowerMax = UnitPowerMax
local UnitGUID = UnitGUID
local UnitName = UnitName
local C_UnitAuras = C_UnitAuras
local AntiSpam = ExRT.F.AntiSpam
local GetUnitInfoByUnitFlag = ExRT.F.GetUnitInfoByUnitFlag
local UnitInRaid = UnitInRaid
local UnitIsPlayerOrPet = ExRT.F.UnitIsPlayerOrPet
local GUIDtoID = ExRT.F.GUIDtoID
local GetUnitTypeByGUID = ExRT.F.GetUnitTypeByGUID
local pairs = pairs
local GetTime = GetTime
local UnitIsFriendlyByUnitFlag = ExRT.F.UnitIsFriendlyByUnitFlag
local wipe = wipe
local bit_band = bit.band
local tremove = tremove
local strsplit = strsplit
local type = type
local GetSpellTexture = C_Spell and C_Spell.GetSpellTexture or GetSpellTexture
local COMBATLOG_OBJECT_RAIDTARGET_MASK = COMBATLOG_OBJECT_RAIDTARGET_MASK
local SendChatMessage = C_ChatInfo and C_ChatInfo.SendChatMessage or SendChatMessage
local IsEncounterInProgress = C_InstanceEncounter and C_InstanceEncounter.IsEncounterInProgress or IsEncounterInProgress

local VMRT = nil

local module = ExRT:New("BossWatcher",ExRT.L.BossWatcher)
local ELib,L = ExRT.lib,ExRT.L

module.db.data = {}

module.db.nowNum = 1
local fightData,guidData,graphData,reactionData,segmentsData = nil

module.db.lastFightID = 0
module.db.timeFix = nil

module.db.spellsSchool = {}
local spellsSchool = module.db.spellsSchool

local deathLog = {}
module.db.deathLog = deathLog

local raidGUIDs = {}

local damageTakenLog = {}
module.db.damageTakenLog = damageTakenLog

local spellFix_LotM = {}
local spellFix_SM = {}

module.db.raidTargets = {
	[0x1] = 1,
	[0x2] = 2,
	[0x4] = 3,
	[0x8] = 4,
	[0x10] = 5,
	[0x20] = 6,
	[0x40] = 7,
	[0x80] = 8,
	[0x100] = 9,
	[0x200] = 10,
	[0x400] = 11,
	[0x800] = 12,
	[0x1000] = 13,
	[0x2000] = 14,
	[0x4000] = 15,
	[0x8000] = 16,
	[0x10000] = 17,
	[0x20000] = 18,
}
module.db.energyLocale = {
	[0] = "|cff69ccf0"..L.BossWatcherEnergyType0,
	[1] = "|cffedc294"..L.BossWatcherEnergyType1,
	[2] = "|cffd1fa99"..L.BossWatcherEnergyType2,
	[3] = "|cffffff8f"..L.BossWatcherEnergyType3,
	[4] = "|cfffff569"..L.BossWatcherEnergyType4,
	[5] = "|cffeb4561"..L.BossWatcherEnergyType5,
	[6] = "|cffeb4561"..L.BossWatcherEnergyType6,
	[7] = "|cff9482c9"..L.BossWatcherEnergyType7,
	[8] = "|cff"..format("%02x%02x%02x",113,0,197)..L.BossWatcherEnergyType8,
	[9] = "|cffffb3e0"..L.BossWatcherEnergyType9,
	[10] = "|cffffffff"..L.BossWatcherEnergyType10,
	[11] = "|cff"..format("%02x%02x%02x",0,143,255)..L.BossWatcherEnergyType11,
	[12] = "|cff4DbB98"..L.BossWatcherEnergyType12,
	[13] = "|cff"..format("%02x%02x%02x",51,0,102)..L.BossWatcherEnergyType13,
	[16] = "|cff"..format("%02x%02x%02x",0,255,255)..L.BossWatcherEnergyType16,
	[17] = "|cff"..format("%02x%02x%02x",209,76,223)..L.BossWatcherEnergyType17,
	[18] = "|cff"..format("%02x%02x%02x",255,147,0)..L.BossWatcherEnergyType18,
	[19] = "|cff"..format("%02x%02x%02x",170,169,53)..(L.BossWatcherEnergyType19 or "Essence"),
}

module.db.energyPerClass = {
	--class		--for all	--for player
	["WARRIOR"] = 	{{1,10},	{1,10}},
	["PALADIN"] = 	{{0,10},	{0,9,10}},
	["HUNTER"] = 	{{2,10},	{2,10}},
	["ROGUE"] = 	{{3,10},	{2,4,10}},
	["PRIEST"] = 	{{0,10},	{0,10,13}},
	["DEATHKNIGHT"]={{6,10},	{5,6,10}},
	["SHAMAN"] = 	{{0,10},	{0,10,11}},
	["MAGE"] = 	{{0,10},	{0,10,16}},
	["WARLOCK"] = 	{{0,10},	{0,10,7,14,15}},
	["MONK"] = 	{{0,3,10},	{0,3,10,12}},
	["DRUID"] = 	{{0,1,3,10},	{0,3,4,8,10}},
	["DEMONHUNTER"]={{0,17,18,10},	{0,17,18,10}},
	["EVOKER"] = 	{{0,19,10},	{0,19,10}},
	["NO"] = 	{{0,1,2,3,6,10},{0,1,2,3,6,10,5,7,8,9,11,12,13,14,15,16,17,18,19}},
	["ALL"] =	{{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25},{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25}},
}
local energyPerClass = module.db.energyPerClass

module.db.schoolsDefault = {0x1,0x2,0x4,0x8,0x10,0x20,0x40}
module.db.schoolsColors = {
	[SCHOOL_MASK_NONE or Enum.Damageclass.MaskNone]	= {r=.8,g=.8,b=.8},
	[SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical]	= {r=1,g=.64,b=.19},
	[SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly] 	= {r=1,g=1,b=.56},
	[SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire] 	= {r=.92,g=.27,b=.38},
	[SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature] 	= {r=.6,g=1,b=.4},	--r=.82,g=.98,b=.6
	[SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost] 	= {r=.29,g=.50,b=1},
	[SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow] 	= {r=.72,g=.66,b=.94},
	[SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane] 	= {r=.56,g=.95,b=1},

	[0x1C] = {r=1,g=.3,b=1},	--Elemental
	[0x7C] = {r=.6,g=0,b=0},	--Chromatic
	[0x7E] = {r=1,g=0,b=0},		--Magic
	[0x7F] = {r=.25,g=.25,b=.25},	--Chaos
}
module.db.schoolsColorsGradient = {
	[0x3] = {SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly,SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical},
	[0x5] = {SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire,SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical},
	[0x6] = {SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire,SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly},
	[0x9] = {SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature,SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical},
	[0xA] = {SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature,SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly},
	[0xC] = {SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature,SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire},
	[0x11] = {SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost,SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical},
	[0x12] = {SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost,SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly},
	[0x14] = {SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost,SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire},
	[0x18] = {SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost,SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature},
	[0x21] = {SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow,SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical},
	[0x22] = {SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow,SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly},
	[0x24] = {SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow,SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire},
	[0x28] = {SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow,SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature},
	[0x30] = {SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow,SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost},
	[0x41] = {SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane,SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical},
	[0x42] = {SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane,SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly},
	[0x44] = {SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane,SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire},
	[0x48] = {SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane,SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature},
	[0x50] = {SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane,SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost},
	[0x60] = {SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane,SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow},
}
module.db.schoolsNames = {
	[SCHOOL_MASK_NONE or Enum.Damageclass.MaskNone]	= L.BossWatcherSchoolUnknown,
	[SCHOOL_MASK_PHYSICAL or Enum.Damageclass.MaskPhysical]	= L.BossWatcherSchoolPhysical,
	[SCHOOL_MASK_HOLY or Enum.Damageclass.MaskHoly] 	= L.BossWatcherSchoolHoly,
	[SCHOOL_MASK_FIRE or Enum.Damageclass.MaskFire] 	= L.BossWatcherSchoolFire,
	[SCHOOL_MASK_NATURE or Enum.Damageclass.MaskNature] 	= L.BossWatcherSchoolNature,
	[SCHOOL_MASK_FROST or Enum.Damageclass.MaskFrost] 	= L.BossWatcherSchoolFrost,
	[SCHOOL_MASK_SHADOW or Enum.Damageclass.MaskShadow] 	= L.BossWatcherSchoolShadow,
	[SCHOOL_MASK_ARCANE or Enum.Damageclass.MaskArcane] 	= L.BossWatcherSchoolArcane,

	[0x1C] = L.BossWatcherSchoolElemental,	--Elemental
	[0x7C] = L.BossWatcherSchoolChromatic,	--Chromatic
	[0x7E] = L.BossWatcherSchoolMagic,		--Magic
	[0x7F] = L.BossWatcherSchoolChaos,		--Chaos
}

local ReductionAurasFunctions = {
	physical = 1,
	magic = 2,
	feintCheck = 3,
	dampenHarmCheck = 4,
}
module.db.reductionAuras = {
	--Paladin
	--[465] = {0.8,nil,function(auraVar) return (100+auraVar)/100 end},	--Devotion Aura
	[498] = 0.8,		--Divine Protection
	[86659] = 0.5,		--Guardian of Ancient Kings
	[31850] = 0.8,		--Ardent Defender

	--Priest
	[45242] = 0.85,		--Focused Will
	[33206] = 0.6,		--Pain Suppression
	[81782] = 0.75,		--Power Word: Barrier
	[47585] = 0.4,		--Dispersion
	[194384] = 1,	--Atonement talent

	--Druid
	[22812] = {0.8,nil,function(_,auraVar) return (100+auraVar)/100 end},		--Barkskin
	[102342] = {0.8,nil,function(auraVar) return (100+auraVar)/100 end},		--Ironbark

	--DH
	[212800] = {0.65,nil,function(_,_,auraVar) return (100+auraVar)/100 end},		--Blur

	--Shaman
	[260881] = 0.95,		--Ghost in the Mist
	[108271] = 0.6,		--Astral Shift

	--Warlock
	[104773] = {0.6,nil,function(_,_,auraVar) return (100+auraVar)/100 end},		--Unending Resolve

	--DK
	[48792] = {0.7,nil,function(_,_,auraVar) return (100+auraVar)/100 end},		--Icebound Fortitude

	--Monk
	[122278] = 0.75,		--Dampen Harm
	[120954] = {0.8,nil,function(_,auraVar) return (100+auraVar)/100 end},		--Fortifying Brew

	--Warrior
	[871] = 0.6,		--Shield Wall
	[184364] = 0.7,		--Enraged Regeneration

	--Mage
	[113862] = 0.4,		--Greater Invisibility

	--Other
	[303350] = 0.9,	--EP weapon
	[296003] = {1,nil,function(_,auraVar) return (100+auraVar)/100 end},	--Essence: Unwavering Ward
}
module.db.reductionBySpec = {
	[63] = {30482,	0.94,	ReductionAurasFunctions.physical,	0x4},	--Mage fire;  16% with artifact trait, 6% without
	[104] = {16931,	0.94},			--Druid bear
	[581] = {203513,0.9},			--Demonic Wards
}
module.db.reductionCurrent = {}
module.db.reductionPowerWordBarrierCaster = nil

module.db.reductionIsNotAoe = {}

module.db.def_trackingDamageSpells = {
	[209471]=1873,	--Il'gynoth: Nightmare Explosion
	[198099]=1841,	--Ursoc: Barreling Momentum
	[199237]=1841,	--Ursoc: Barreling Momentum > Crushing Impact
	[211073]=1877,	--Cenarius: Desiccating Stomp
	[210619]=1877,	--Cenarius: Destructive Nightmares
	[206369]=1864,	--Xavius: Corruption Meteor

	[228162]=1958,	--Odyn: Shield of Light

	[210074]=1849,	--Crystal Scorpion: Shockwave
	[204733]=1849,	--Crystal Scorpion: Volatile Chitin
	[207328]=1867,	--Trillax: Cleansing Destruction
	[206376]=1842,	--Krosus: Burning Pitch
	[206938]=1863,	--Etraeus: Shatter
	[210546]=1872,	--Elisande: orb
	[206370]=1866,	--Guldan: 

	[317066]=2344,	--N'Zoth the Corruptor

	[326707]=2407,	--Sire Denathrius: Cleansing Pain
	[339728]=2417,	--Stone Legion Generals: Pulverizing Meteor
	[330712]=2398,	--Shriekwing: Bloodcurdling Shriek
	[334948]=2412,	--The Council of Blood: Unstoppable Charge
	[331708]=2412,	--The Council of Blood: Scarlet Letter

	--[2812]=true,	--Test
}

local var_reductionAuras,var_reductionCurrent = module.db.reductionAuras,module.db.reductionCurrent
local var_trackingDamageSpells = nil

local encounterSpecial = {}

local _graphSectionTimer,_graphSectionTimerRounded,_graphRaidSnapshot = 0,0,{}
local _graphRaidEnergy = {}
module.db.graphRaidEnergy = _graphRaidEnergy

local _BW_Start,_BW_End = nil

local fightData_damage,fightData_damage_seen,fightData_heal,fightData_healFrom,fightData_switch,fightData_cast,fightData_auras,fightData_power,fightData_deathLog,fightData_maxHP,fightData_reduction

local active_segment
local active_phase

local deathMaxEvents = 100

do
	local function CheckForCombat()
		if UnitAffectingCombat("player") or IsEncounterInProgress() then
			_BW_Start()
		end
	end

	function module:Enable()
		VMRT.BossWatcher.enabled = true

		module:RegisterEvents('ZONE_CHANGED_NEW_AREA','PLAYER_REGEN_DISABLED','PLAYER_REGEN_ENABLED','ENCOUNTER_START','ENCOUNTER_END','CHALLENGE_MODE_START','CHALLENGE_MODE_COMPLETED','CHALLENGE_MODE_RESET')
		module.main:ZONE_CHANGED_NEW_AREA()
		module:RegisterSlash()

		if select(3,GetInstanceInfo()) == 8 and C_ChallengeMode.IsChallengeModeActive() then
			module.main:CHALLENGE_MODE_START()
		elseif UnitAffectingCombat("player") then
			_BW_Start()
		else
			ExRT.F.Timer(CheckForCombat,3)
		end
	end
end

function module:Disable()
	VMRT.BossWatcher.enabled = nil

	if fightData then
		_BW_End()
	end

	module.main:UnregisterAllEvents()
	module:UnregisterSlash()
end

local BWInterfaceFrame = nil
local BWInterfaceFrameLoad,isBWInterfaceFrameLoaded,BWInterfaceFrameLoadFunc = nil
do
	local isAdded = nil
	function BWInterfaceFrameLoadFunc()
		if not isBWInterfaceFrameLoaded then
			BWInterfaceFrameLoad()
		end
		if isBWInterfaceFrameLoaded then
			if SettingsPanel then
				SettingsPanel:Hide()
			else
				InterfaceOptionsFrame:Hide()
			end
			BWInterfaceFrame:Show()
		end
		CloseDropDownMenus() 
		ELib.ScrollDropDown.Close()
	end
	function module:miniMapMenu()
		if isAdded then
			return
		end
		local subMenu = {
			{text = L.BossWatcher, func = BWInterfaceFrameLoadFunc, notCheckable = true},
			{text = L.BossWatcherTabMobs, func = ExRT.F.FightLog_OpenTab, arg1 = 1, notCheckable = true},
			{text = L.BossWatcherTabHeal, func = ExRT.F.FightLog_OpenTab, arg1 = 2, notCheckable = true},
			{text = L.BossWatcherTabBuffsAndDebuffs, func = ExRT.F.FightLog_OpenTab, arg1 = 3, notCheckable = true},
			{text = L.BossWatcherTabEnemy, func = ExRT.F.FightLog_OpenTab, arg1 = 4, notCheckable = true},
			{text = L.BossWatcherTabPlayersSpells, func = ExRT.F.FightLog_OpenTab, arg1 = 5, notCheckable = true},
			{text = L.BossWatcherTabEnergy, func = ExRT.F.FightLog_OpenTab, arg1 = 6, notCheckable = true},
			{text = L.BossWatcherTabInterruptAndDispel, func = ExRT.F.FightLog_OpenTab, arg1 = 7, notCheckable = true},
			{text = TRACKING, func = ExRT.F.FightLog_OpenTab, arg1 = 8, notCheckable = true},
			{text = L.BossWatcherDeath, func = ExRT.F.FightLog_OpenTab, arg1 = 9, notCheckable = true},
			{text = L.BossWatcherPositions, func = ExRT.F.FightLog_OpenTab, arg1 = 10, notCheckable = true},
		}
		ExRT.F.MinimapMenuAdd(L.BossWatcher, BWInterfaceFrameLoadFunc, 1, "FightLog_Navigation", subMenu)
	end
	module:RegisterMiniMapMenu()
end
ExRT.F.FightLog_Open = BWInterfaceFrameLoadFunc

function ExRT.F:FightLog_OpenTab(tabID)
	if not isBWInterfaceFrameLoaded then
		BWInterfaceFrameLoad()
	end
	BWInterfaceFrame.tab:SelectTab(tabID)
	BWInterfaceFrame:Show()

	CloseDropDownMenus()
	ELib.ScrollDropDown.Close()
end

function module.options:Load()
	self:CreateTilte()

	self.checkEnabled = ELib:Check(self,L.Enable,VMRT.BossWatcher.enabled):Point(15,-35):AddColorState():OnClick(function(self) 
		if self:GetChecked() then
			module:Enable()
		else
			module:Disable()
		end
	end)

	self.sliderNum = ELib:Slider(self,L.BossWatcherOptionsFightsSave):Size(300):Point(20,-125):Range(1,25):SetTo(VMRT.BossWatcher.fightsNum or 1):OnChange(function(self,event) 
		event = ExRT.F.Round(event)
		VMRT.BossWatcher.fightsNum = event
		self.tooltipText = event
		self:tooltipReload(self)
	end)
	self.warningText = ELib:Text(self,L.BossWatcherOptionsFightsWarning,12):Size(570,25):Point(15,-150):Top():Color():Shadow()

	if ExRT.isDev then
		self.saveVariables = ELib:Check(self,L.BossWatcherSaveVariables):Point(260,-35):Tooltip(L.BossWatcherSaveVariablesWarring):OnClick(function(self) 
			VMRT.BossWatcher.saveVariables = true
			VMRT.BossWatcher.SAVED_DATA = module.db.data
			print('Saved')
		end)
	end

	self.showButton = ELib:Button(self,L.BossWatcherGoToBossWatcher):Size(550,20):Point("TOP",0,-200):OnClick(function ()
		if SettingsPanel then
			SettingsPanel:Hide()
		else
			InterfaceOptionsFrame:Hide()
		end
		ExRT.Options.Frame:Hide()
		BWInterfaceFrameLoadFunc()
	end)
	self.buttonChecker = CreateFrame("Frame",nil,self)
	self.buttonChecker:SetScript("OnShow",function (self)
		if not ExRT.Options.Frame:IsShown() then
			module.options.showButton:Hide()
		else
			module.options.showButton:Show()
		end
	end)

	self.chatText = ELib:Text(self,L.BossWatcherOptionsHelp,12):Size(600,250):Point(15,-235):Top():Color():Shadow()

	function module.options:AdditionalOnShow()
		if ExRT.Options.Frame:IsShown() then
			module.options:SetParent(ExRT.Options.Frame)
			module.options:ClearAllPoints()
			module.options:SetPoint("TOPLEFT",ExRT.Options.Frame.ListWidth,-16)
		end
	end
end

local function UpdateTrackingDamageSpellsTable()
	var_trackingDamageSpells = ExRT.F.table_copy2(module.db.def_trackingDamageSpells)
	for spellID,_ in pairs(VMRT.BossWatcher.trackingDamageSpells) do
		var_trackingDamageSpells[spellID] = true
	end
end

function module.main:ADDON_LOADED()
	VMRT = _G.VMRT
	VMRT.BossWatcher = VMRT.BossWatcher or {
		optionsDamageGraph = true,
		optionsHealingGraph = true,
		optionsPositionsDist = true,
		fightsNum = 2,
	}

	if VMRT.BossWatcher.enabled then
		module:Enable(true)
	end
	VMRT.BossWatcher.fightsNum = VMRT.BossWatcher.fightsNum or 2

	VMRT.BossWatcher.trackingDamageSpells = VMRT.BossWatcher.trackingDamageSpells or {}
	UpdateTrackingDamageSpellsTable()

	if VMRT.BossWatcher.saveVariables and VMRT.BossWatcher.SAVED_DATA then
		module.db.data = VMRT.BossWatcher.SAVED_DATA
		for i=1,#module.db.data do
			if module.db.data[i] then
				module.db.data[i].fightID = -i
			end
		end
	else
		VMRT.BossWatcher.SAVED_DATA = nil
	end

	VMRT.BossWatcher.saveVariables = nil

	if VMRT.Addon.Version < 3596 then
		VMRT.BossWatcher.optionsDamageGraph = true
		VMRT.BossWatcher.optionsHealingGraph = true
		VMRT.BossWatcher.optionsPositionsDist = true
	end
end

local negateHealing = {}

local SLTReductionAuraSpellID = 98007
local SLTReductionAuraData = {}
local SLTReductionSourceGUID = nil

local SLTReductionFrame = CreateFrame("Frame")
SLTReductionFrame:SetScript("OnEvent",function(_,_,unit)
	local findEm = nil
	for i=1,60 do
		local auraData = C_UnitAuras.GetAuraDataByIndex(unit, i, "HELPFUL")
		if not auraData then
			break
		elseif auraData.spellId == SLTReductionAuraSpellID then 
			findEm = true
			break
		end
	end    

	local guid = UnitGUID(unit)
	if not guid then
		return
	elseif findEm and not SLTReductionAuraData[ guid ] then
		if not fightData_auras then
			return
		end
		local destData = var_reductionCurrent[ guid ]
		if not destData then
			destData = {}
			var_reductionCurrent[ guid ] = destData
		end
		local destCount = #destData
		local from = 1
		for i=1,destCount do
			from = from * destData[i].r
		end
		local currReduction = 1 / (1 - (from - from * 0.9))
		destData[destCount + 1] = {
			s = SLTReductionAuraSpellID,
			r = 0.9,
			c = (currReduction - 1),
			g = SLTReductionSourceGUID,
		}

		SLTReductionAuraData[ guid ] = true

		fightData_auras[ #fightData_auras + 1 ] = {GetTime() - module.db.timeFix[1] + module.db.timeFix[2],SLTReductionSourceGUID,UnitGUID(unit),true,true,SLTReductionAuraSpellID,"BUFF",1,1}
	elseif not findEm and SLTReductionAuraData[ guid ] then
		if not fightData_auras then
			return
		end
		local destData = var_reductionCurrent[ guid ]
		if not destData then
			return
		end
		for i=1,#destData do
			if destData[i] and destData[i].s == SLTReductionAuraSpellID then
				tremove(destData,i)
			end
		end

		local from,fromPhysical,fromMagic = 1,1,1
		for i=1,#destData do
			local spellData = destData[i]
			local currReduction = nil
			if spellData.f == ReductionAurasFunctions.magic then
				currReduction = 1 / (1 - (fromMagic - fromMagic * spellData.r))
				fromMagic = fromMagic * spellData.r
			elseif spellData.f == ReductionAurasFunctions.physical then
				currReduction = 1 / (1 - (fromPhysical - fromPhysical * spellData.r))
				fromPhysical = fromPhysical * spellData.r
			else
				currReduction = 1 / (1 - (from - from * spellData.r))
				fromPhysical = fromPhysical * spellData.r
				fromMagic = fromMagic * spellData.r
			end
			from = from * spellData.r
			spellData.c = currReduction - 1
		end

		SLTReductionAuraData[ guid ] = nil

		fightData_auras[ #fightData_auras + 1 ] = {GetTime() - module.db.timeFix[1] + module.db.timeFix[2],SLTReductionSourceGUID,UnitGUID(unit),true,true,SLTReductionAuraSpellID,"BUFF",2,1}
	end
end)

local SLTReductionUnregTimer = nil
local function SLTReductionUnreg()
	SLTReductionUnregTimer = nil
	SLTReductionFrame:UnregisterAllEvents()
	wipe(SLTReductionAuraData)
end
local function SLTReductionReg(sourceGUID)
	SLTReductionSourceGUID = sourceGUID
	SLTReductionFrame:RegisterEvent("UNIT_AURA")
end

local reductionAtonement = {}

local function addReductionOnPull(unit,destGUID)
	--------------> Add passive reductions
	--- Note: this is first reduction check ever and I must don't care about any existens data
	local unitInspectData = ExRT.A.ExCD2 and ExRT.A.ExCD2.db and ExRT.A.ExCD2.db.inspectDB and ExRT.A.ExCD2.db.inspectDB[unit]
	local specID = unitInspectData and unitInspectData.spec or 0
	local reductionSpec = module.db.reductionBySpec[ specID ]
	if reductionSpec then
		var_reductionCurrent[ destGUID ] = {
			{
				s = reductionSpec[1],
				r = reductionSpec[2],
				c = (1 / reductionSpec[2] - 1),
				g = destGUID,
				f = reductionSpec[3],
			}
		}
		spellsSchool[ reductionSpec[1] ] = reductionSpec[4] or 0x1
	end

	if unitInspectData and unitInspectData.class == "PRIEST" and specID == 256 and unitInspectData.GUID then
		if (unitInspectData[7] == 1) then
			reductionAtonement[ unitInspectData.GUID ] = 0.97
		else
			reductionAtonement[ unitInspectData.GUID ] = nil
		end
	end

	if unitInspectData and unitInspectData.class == "DRUID" and specID ~= 104 then
		--Guardian affinity
		if (unitInspectData[3] == 2 and specID ~= 105) or (unitInspectData[3] == 3 and specID == 105) then
			var_reductionCurrent[ destGUID ] = {
				{
					s = 16931,
					r = 0.94,
					c = (1 / 0.94 - 1),
					g = destGUID,
				}
			}
		end
	end



	--------------> Add active reductions from current auras
	for i=1,60 do
		local auraData = C_UnitAuras.GetAuraDataByIndex(unit,i)

		if not auraData then
			return
		end

		--------------> Add reduction
		local reduction = var_reductionAuras[auraData.spellId]
		if reduction then
			local sourceGUID = nil
			if auraData.sourceUnit then
				sourceGUID = UnitGUID(auraData.sourceUnit)
			end
			sourceGUID = sourceGUID or ""

			local destData = var_reductionCurrent[ destGUID ]
			if not destData then
				destData = {}
				var_reductionCurrent[ destGUID ] = destData
			end
			local destCount = #destData

			local func,funcAura,reductionTable = nil
			if type(reduction)=="table" then
				reductionTable = reduction
				funcAura = reduction[3]
				func = reduction[2]
				reduction = reduction[1]
			end

			if funcAura then
				if auraData.points then
					reduction, func = funcAura(auraData.points[1] or 0,auraData.points[2] or 0,auraData.points[3] or 0,auraData.points[4] or 0,auraData.points[5] or 0)
					if not reduction then
						reduction = reductionTable[1]
						func = reductionTable[2]
						funcAura = nil
					end
					--ExRT.F.dprint(format("%s > %s: %s [%d%%]",sourceName,destName,spellName,(reduction or 0)*100))
				else
					funcAura = nil
				end
			end

			if reduction ~= 1 then
				local from = 1
				if func == ReductionAurasFunctions.magic then
					for i=1,destCount do
						if destData[i].f ~= ReductionAurasFunctions.physical then
							from = from * destData[i].r
						end
					end
				elseif func == ReductionAurasFunctions.physical then
					for i=1,destCount do
						if destData[i].f ~= ReductionAurasFunctions.magic then
							from = from * destData[i].r
						end
					end
				else
					for i=1,destCount do
						from = from * destData[i].r
					end
				end

				local currReduction = 1 / (1 - (from - from * reduction))
				destData[destCount + 1] = {
					s = auraData.spellId,
					r = reduction,
					c = (currReduction - 1),
					g = sourceGUID,
					f = func,
				}

				if not spellsSchool[auraData.spellId] then
					spellsSchool[auraData.spellId] = 0x1
				end
			end
		end
	end
end

local BossPhasesData = {}
local BossPhasesFrame = CreateFrame("Frame")
local BossPhasesBossmodPhaseCounter, BossPhasesBossmodPhase, BossPhasesBossmodEnabled = 1
local BossPhasesBossmodCL
local BossPhasesBossmod
function BossPhasesBossmod()
	if BigWigsLoader and type(BigWigsLoader)=='table' and BigWigsLoader.RegisterMessage then
		local r = {}
		function r:BigWigs_Message (event, module, key, text, ...)

			if (key == "stages") then
				if not text or not BossPhasesBossmodEnabled then
					return
				elseif BossPhasesBossmodPhase ~= text then
					if BossPhasesBossmodCL or BigWigsAPI then
						local CL = BossPhasesBossmodCL or BigWigsAPI:GetLocale("BigWigs: Common")
						BossPhasesBossmodCL = CL
						if CL and CL.soon and type(text)=='string' then
							local patt = CL.soon:gsub("%%s","")
							if CL.soon:find("^%%s") then
								patt = patt .. "$"
							else
								patt = "^" .. patt
							end
							if text:find( patt ) then
								return
							end
						end
					end

					local phaseNumInDB = nil
					for index,phase in pairs(segmentsData.phaseNames) do
						if text == phase then
							phaseNumInDB = index
							break
						end
					end
					if not phaseNumInDB then
						BossPhasesBossmodPhaseCounter = BossPhasesBossmodPhaseCounter + 1
						phaseNumInDB = BossPhasesBossmodPhaseCounter

						segmentsData.phaseNames[BossPhasesBossmodPhaseCounter] = text
					end

					BossPhasesBossmodPhase = text

					active_phase = phaseNumInDB
				end
			end
		end

		BigWigsLoader.RegisterMessage (r, "BigWigs_Message")

		BossPhasesBossmod = nil
	end
end


function _BW_Start(encounterID,encounterName)
	module.db.lastFightID = module.db.lastFightID + 1

	local maxFights = (VMRT.BossWatcher.fightsNum or 5)
	for i=maxFights+1,2,-1 do
		module.db.data[i] = module.db.data[i-1]
	end

	fightData_damage = {}
	fightData_damage_seen = {}
	fightData_heal = {}
	fightData_healFrom = {}
	fightData_switch = {}
	fightData_cast = {}
	fightData_auras = {}
	fightData_power = {}
	fightData_deathLog = {}
	fightData_maxHP = {}
	fightData_reduction = {}

	fightData = {
		guids = {},
		raidguids = {},
		reaction = {},
		pets = {},
		encounterName = encounterName,
		encounterID = encounterID,
		encounterStartGlobal = time(),
		encounterStart = GetTime(),
		encounterEnd = 0,
		graphData = {},
		positionsData = {},
		fightID = module.db.lastFightID,
		segments = {
			[1] = {
				e=true,
				t=GetTime(),
				p=1,
			},
		},
		damage = fightData_damage,
		damage_seen = fightData_damage_seen,
		heal = fightData_heal,
		healFrom = fightData_healFrom,
		switch = fightData_switch,
		cast = fightData_cast,
		interrupts = {},
		dispels = {},
		auras = fightData_auras,
		power = fightData_power,
		dies = {},
		chat = {},
		resurrests = {},
		summons = {},
		aurabroken = {},
		deathLog = fightData_deathLog,
		maxHP = fightData_maxHP,
		reduction = fightData_reduction,
		tracking = {},
		other = {
			roles = {},
			rolesGUID = {},
		},
	}

	module.db.data[1] = fightData

	wipe(deathLog)
	wipe(damageTakenLog)
	wipe(encounterSpecial)

	raidGUIDs = fightData.raidguids
	guidData = fightData.guids
	graphData = fightData.graphData
	reactionData = fightData.reaction
	segmentsData = fightData.segments

	active_segment = 1
	active_phase = 1

	wipe(negateHealing)

	module:RegisterEvents('COMBAT_LOG_EVENT_UNFILTERED','UNIT_TARGET','RAID_BOSS_EMOTE','RAID_BOSS_WHISPER','UPDATE_MOUSEOVER_UNIT')

	BossPhasesBossmodEnabled = nil
	local bossPhaseReg = BossPhasesData[encounterID or -1]
	if bossPhaseReg then
		BossPhasesFrame:SetScript("OnEvent",bossPhaseReg.func)
		for i=1,#bossPhaseReg.events do
			local event = bossPhaseReg.events[i]
			if type(event)=='table' then
				BossPhasesFrame:RegisterUnitEvent(event[1],event[2])
			else
				BossPhasesFrame:RegisterEvent(event)
			end
		end
		segmentsData.phaseNames = bossPhaseReg.names
	elseif encounterID then
		BossPhasesBossmodPhase = nil
		BossPhasesBossmodEnabled = true
		BossPhasesBossmodPhaseCounter = 1
		if BossPhasesBossmod then
			BossPhasesBossmod()
		end
		segmentsData.phaseNames = {[1] = 1,}
		if BossPhasesBossmodCL and BossPhasesBossmodCL.stage then
			segmentsData.phaseNames[1] = BossPhasesBossmodCL.stage:format(1)
		end
	end

	_graphSectionTimer = 0
	_graphSectionTimerRounded = 0
	_graphRaidSnapshot = {"boss1","boss2","boss3","boss4","boss5","boss6","target","focus"}
	local energyPerClass_general = energyPerClass["NO"][1]
	wipe(_graphRaidEnergy)
	for i=1,#_graphRaidSnapshot do
		_graphRaidEnergy[i] = energyPerClass_general
	end

	wipe(var_reductionCurrent)

	if not var_trackingDamageSpells then
		var_trackingDamageSpells = {}
	end

	module:RegisterTimer()
	for _, name, subgroup, class, guid, rank, level, online, isDead, combatRole in ExRT.F.IterateRoster, ExRT.F.GetRaidDiffMaxGroup() do
		_graphRaidSnapshot[#_graphRaidSnapshot + 1] = name
		if module.db.allEnergyMode then
			class = "ALL"
		end
		local energy = energyPerClass[class or "NO"]
		if name == ExRT.SDB.charName then
			energy = energy and energy[2]
		else
			energy = energy and energy[1]
		end
		_graphRaidEnergy[#_graphRaidSnapshot] = energy or energyPerClass_general

		if guid then
			raidGUIDs[ guid ] = name

			addReductionOnPull(name,guid)

			fightData.other.rolesGUID[guid] = combatRole
		end

		fightData.other.roles[name] = combatRole
	end
end

function _BW_End(encounterID)
	if fightData then
		fightData.encounterEnd = GetTime()
		fightData.timeFix = module.db.timeFix
		fightData.ExRTver = ExRT.V
		fightData.isEnded = true

		if not fightData.encounterName then
			local minSeen,minGUID = nil
			for GUID,seen in pairs(fightData_damage_seen) do
				if (not minSeen or minSeen > seen) and ExRT.F.GetUnitInfoByUnitFlag(fightData.reaction[GUID],3) == 64 then
					minGUID = GUID
					minSeen = seen
				end
			end
			if minGUID and fightData.guids[minGUID] and fightData.guids[minGUID] ~= "nil" then
				fightData.encounterName = fightData.guids[minGUID]
			end
		end

		local GLOBALpets = ExRT.F.Pets:getPetsDB()
		for GUID,name in pairs(fightData.guids) do
			local petData = GLOBALpets[GUID]
			if petData then
				fightData.pets[GUID] = petData
			end
		end
	end

	wipe(encounterSpecial)

	module:UnregisterEvents('COMBAT_LOG_EVENT_UNFILTERED','UNIT_TARGET','RAID_BOSS_EMOTE','RAID_BOSS_WHISPER','UPDATE_MOUSEOVER_UNIT')
	module:UnregisterTimer()

	BossPhasesFrame:UnregisterAllEvents()

	fightData = nil
	guidData = nil
	graphData = nil
	reactionData = nil

	active_phase = nil

	if BossPhasesBossmodEnabled and segmentsData.phaseNames and ExRT.F.table_len(segmentsData.phaseNames) == 1 then
		segmentsData.phaseNames = nil
	end
	BossPhasesBossmodEnabled = nil

	segmentsData = nil

	wipe(deathLog)
	wipe(var_reductionCurrent)
	wipe(damageTakenLog)

	local maxFights = (VMRT.BossWatcher.fightsNum or 5)
	for i=25,1,-1 do
		local data = module.db.data[i]
		if data and data.encounterStart and data.encounterEnd and data.encounterID and (data.encounterEnd - data.encounterStart) < 20 and not (not ExRT.isClassic and PlayerGetTimerunningSeasonID and PlayerGetTimerunningSeasonID()) then
			local c = 0
			for k,v in pairs(data.raidguids) do 
				c = c + 1 
				if c > 1 then
					break
				end
			end
			if c > 1 then
				tremove(module.db.data,i)
			end
		end
	end
	for i=(maxFights+1),25 do
		if module.db.data[i] then
			wipe(module.db.data[i])
		end
		module.db.data[i] = nil
	end

	fightData_damage = nil
	fightData_damage_seen = nil
	fightData_heal = nil
	fightData_healFrom = nil
	fightData_switch = nil
	fightData_cast = nil
	fightData_auras = nil
	fightData_power = nil
	fightData_deathLog = nil
	fightData_maxHP = nil
	fightData_reduction = nil
end

do
	local segment_tmr,segment_checker = 0,-1
	function module:timer(elapsed)
		--------------> Graphs
		_graphSectionTimer = _graphSectionTimer + elapsed
		local nowTimer = _graphSectionTimer - _graphSectionTimer % 1 + 1
		if _graphSectionTimerRounded ~= nowTimer then
			_graphSectionTimerRounded = nowTimer
			local data = {}
			graphData[_graphSectionTimerRounded] = data
			for i=1,#_graphRaidSnapshot do
				local name = _graphRaidSnapshot[i]
				local _name = i <= 8 and UnitCombatlogname(name)
				if i > 8 or _name then
					local health = UnitHealth(name)
					local hpmax = UnitHealthMax(name)
					local absorbs = UnitGetTotalAbsorbs(name)
					local power = UnitPower(name)
					local powerMax = UnitPowerMax(name)

					local currData = {
						name = _name or nil,
						health = health ~= 0 and health or nil,
						hpmax = hpmax ~= 0 and hpmax or nil,
						absorbs = absorbs ~= 0 and absorbs or nil,
						power = power ~= 0 and power or nil,
						pmax = powerMax ~=0 and powerMax or nil,
					}
					data[name] = currData

					local energy = _graphRaidEnergy[i]
					for j=1,#energy do
						local powerID = energy[j]
						local power = UnitPower(name,powerID)
						if power ~= 0 then
							currData[powerID] = power
						end
					end
				end
			end
		end

		segment_tmr = segment_tmr + elapsed
		local nowSegment = segment_tmr - segment_tmr % 1
		if nowSegment ~= segment_checker then
			segment_checker = nowSegment
			active_segment = active_segment + 1
			segmentsData[active_segment] = {
				e = true,
				t = GetTime(),
				p = active_phase,
			}
		end
	end
end


local function GetCurrentZoneID()
	local zoneID = 0
	local zoneName, zoneType, difficulty, _, _, _, _, mapID = GetInstanceInfo()
	if difficulty == 8 then
		zoneID = 3
	elseif zoneType == 'raid' and ((tonumber(mapID) and mapID >= 603) or mapID == 533) then
		zoneID = 1
	elseif zoneType == 'arena' or zoneType == 'pvp' then
		zoneID = 2
	elseif zoneType == 'scenario' and (difficulty == 38 or difficulty == 39 or difficulty == 40 or difficulty == 45) then	--islands
		zoneID = 4
	elseif mapID == 2274 or mapID == 2212 or mapID == 2213 or mapID == 2275 then	--horrific vision
		zoneID = 4
	elseif difficulty == 167 then	--torghast
		zoneID = 4
	end
	return zoneID, zoneName
end

function module.main:ENCOUNTER_START(encounterID,encounterName)
	local zoneID = GetCurrentZoneID()
	if zoneID == 1 then
		_BW_Start(encounterID,encounterName)
	end
end
function module.main:PLAYER_REGEN_DISABLED()
	local zoneID = GetCurrentZoneID()
	if zoneID == 0 then
		_BW_Start()
	end
end
function module.main:CHALLENGE_MODE_START()
	local _,zoneName = GetCurrentZoneID()
	_BW_Start(nil,zoneName)
end

function module.main:ENCOUNTER_END(encounterID)
	local zoneID = GetCurrentZoneID()
	if zoneID == 1 then
		_BW_End(encounterID)
	end
end
function module.main:PLAYER_REGEN_ENABLED()
	local zoneID = GetCurrentZoneID()
	if zoneID == 0 then
		_BW_End()
	end
end
function module.main:CHALLENGE_MODE_RESET()
	if fightData then
		_BW_End()
	end
end
module.main.CHALLENGE_MODE_COMPLETED = module.main.CHALLENGE_MODE_RESET

do
	local function ZoneCheck()
		local zoneID, zoneName = GetCurrentZoneID()
		if zoneID == 2 or zoneID == 4 then
			_BW_Start(nil,zoneName)
		end
	end
	function module.main:ZONE_CHANGED_NEW_AREA()
		if fightData then
			_BW_End()
		end
		ExRT.F.ScheduleTimer(ZoneCheck,2)
	end
end

local function AddNotRealDeath(destGUID,timestamp,spellID)
	local destData = deathLog[destGUID]
	if not destData then
		destData = {c = 0}
		deathLog[destGUID] = destData
	end
	local destTable = {
		{5,destGUID,timestamp,active_segment,spellID},
	}
	destTable.h = destTable[1]
	local destTableLen = 1
	fightData_deathLog[#fightData_deathLog + 1] = destTable
	local c = destData.c
	for i=c,1,-1 do
		local copyTable = destData[i]
		if copyTable and copyTable.t then
			destTableLen = destTableLen + 1
			destTable[destTableLen] = {
				copyTable.t,
				copyTable.s,
				copyTable.ti,
				copyTable.sp,
				copyTable.a,
				copyTable.o,
				copyTable.sc,
				copyTable.b,
				copyTable.ab,
				copyTable.c,
				false,
				copyTable.h,
				copyTable.hm,
				copyTable.ia,
				copyTable.sm,
				copyTable.dm,
			}
		end
	end
	for i=deathMaxEvents,c+1,-1 do
		local copyTable = destData[i]
		if copyTable and copyTable.t then
			destTableLen = destTableLen + 1
			destTable[destTableLen] = {
				copyTable.t,
				copyTable.s,
				copyTable.ti,
				copyTable.sp,
				copyTable.a,
				copyTable.o,
				copyTable.sc,
				copyTable.b,
				copyTable.ab,
				copyTable.c,
				false,
				copyTable.h,
				copyTable.hm,
				copyTable.ia,
				copyTable.sm,
				copyTable.dm,
			}
		end
	end
	destData.schFunc = function()
		local tinsert = tinsert
		if destData.c ~= c then
			local d = {}
			if destData.c < c then
				for i=destData.c,1,-1 do
					local copyTable = destData[i]
					if copyTable and copyTable.t and (copyTable.ti - timestamp) <= 0.25 then
						d[#d+1] = {
							copyTable.t,
							copyTable.s,
							copyTable.ti,
							copyTable.sp,
							copyTable.a,
							copyTable.o,
							copyTable.sc,
							copyTable.b,
							copyTable.ab,
							copyTable.c,
							false,
							copyTable.h,
							copyTable.hm,
							copyTable.ia,
							copyTable.sm,
							copyTable.dm,
						}
					end
				end
				for i=deathMaxEvents,c+1,-1 do
					local copyTable = destData[i]
					if copyTable and copyTable.t and (copyTable.ti - timestamp) <= 0.25 then
						d[#d+1] = {
							copyTable.t,
							copyTable.s,
							copyTable.ti,
							copyTable.sp,
							copyTable.a,
							copyTable.o,
							copyTable.sc,
							copyTable.b,
							copyTable.ab,
							copyTable.c,
							false,
							copyTable.h,
							copyTable.hm,
							copyTable.ia,
							copyTable.sm,
							copyTable.dm,
						}
					end
				end
				for i=#d,1,-1 do
					tinsert(destTable,1,d[i])
				end
			else
				for i=destData.c,c+1,-1 do
					local copyTable = destData[i]
					if copyTable and copyTable.t and (copyTable.ti - timestamp) <= 0.25 then
						d[#d+1] = {
							copyTable.t,
							copyTable.s,
							copyTable.ti,
							copyTable.sp,
							copyTable.a,
							copyTable.o,
							copyTable.sc,
							copyTable.b,
							copyTable.ab,
							copyTable.c,
							false,
							copyTable.h,
							copyTable.hm,
							copyTable.ia,
							copyTable.sm,
							copyTable.dm,
						}
					end
				end
				for i=#d,1,-1 do
					tinsert(destTable,1,d[i])
				end
			end
		end

		destData.schFunc = nil
		destData.sch = nil
	end
	destData.sch = C_Timer.NewTimer(1,destData.schFunc)
end
module.AddNotRealDeath = AddNotRealDeath

local EnvironmentalTypeToSpellID = {
	["Falling"] = 110122,
	["Drowning"] = 68730,
	["Fatigue"] = 125024,
	["Fire"] = 103795,
	["Lava"] = 119741,
	["Slime"] = 16456,
	-- UnkEnvDamage = 48360,
}

local DeathLogBlackList = {
	[154420] = true, --Azshara encounter
	[157452] = true, --Nzoth spine
}

local CLEUParser, CLEU

function module.main.SPELL_DAMAGE(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14)
	--[[
		val1	spellID
		val2	_
		val3	_
		val4	amount
		val5	overkill
		val6	school
		val7	resisted
		val8	blocked
		val9	absorbed
		val10	critical
		val11	glancing
		val12	crushing
		val13	isOffHand
		val14	missType
			--Note, missType param added by myself for tracking function
	]]

	--------------> Add damage
	local destTable = fightData_damage[destGUID]	--destTable
	if not destTable then
		fightData_damage_seen[destGUID] = timestamp
		destTable = {
			[destFlags]={
				[sourceGUID]={
					[event == "SPELL_PERIODIC_DAMAGE" and -val1 or val1]={
						[active_segment] = {
							amount = 0,
							count = 0,
							overkill = 0,
							blocked = 0,
							absorbed = 0,
							crit = 0,
							critcount = 0,
							critmax = 0,
							critover = 0,
							hitmax = 0,
							parry = 0,
							dodge = 0,
							miss = 0,
						}
					}
				}
			}
		}
		fightData_damage[destGUID] = destTable
		if val6 then
			spellsSchool[val1] = val6
		end
	end

	local destReaction = destTable[destFlags]	--destReaction
	if not destReaction then
		destReaction = {
			[sourceGUID]={
				[event == "SPELL_PERIODIC_DAMAGE" and -val1 or val1]={
					[active_segment] = {
						amount = 0,
						count = 0,
						overkill = 0,
						blocked = 0,
						absorbed = 0,
						crit = 0,
						critcount = 0,
						critmax = 0,
						critover = 0,
						hitmax = 0,
						parry = 0,
						dodge = 0,
						miss = 0,
					}
				}
			}
		}
		destTable[destFlags] = destReaction
		if val6 then
			spellsSchool[val1] = val6
		end
	end

	local sourceTable = destReaction[sourceGUID]	--sourceTable
	if not sourceTable then
		sourceTable = {
			[event == "SPELL_PERIODIC_DAMAGE" and -val1 or val1]={
				[active_segment] = {
					amount = 0,
					count = 0,
					overkill = 0,
					blocked = 0,
					absorbed = 0,
					crit = 0,
					critcount = 0,
					critmax = 0,
					critover = 0,
					hitmax = 0,
					parry = 0,
					dodge = 0,
					miss = 0,
				}
			}
		}
		destReaction[sourceGUID] = sourceTable
		if val6 then
			spellsSchool[val1] = val6
		end
	end

	local segmentsTable = sourceTable[event == "SPELL_PERIODIC_DAMAGE" and -val1 or val1]	--segmentsTable
	if not segmentsTable then
		segmentsTable = {
			[active_segment] = {
				amount = 0,
				count = 0,
				overkill = 0,
				blocked = 0,
				absorbed = 0,
				crit = 0,
				critcount = 0,
				critmax = 0,
				critover = 0,
				hitmax = 0,
				parry = 0,
				dodge = 0,
				miss = 0,
			}
		}
		sourceTable[event == "SPELL_PERIODIC_DAMAGE" and -val1 or val1] = segmentsTable
		if val6 then
			spellsSchool[val1] = val6
		end
	end

	local spellTable = segmentsTable[active_segment]	--spellTable
	if not spellTable then
		spellTable = {
			amount = 0,
			count = 0,
			overkill = 0,
			blocked = 0,
			absorbed = 0,
			crit = 0,
			critcount = 0,
			critmax = 0,
			critover = 0,
			hitmax = 0,
			parry = 0,
			dodge = 0,
			miss = 0,
		}
		segmentsTable[active_segment] = spellTable
	end
	spellTable.amount = spellTable.amount + val4
	spellTable.count = spellTable.count + 1
	if val5 > 0 then
		spellTable.overkill = spellTable.overkill + val5
	end
	if val8 then
		spellTable.blocked = spellTable.blocked + val8
	end
	if val9 then
		spellTable.absorbed = spellTable.absorbed + val9
	end
	if val10 then
		spellTable.crit = spellTable.crit + val4
		spellTable.critcount = spellTable.critcount + 1
		if spellTable.critmax < val4 then
			spellTable.critmax = val4
		end
		spellTable.critover = spellTable.critover + (val5 > 0 and val5 or 0) + (val8 and val8 or 0) + (val9 and val9 or 0)
	elseif spellTable.hitmax < val4 then
		spellTable.hitmax = val4
	end


	--------------> Add death
	--local mobID = GUIDtoID(destGUID)
	--if not DeathLogBlackList[mobID] then
	do
		local destData = deathLog[destGUID]	--destData
		if not destData then
			destData = {c=0}
			deathLog[destGUID] = destData
		end
		local tmpVar = destData.c + 1
		if tmpVar > deathMaxEvents then
			tmpVar = 1
		end
		destData.c = tmpVar
		local activeTable = destData[tmpVar]
		if not activeTable then
			activeTable = {}
			destData[tmpVar] = activeTable
		end
		activeTable.t = 1
		activeTable.s = sourceGUID
		activeTable.ti = timestamp
		activeTable.sp = val1
		activeTable.a = val4
		activeTable.o = val5
		activeTable.sc = val6
		activeTable.b = val8
		activeTable.ab = val9
		activeTable.c = val10
		activeTable.ia = nil
		activeTable.sm = sourceFlags2
		activeTable.dm = destFlags2

		local raidunit = raidGUIDs[ destGUID ]
		if raidunit then
			activeTable.h = UnitHealth( raidunit )
			activeTable.hm = UnitHealthMax( raidunit )
		end
	end


	--------------> Add reduction
	local reductionTable = var_reductionCurrent[destGUID]
	if reductionTable then
		local reduction = fightData_reduction[destGUID]
		if not reduction then
			reduction = {}
			fightData_reduction[destGUID] = reduction
		end
		local reduction2 = reduction[sourceGUID]
		if not reduction2 then
			reduction2 = {}
			reduction[sourceGUID] = reduction2
		end
		reduction = reduction2[val1]
		if not reduction then
			reduction = {}
			reduction2[val1] = reduction
		end

		for i=1,#reductionTable do
			local reductionSubtable = reductionTable[i]

			local amount2 = val4+(val9 or 0)+(val8 or 0)+val5

			local isCheck = reductionSubtable.f
			if not isCheck then
				isCheck = true
			elseif isCheck == 1 then --physical
				isCheck = val6 == 1
			elseif isCheck == 2 then --magic
				isCheck = bit_band(val6 or 0,1) == 0
			elseif isCheck == 3 then --feintCheck
				isCheck = module.db.reductionIsNotAoe[val1]
			elseif isCheck == 4 then --dampenHarmCheck
				local unitHealthMax = UnitHealthMax(destName or "?")
				unitHealthMax = unitHealthMax == 0 and 1400000 or unitHealthMax
				isCheck = (amount2 / unitHealthMax) >= 0.15
			end

			if isCheck then
				local reductionGUID = reductionSubtable.g
				reduction2 = reduction[reductionGUID]
				if not reduction2 then
					reduction2 = {}
					reduction[reductionGUID] = reduction2
				end
				local reductionSpell = reductionSubtable.s

				local amount = amount2 * reductionSubtable.c

				local reductionSpellData = reduction2[reductionSpell]
				if not reductionSpellData then
					reductionSpellData = {}
					reduction2[reductionSpell] = reductionSpellData
				end

				reductionSpellData[active_segment] = (reductionSpellData[active_segment] or 0)+amount
			end
		end
	end



	--------------> Add switch
	local switchTable = fightData_switch[destGUID]
	if not switchTable then
		switchTable = {
			[1]={},	--cast
			[2]={},	--target
			seen=timestamp,
		}
		fightData_switch[destGUID] = switchTable
	end
	local switchTableCLEU = switchTable[1]
	if not switchTableCLEU[sourceGUID] then
		switchTableCLEU[sourceGUID] = {timestamp,val1,1}
	end



	--------------> Add special spells [tracking]
	if var_trackingDamageSpells[val1] then
		fightData.tracking[#fightData.tracking + 1] = {timestamp,sourceGUID,sourceFlags2,destGUID,destFlags2,val1,val4,val5,val6,val8,val9,val10,val14,s = active_segment}
	end


	--------------> Other
	if val1 == 196917 then	-- Light of the Martyr: effective healing fix
		local lotmData = spellFix_LotM[sourceGUID]
		if lotmData then
			local damageTaken = val4 + val5 + (val9 or 0)
			if damageTaken < (lotmData[1] + lotmData[2]) and (timestamp - lotmData[5]) < 0.2 then
				local spellTable = lotmData[3]
				if lotmData[2] == 0 then
					spellTable.amount = spellTable.amount - damageTaken
				elseif lotmData[2] >= damageTaken then
					spellTable.absorbed = spellTable.absorbed - damageTaken
				else
					spellTable.absorbed = spellTable.absorbed - lotmData[2]
					spellTable.amount = spellTable.amount - damageTaken + lotmData[2]
				end
				if lotmData[4] then
					spellTable.crit = spellTable.crit - damageTaken
				end
			end
		end
	--[[
	elseif val1 == 186439 then	-- Shadow Mend
		local spellTable = spellFix_SM[destGUID]
		if spellTable then
			local damageTaken = val4 + val5 + (val9 or 0)
			local amount = spellTable.amount
			if amount < damageTaken then
				spellTable.amount = 0
			else
				spellTable.amount = amount - damageTaken
			end
		end
	]]
	end

	if val14 then
		return spellTable
	end
end
function module.main.SPELL_HEAL(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7)
	--[[
	Note about healing:
	amount = healing + overhealing
	absorbed = if spell absorbed by ability (ex. DK's egg, Koragh shadow phase)
	absorbs = if spell is absorb (ex. PW:S, HPally mastery, BloodDK mastery)
	]]
	--[[
		val1	spellID
		val2	_
		val3	school
		val4	amount
		val5	overhealing
		val6	absorbed
		val7	critical
	]]
	if val6 < 0 then return end	--Fix 8.2 boss

	--------------> Add heal
	local sourceTable = fightData_heal[sourceGUID]	--sourceTable
	if not sourceTable then
		sourceTable = {
			[destGUID] = {
				[destFlags] = {
					[event == "SPELL_PERIODIC_HEAL" and -val1 or val1] = {
						[active_segment] = {
							amount = 0,
							over = 0,
							absorbed = 0,
							count = 0,
							crit = 0,
							critcount = 0,
							critmax = 0,
							critover = 0,
							hitmax = 0,
							absorbs = 0,
						}
					}
				}
			}
		}
		fightData_heal[sourceGUID] = sourceTable
		if val3 then
			spellsSchool[val1] = val3
		end
	end

	local destTable = sourceTable[destGUID]		--destTable
	if not destTable then
		destTable = {
			[destFlags] = {
				[event == "SPELL_PERIODIC_HEAL" and -val1 or val1] = {
					[active_segment] = {
						amount = 0,
						over = 0,
						absorbed = 0,
						count = 0,
						crit = 0,
						critcount = 0,
						critmax = 0,
						critover = 0,
						hitmax = 0,
						absorbs = 0,
					}
				}
			}
		}
		sourceTable[destGUID] = destTable
		if val3 then
			spellsSchool[val1] = val3
		end
	end

	local destReactTable = destTable[destFlags]	--destReactTable
	if not destReactTable then
		destReactTable = {
			[event == "SPELL_PERIODIC_HEAL" and -val1 or val1] = {
				[active_segment] = {
					amount = 0,
					over = 0,
					absorbed = 0,
					count = 0,
					crit = 0,
					critcount = 0,
					critmax = 0,
					critover = 0,
					hitmax = 0,
					absorbs = 0,
				}
			}
		}
		destTable[destFlags] = destReactTable
		if val3 then
			spellsSchool[val1] = val3
		end
	end

	local segmentsTable = destReactTable[event == "SPELL_PERIODIC_HEAL" and -val1 or val1]		--segmentsTable
	if not segmentsTable then
		segmentsTable = {
			[active_segment] = {
				amount = 0,
				over = 0,
				absorbed = 0,
				count = 0,
				crit = 0,
				critcount = 0,
				critmax = 0,
				critover = 0,
				hitmax = 0,
				absorbs = 0,
			}
		}
		destReactTable[event == "SPELL_PERIODIC_HEAL" and -val1 or val1] = segmentsTable
		if val3 then
			spellsSchool[val1] = val3
		end
	end

	local spellTable = segmentsTable[active_segment]
	if not spellTable then
		spellTable = {
			amount = 0,
			over = 0,
			absorbed = 0,
			count = 0,
			crit = 0,
			critcount = 0,
			critmax = 0,
			critover = 0,
			hitmax = 0,
			absorbs = 0,
		}
		segmentsTable[active_segment] = spellTable
		if val3 then
			spellsSchool[val1] = val3
		end
	end
	spellTable.amount = spellTable.amount + val4
	spellTable.over = spellTable.over + val5
	spellTable.absorbed = spellTable.absorbed + val6
	spellTable.count = spellTable.count + 1
	if val7 then
		spellTable.crit = spellTable.crit + val4 + val6
		spellTable.critcount = spellTable.critcount + 1
		if spellTable.critmax < val4 then
			spellTable.critmax = val4
		end
		spellTable.critover = spellTable.critover + val5
	elseif spellTable.hitmax < val4 then
		spellTable.hitmax = val4
	end



	--------------> Add death
	local destData = deathLog[destGUID]
	if not destData then
		destData = {c=0}
		deathLog[destGUID] = destData
	end
	local tmpVar = destData.c + 1
	if tmpVar > deathMaxEvents then
		tmpVar = 1
	end
	destData.c = tmpVar
	local activeTable = destData[tmpVar]
	if not activeTable then
		activeTable = {}
		destData[tmpVar] = activeTable
	end
	activeTable.t = 2
	activeTable.s = sourceGUID
	activeTable.ti = timestamp
	activeTable.sp = val1
	activeTable.a = val4
	activeTable.o = val5
	activeTable.sc = val3
	activeTable.b = nil
	activeTable.ab = val6
	activeTable.c = val7
	activeTable.ia = nil
	activeTable.sm = sourceFlags2
	activeTable.dm = destFlags2

	local raidunit = raidGUIDs[ destGUID ]
	if raidunit then
		activeTable.h = UnitHealth( raidunit )
		activeTable.hm = UnitHealthMax( raidunit )
	end


	--------------> Other
	--[[
	if negateHealing[destGUID] then
		spellTable.amount = spellTable.amount - val4
		spellTable.over = spellTable.over + val4 + val6
		spellTable.absorbed = spellTable.absorbed - val6
		if val7 then
			spellTable.crit = spellTable.crit - val4 - val6
			spellTable.critcount = spellTable.critcount - 1
			spellTable.critover = spellTable.critover - val5
		end
	end
	]]
	if val1 == 183998 then	--Light of the Martyr: effective healing fix
		local lotmData = spellFix_LotM[sourceGUID]
		if not lotmData then
			lotmData = {}
			spellFix_LotM[sourceGUID] = lotmData
		end
		lotmData[1] = val4 - val5
		lotmData[2] = val6
		lotmData[3] = spellTable
		lotmData[4] = val7
		lotmData[5] = timestamp
	elseif val1 == 186263 then	--Shadow Mend: effective healing fix, remove damage from debuff
		spellFix_SM[destGUID] = spellTable
	elseif val1 == 213313 then	--Paladin: Divine intervention
		AddNotRealDeath(destGUID,timestamp,val1)
	end

end
function module.main.SPELL_AURA_APPLIED(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,spellName,school,auraType)
	if spellID == 465 then	--HPal devo is broken and can spam 2000 events / sec
		return
	end

	--fightData_auras[ #fightData_auras + 1 ] = {timestamp,sourceGUID,destGUID,UnitIsFriendlyByUnitFlag(sourceFlags),UnitIsFriendlyByUnitFlag(destFlags),spellID,auraType,1,1,s = active_segment}
	fightData_auras[ #fightData_auras + 1 ] = {timestamp,sourceGUID,destGUID,bit_band(sourceFlags or 0,240) == 16,bit_band(destFlags or 0,240) == 16,spellID,auraType,1,1,s = active_segment}

	--------------> Add reduction
	local reduction = var_reductionAuras[spellID]
	if reduction then
		if spellID == 81782 then
			sourceGUID = module.db.reductionPowerWordBarrierCaster or sourceGUID
		elseif spellID == 194384 then
			reduction = reductionAtonement[sourceGUID] or 1
			--[[
			if ExRT.A.Inspect then
				local db = ExRT.A.Inspect.db.inspectDB
				for k,v in pairs(db) do
					if v.GUID == sourceGUID then
						if v[7] == 1 then
							reduction = 0.97
						end
						break
					end
				end
			end
			]]
		end

		local destData = var_reductionCurrent[ destGUID ]
		if not destData then
			destData = {}
			var_reductionCurrent[ destGUID ] = destData
		end
		local destCount = #destData

		local func,funcAura,reductionTable = nil
		if type(reduction)=="table" then
			reductionTable = reduction
			funcAura = reduction[3]
			func = reduction[2]
			reduction = reduction[1]
		end

		if funcAura then
			for i=1,60 do
				local auraData = C_UnitAuras.GetAuraDataByIndex(destName or "?",i)
				if not auraData then
					break
				elseif auraData.spellId == spellID then
					if auraData.points then
						reduction, func = funcAura(auraData.points[1] or 0,auraData.points[2] or 0,auraData.points[3] or 0,auraData.points[4] or 0,auraData.points[5] or 0)
						if not reduction then
							reduction = reductionTable[1]
							func = reductionTable[2]
							funcAura = nil
						end
						--ExRT.F.dprint(format("%s > %s: %s [%d%%]",sourceName,destName,spellName,(reduction or 0)*100))
					else
						funcAura = nil
					end
					break
				end
			end
		end

		if reduction == 1 then
			return
		end


		for i=1,destCount do
			if destData[i].s == spellID then
				local destSpell = destData[i]

				destSpell.r = reduction

				local from,fromMagic,fromPhysical = 1,1,1
				for j=1,i-1 do
					if destData[j].f == ReductionAurasFunctions.magic then
						fromMagic = fromMagic * destData[j].r
					elseif destData[j].f == ReductionAurasFunctions.physical then
						fromPhysical = fromPhysical * destData[j].r
					else
						from = from * destData[j].r
					end
				end

				for j=i,destCount do
					local currReduction
					if destData[j].f == ReductionAurasFunctions.magic then
						currReduction = 1 / (1 - (fromMagic - fromMagic * destData[j].r))
						fromMagic = fromMagic * destData[j].r
					elseif destData[j].f == ReductionAurasFunctions.physical then
						currReduction = 1 / (1 - (fromPhysical - fromPhysical * destData[j].r))
						fromPhysical = fromPhysical * destData[j].r
					else
						currReduction = 1 / (1 - (from - from * destData[j].r))
						from = from * destData[j].r
					end
					destData[j].c = currReduction
				end

				return
			end
		end

		local from = 1
		if func == ReductionAurasFunctions.magic then
			for i=1,destCount do
				if destData[i].f ~= ReductionAurasFunctions.physical then
					from = from * destData[i].r
				end
			end
		elseif func == ReductionAurasFunctions.physical then
			for i=1,destCount do
				if destData[i].f ~= ReductionAurasFunctions.magic then
					from = from * destData[i].r
				end
			end
		else
			for i=1,destCount do
				from = from * destData[i].r
			end
		end

		local currReduction = 1 / (1 - (from - from * reduction))
		destData[destCount + 1] = {
			s = spellID,
			r = reduction,
			c = (currReduction - 1),
			g = sourceGUID,
			f = func,
		}

		--debug_CurrentReductionToChat(destData)

		if school then
			spellsSchool[spellID] = school
		end
	end


	if spellID == 45181 or spellID == 211319 or spellID == 87024 or spellID == 344907 or spellID == 116888 or spellID == 209261 then	--Cheated Death, Archbishop Benedictus' Restitution, Cauterize, Sands of Time (Trinket), Shroud of Purgatory, Uncontained Fel 
		AddNotRealDeath(destGUID,timestamp,spellID)
	--elseif spellID == 243961 then	--Varimatras Disable Healing Debuff
	--	negateHealing[destGUID] = true
	end
end
function module.main.SPELL_AURA_REMOVED(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,school,auraType,amount)
	if spellID == 465 then	--HPal devo is broken and can spam 2000 events / sec
		return
	end

	--fightData_auras[ #fightData_auras + 1 ] = {timestamp,sourceGUID,destGUID,UnitIsFriendlyByUnitFlag(sourceFlags),UnitIsFriendlyByUnitFlag(destFlags),spellID,auraType,2,1,s = active_segment}
	fightData_auras[ #fightData_auras + 1 ] = {timestamp,sourceGUID,destGUID,bit_band(sourceFlags or 0,240) == 16,bit_band(destFlags or 0,240) == 16,spellID,auraType,2,1,s = active_segment}

	if amount and amount > 0 and 
		spellID ~= 284663 --BfD: Conclave: Bwonsamdi
	then
		CLEU["SPELL_HEAL"](timestamp,"SPELL_HEAL",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,school,amount,amount,0)
	end


	--------------> Add reduction
	local reduction = var_reductionAuras[spellID]
	if reduction then
		local destData = var_reductionCurrent[ destGUID ]
		if not destData then
			return
		end
		for i=1,#destData do
			if destData[i] and destData[i].s == spellID and (destData[i].g == sourceGUID or spellID == 81782) then
				tremove(destData,i)
			end
		end

		local from,fromPhysical,fromMagic = 1,1,1
		for i=1,#destData do
			local spellData = destData[i]
			local currReduction = nil
			if spellData.f == ReductionAurasFunctions.magic then
				currReduction = 1 / (1 - (fromMagic - fromMagic * spellData.r))
				fromMagic = fromMagic * spellData.r
			elseif spellData.f == ReductionAurasFunctions.physical then
				currReduction = 1 / (1 - (fromPhysical - fromPhysical * spellData.r))
				fromPhysical = fromPhysical * spellData.r
			else
				currReduction = 1 / (1 - (from - from * spellData.r))
				fromPhysical = fromPhysical * spellData.r
				fromMagic = fromMagic * spellData.r
			end
			from = from * spellData.r
			spellData.c = currReduction - 1
		end

		--debug_CurrentReductionToChat(destData)
	end


	--------------> Other
	if spellID == 187464 then	--Shadow Mend
		spellFix_SM[destGUID] = nil
	--elseif spellID == 243961 then	--Varimatras Disable Healing Debuff
	--	negateHealing[destGUID] = nil
	end
end
function module.main.SPELL_CAST_SUCCESS(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,spellName,spellSchool,empoweredRank)
	--------------> Add cast
	local sourceTable = fightData_cast[sourceGUID]
	if not sourceTable then
		sourceTable = {}
		fightData_cast[sourceGUID] = sourceTable
	end
	sourceTable[ #sourceTable + 1 ] = {timestamp,spellID,1,destGUID,destFlags2,sourceFlags2,sourceFlags,empoweredRank,s = active_segment}

	if spellSchool then
		spellsSchool[spellID] = spellSchool
	end


	--------------> Add switch
	local targetTable = fightData_switch[destGUID]
	if not targetTable then
		targetTable = {
			[1]={},	--cast
			[2]={},	--target
			seen=timestamp,
		}
		fightData_switch[destGUID] = targetTable
	end
	local targetCastTable = targetTable[1]
	if not targetCastTable[sourceGUID] then
		targetCastTable[sourceGUID] = {timestamp,spellID,2}
	end


	--------------> Other
	if spellID == 62618 then	--PW:B caster fix
		module.db.reductionPowerWordBarrierCaster = sourceGUID
	elseif spellID == 98008 then	--SLT Totem
		if SLTReductionUnregTimer then
			SLTReductionUnregTimer:Cancel()
		end
		SLTReductionUnregTimer = C_Timer.NewTimer(8,SLTReductionUnreg)
		SLTReductionReg(sourceGUID)
	elseif spellID == 209471 then	--Illgynoth blossom death-cast
		return CLEU["UNIT_DIED"](timestamp,"UNIT_DIED",true,"",nil,0,0,sourceGUID,sourceName,sourceFlags,sourceFlags2)
	end
end
function module.main.SPELL_ENERGIZE(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID, _, _, amount, overEnergize, powerType, alternatePowerType)
	local sourceData = fightData_power[destGUID]
	if not sourceData then
		sourceData = {}
		fightData_power[destGUID] = sourceData
	end
	local powerData = sourceData[powerType or 0]
	if not powerData then
		powerData = {}
		sourceData[powerType or 0] = powerData
	end
	local spellData = powerData[spellID]
	if not spellData then
		spellData = {0,0}
		powerData[spellID] = spellData
	end
	spellData[1] = spellData[1] + amount
	spellData[2] = spellData[2] + 1
end
function module.main.SWING_DAMAGE(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10)
	return CLEU["SPELL_DAMAGE"](timestamp,"SPELL_DAMAGE",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,6603,nil,1,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10)
end
function module.main.SPELL_AURA_APPLIED_DOSE(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,_,type,stack)
	--fightData_auras[ #fightData_auras + 1 ] = {timestamp,sourceGUID,destGUID,UnitIsFriendlyByUnitFlag(sourceFlags),UnitIsFriendlyByUnitFlag(destFlags),spellID,type,3,stack,s = active_segment}
	fightData_auras[ #fightData_auras + 1 ] = {timestamp,sourceGUID,destGUID,bit_band(sourceFlags or 0,240) == 16,bit_band(destFlags or 0,240) == 16,spellID,type,3,stack,s = active_segment}
end
function module.main.SPELL_CAST_START(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,spellName,spellSchool)
	--------------> Add cast
	local sourceTable = fightData_cast[sourceGUID]
	if not sourceTable then
		sourceTable = {}
		fightData_cast[sourceGUID] = sourceTable
	end
	sourceTable[ #sourceTable + 1 ] = {timestamp,spellID,2,destGUID,destFlags2,sourceFlags2,sourceFlags,s = active_segment}

	if spellSchool then
		spellsSchool[spellID] = spellSchool
	end


	--------------> Add switch
	if sourceName and GetUnitInfoByUnitFlag(sourceFlags,1) == 1024 then
		local unitID = UnitInRaid(sourceName)
		if unitID then
			unitID = "raid"..unitID
			local targetGUID = UnitGUID(unitID.."target")
			if targetGUID and not UnitIsPlayerOrPet(targetGUID) then
				-- Switch code
				local targetTable = fightData_switch[targetGUID]
				if not targetTable then
					targetTable = {
						[1]={},	--cast
						[2]={},	--target
						seen=timestamp,
					}
					fightData_switch[targetGUID] = targetTable
				end
				local targetCastTable = targetTable[1]
				if not targetCastTable[sourceGUID] then
					targetCastTable[sourceGUID] = {timestamp,spellID,3}
				end
				-- / Switch code
			end
		end
	end
end
function module.main.SPELL_ABSORBED(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11)
	--[[
	SPELL_ABSORBED event info:
		for SWING
	timestamp,attackerGUID,attackerName,attackerFlags,attackerFlags2,destGUID,destName,destFlags,destFlags2,sourceGUID,sourceName,sourceFlags,sourceFlags2,spellID,spellName,school,amount
		OR for SPELL
	timestamp,attackerGUID,attackerName,attackerFlags,attackerFlags2,destGUID,destName,destFlags,destFlags2,attackerSpellId,attackerSpellName,attackerSchool,sourceGUID,sourceName,sourceFlags,sourceFlags2,spellID,spellName,school,amount
	]]

	local attackerSpellId,attackerSpellName,attackerSchool,sourceGUID,sourceName,sourceFlags,sourceFlags2,spellID,spellName,school,amount
	if not val11 then
		sourceGUID,sourceName,sourceFlags,sourceFlags2,spellID,spellName,school,amount = val1,val2,val3,val4,val5,val6,val7,val8
		attackerSpellId = 6603
	else
		attackerSpellId,attackerSpellName,attackerSchool,sourceGUID,sourceName,sourceFlags,sourceFlags2,spellID,spellName,school,amount = val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11
	end
	if spellID == 20711 or spellID == 115069 or spellID == 157533 then	--Not real absorbs spells
		return
	end


	--------------> Add heal
	local sourceTable = fightData_heal[sourceGUID]
	if not sourceTable then
		sourceTable = {}
		fightData_heal[sourceGUID] = sourceTable
	end
	local destTable = sourceTable[destGUID]
	if not destTable then
		destTable = {}
		sourceTable[destGUID] = destTable
	end
	local destReactTable = destTable[destFlags]
	if not destReactTable then
		destReactTable = {}
		destTable[destFlags] = destReactTable
	end
	local segmentsTable = destReactTable[spellID]
	if not segmentsTable then
		segmentsTable = {}
		destReactTable[spellID] = segmentsTable
	end
	local spellTable = segmentsTable[active_segment]
	if not spellTable then
		spellTable = {
			amount = 0,
			over = 0,
			absorbed = 0,
			count = 0,
			crit = 0,
			critcount = 0,
			critmax = 0,
			critover = 0,
			hitmax = 0,
			absorbs = 0,
		}
		segmentsTable[active_segment] = spellTable
		spellsSchool[spellID] = school
	end
	spellTable.amount = spellTable.amount + amount
	spellTable.absorbs = spellTable.absorbs + amount
	spellTable.count = spellTable.count + 1
	if spellTable.hitmax < amount then
		spellTable.hitmax = amount
	end



	--------------> Add death
	local destData = deathLog[destGUID]
	if not destData then
		destData = {c=0}
		deathLog[destGUID] = destData
	end
	local pos = destData.c + 1
	if pos > deathMaxEvents then
		pos = 1
	end
	local deathLine = destData[pos]
	if not deathLine then
		deathLine = {}
		destData[pos] = deathLine
	end
	deathLine.t = 2
	deathLine.s = sourceGUID
	deathLine.ti = timestamp
	deathLine.sp = spellID
	deathLine.a = amount
	deathLine.o = 0
	deathLine.sc = school
	deathLine.b = nil
	deathLine.ab = nil
	deathLine.c = nil
	deathLine.ia = amount
	deathLine.sm = sourceFlags2
	deathLine.dm = destFlags2
	local player = raidGUIDs[ destGUID ]
	if player then
		deathLine.h = UnitHealth( player )
		deathLine.hm = UnitHealthMax( player )
	end
	destData.c = pos
end
function module.main.SPELL_MISSED(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,school,missType,isOffHand,amountMissed,critical)
	local newEvent = event == "SPELL_PERIODIC_MISSED" and "SPELL_PERIODIC_DAMAGE" or "SPELL_DAMAGE"
	if missType == "ABSORB" then
		return CLEU[newEvent](timestamp,newEvent,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,0,0,school,nil,nil,amountMissed,critical,nil,nil,isOffHand)
	elseif missType == "BLOCK" then
		return CLEU[newEvent](timestamp,newEvent,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,0,0,school,nil,amountMissed,nil,critical,nil,nil,isOffHand)
	elseif missType == "PARRY" then
		local spellTable = CLEU[newEvent](timestamp,newEvent,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,0,0,school,nil,nil,nil,critical,nil,nil,isOffHand,missType)
		spellTable.parry = spellTable.parry + 1
	elseif missType == "DODGE" then
		local spellTable = CLEU[newEvent](timestamp,newEvent,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,0,0,school,nil,nil,nil,critical,nil,nil,isOffHand,missType)
		spellTable.dodge = spellTable.dodge + 1
	else
		local spellTable = CLEU[newEvent](timestamp,newEvent,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,0,0,school,nil,nil,nil,critical,nil,nil,isOffHand,missType)
		spellTable.miss = spellTable.miss + 1
	end
end
function module.main.SWING_MISSED(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14)
	return CLEU["SPELL_MISSED"](timestamp,"SPELL_MISSED",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,6603,nil,0x1,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14)
end
function module.main.RANGE_DAMAGE(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14)
	return CLEU["SPELL_DAMAGE"](timestamp,"SPELL_DAMAGE",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14)
end
function module.main.SPELL_AURA_REMOVED_DOSE(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,_,type,stack)
	fightData_auras[ #fightData_auras + 1 ] = {timestamp,sourceGUID,destGUID,bit_band(sourceFlags or 0,240) == 16,bit_band(destFlags or 0,240) == 16,spellID,type,4,stack,s = active_segment}
end
function module.main.UNIT_DIED(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2)
	fightData.dies[#fightData.dies+1] = {destGUID,destFlags,timestamp,destFlags2,s = active_segment}

	--if DeathLogBlackList[GUIDtoID(destGUID)] then	return end
	--[[
	Death line type:
	1: damage
	2: heal
	3: death
	4: insta kill
	5: death simulation (fd, sor proc)
	]]

	local destData = deathLog[destGUID]
	if not destData then
		destData = {c=0}
		deathLog[destGUID] = destData
	end

	if destData.sch then
		destData.sch:Cancel()
		destData.schFunc()

		destData.sch = nil
		destData.schFunc = nil
	end

	fightData_deathLog[#fightData_deathLog + 1] = destData
	deathLog[destGUID] = nil

	destData.h = {3,destGUID,timestamp,active_segment}

	return destData

end
function module.main.SPELL_SUMMON(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID)
	fightData.summons[#fightData.summons+1]={sourceGUID,destGUID,spellID,timestamp,sourceFlags2,destFlags2,s = active_segment}
end
function module.main.SPELL_DISPEL(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,_,destSpell)
	fightData.dispels[#fightData.dispels+1]={sourceGUID,destGUID,spellID,destSpell,timestamp,sourceFlags2,destFlags2,s = active_segment}
end
function module.main.SPELL_AURA_BROKEN_SPELL(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,_,extraSpellId,_,_,auraType)
	if not auraType then
		auraType = extraSpellId		--SPELL_AURA_BROKEN instead SPELL_AURA_BROKEN_SPELL
		extraSpellId = 6603
	end
	fightData.aurabroken[#fightData.aurabroken+1]={sourceGUID,destGUID,spellID,extraSpellId,timestamp,auraType,sourceFlags2,destFlags2,s = active_segment}
end
function module.main.ENVIRONMENTAL_DAMAGE(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,environmentalType,amount,overkill,school,resisted,blocked,absorbed,critical,glancing,crushing,isOffHand)
	local environmentalSpellID = environmentalType and EnvironmentalTypeToSpellID[environmentalType] or 48360

	return CLEU["SPELL_DAMAGE"](timestamp,"SPELL_DAMAGE",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,environmentalSpellID,nil,nil,amount,overkill,school,resisted,blocked,absorbed,critical,glancing,crushing,isOffHand)
end
function module.main.SPELL_INTERRUPT(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,_,destSpell)
	fightData.interrupts[#fightData.interrupts+1]={sourceGUID,destGUID,spellID,destSpell,timestamp,sourceFlags2,destFlags2,s = active_segment}
end
function module.main.DAMAGE_SPLIT(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14)
	return CLEU["SPELL_DAMAGE"](timestamp,"SPELL_DAMAGE",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14)
end
function module.main.SPELL_RESURRECT(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID)
	fightData.resurrests[#fightData.resurrests+1]={sourceGUID,destGUID,spellID,timestamp,s = active_segment}
end
function module.main.SPELL_DRAIN(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,_,amount,powerType)
	return CLEU["SPELL_ENERGIZE"](timestamp,"SPELL_ENERGIZE",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,-amount,powerType)
end
function module.main.SPELL_LEECH(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,_,amount,powerType,extraAmount)
	if extraAmount then
		CLEU["SPELL_ENERGIZE"](timestamp,"SPELL_ENERGIZE",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,extraAmount,powerType)
	end
	return CLEU["SPELL_ENERGIZE"](timestamp,"SPELL_ENERGIZE",hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,nil,nil,-amount,powerType)
end
function module.main.SPELL_INSTAKILL(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,spellID,_,school)
	local destData = deathLog[destGUID]	--destData
	if not destData then
		destData = {c=0}
		deathLog[destGUID] = destData
	end
	local tmpVar = destData.c + 1
	if tmpVar > deathMaxEvents then
		tmpVar = 1
	end
	destData.c = tmpVar
	local destLine = destData[tmpVar]
	if not destLine then
		destLine = {}
		destData[tmpVar] = destLine
	end
	destLine.t = 4
	destLine.s = sourceGUID
	destLine.ti = timestamp
	destLine.sp = spellID
	destLine.a = nil
	destLine.o = nil
	destLine.sc = nil
	destLine.b = nil
	destLine.ab = nil
	destLine.c = nil
	destLine.ia = nil
	destLine.sm = sourceFlags2
	destLine.dm = destFlags2
end


CLEU = {
	SPELL_DAMAGE = module.main.SPELL_DAMAGE,
	SPELL_PERIODIC_DAMAGE = module.main.SPELL_DAMAGE,
	SPELL_HEAL = module.main.SPELL_HEAL,
	SPELL_PERIODIC_HEAL = module.main.SPELL_HEAL,
	SPELL_AURA_APPLIED = module.main.SPELL_AURA_APPLIED,
	SPELL_AURA_REMOVED = module.main.SPELL_AURA_REMOVED,
	SPELL_CAST_SUCCESS = module.main.SPELL_CAST_SUCCESS,
	SPELL_EMPOWER_END = module.main.SPELL_CAST_SUCCESS,
	SPELL_ENERGIZE = module.main.SPELL_ENERGIZE,
	SPELL_PERIODIC_ENERGIZE = module.main.SPELL_ENERGIZE,
	SWING_DAMAGE = module.main.SWING_DAMAGE,
	SPELL_AURA_APPLIED_DOSE = module.main.SPELL_AURA_APPLIED_DOSE,
	SPELL_CAST_START = module.main.SPELL_CAST_START,
	SPELL_EMPOWER_START = module.main.SPELL_CAST_START,
	SPELL_ABSORBED = module.main.SPELL_ABSORBED,
	SPELL_MISSED = module.main.SPELL_MISSED,
	RANGE_MISSED = module.main.SPELL_MISSED,
	SPELL_PERIODIC_MISSED = module.main.SPELL_MISSED,
	SWING_MISSED = module.main.SWING_MISSED,
	RANGE_DAMAGE = module.main.RANGE_DAMAGE,
	SPELL_AURA_REMOVED_DOSE = module.main.SPELL_AURA_REMOVED_DOSE,
	UNIT_DIED = module.main.UNIT_DIED,
	UNIT_DESTROYED = module.main.UNIT_DIED,
	SPELL_SUMMON = module.main.SPELL_SUMMON,
	SPELL_CREATE = module.main.SPELL_SUMMON,
	SPELL_DISPEL = module.main.SPELL_DISPEL,
	SPELL_STOLEN = module.main.SPELL_DISPEL,
	SPELL_AURA_BROKEN_SPELL = module.main.SPELL_AURA_BROKEN_SPELL,
	SPELL_AURA_BROKEN = module.main.SPELL_AURA_BROKEN_SPELL,
	ENVIRONMENTAL_DAMAGE = module.main.ENVIRONMENTAL_DAMAGE,
	SPELL_INTERRUPT = module.main.SPELL_INTERRUPT,
	DAMAGE_SPLIT = module.main.DAMAGE_SPLIT,
	SPELL_RESURRECT = module.main.SPELL_RESURRECT,
	SPELL_DRAIN = module.main.SPELL_DRAIN,
	SPELL_PERIODIC_DRAIN = module.main.SPELL_DRAIN,
	SPELL_LEECH = module.main.SPELL_LEECH,
	SPELL_PERIODIC_LEECH = module.main.SPELL_LEECH,
	SPELL_INSTAKILL = module.main.SPELL_INSTAKILL,
}

CLEUParser = function(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13)
	if not guidData[sourceGUID] then guidData[sourceGUID] = sourceName or "nil" end
	if not guidData[destGUID] then guidData[destGUID] = destName or "nil" end

	reactionData[sourceGUID] = sourceFlags
	reactionData[destGUID] = destFlags

	sourceFlags2 = bit_band(sourceFlags2, COMBATLOG_OBJECT_RAIDTARGET_MASK)
	destFlags2 = bit_band(destFlags2, COMBATLOG_OBJECT_RAIDTARGET_MASK)

	local func = CLEU[event]
	if func then
		return func(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13)
	else
		return
	end

	-- DAMAGE_SHIELD
	-- DAMAGE_SHIELD_MISSED
	-- UNIT_DISSIPATES
	-- SPELL_BUILDING_DAMAGE
	-- SPELL_BUILDING_HEAL
end
if ExRT.isClassic and not ExRT.isCata then
	CLEUParser = function(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13)
		if event ~= "SWING_DAMAGE" and event ~= "SWING_MISSED" then
			val1 = val2
			if event == "SPELL_PERIODIC_DAMAGE" then event = "SPELL_DAMAGE"
			elseif event == "SPELL_PERIODIC_HEAL" then event = "SPELL_HEAL" 
			elseif event == "SPELL_PERIODIC_MISSED" then event = "SPELL_MISSED" end
		end

		if not guidData[sourceGUID] then guidData[sourceGUID] = sourceName or "nil" end
		if not guidData[destGUID] then guidData[destGUID] = destName or "nil" end
	
		reactionData[sourceGUID] = sourceFlags
		reactionData[destGUID] = destFlags

		sourceFlags2 = bit_band(sourceFlags2, COMBATLOG_OBJECT_RAIDTARGET_MASK)
		destFlags2 = bit_band(destFlags2, COMBATLOG_OBJECT_RAIDTARGET_MASK)
	
		local func = CLEU[event]
		if func then
			return func(timestamp,event,hideCaster,sourceGUID,sourceName,sourceFlags,sourceFlags2,destGUID,destName,destFlags,destFlags2,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13)
		else
			return
		end
	end
end

module.main.COMBAT_LOG_EVENT_UNFILTERED2 = CLEUParser

function module.main.COMBAT_LOG_EVENT_UNFILTERED(timestamp,...)
	if not module.db.timeFix then
		module.db.timeFix = {GetTime(),timestamp}
	end
	module.main.COMBAT_LOG_EVENT_UNFILTERED = CLEUParser
	module.main.COMBAT_LOG_EVENT_UNFILTERED2 = nil
	CLEUParser(timestamp,...)
	module:RegisterEvents('COMBAT_LOG_EVENT_UNFILTERED')
end

function module.main:RAID_BOSS_EMOTE(msg,sender)
	local spellID = msg:match("spell:(%d+)")
	if spellID then
		fightData.chat[ #fightData.chat + 1 ] = {sender,msg,spellID,GetTime(),s = active_segment}
	end
end
module.main.RAID_BOSS_WHISPER = module.main.RAID_BOSS_EMOTE

function module.main:UNIT_TARGET(unitID)
	local targetGUID = UnitGUID(unitID.."target")
	if targetGUID and not UnitIsPlayerOrPet(targetGUID) then
		local sourceGUID = UnitGUID(unitID)
		if GetUnitTypeByGUID(sourceGUID) == 0 then
			local targetTable = fightData_switch[targetGUID]
			if not targetTable then
				targetTable = {
					[1]={},	--cast
					[2]={},	--target
					seen=module.db.timeFix and (GetTime() - module.db.timeFix[1] + module.db.timeFix[2]) or GetTime(),
				}
				fightData_switch[targetGUID] = targetTable
			end
			local targetCastTable = targetTable[2]
			if not targetCastTable[sourceGUID] then
				targetCastTable[sourceGUID] = {GetTime()}
			end
		end
		if not fightData_maxHP[targetGUID] then
			fightData_maxHP[targetGUID] = UnitHealthMax(unitID.."target")
		end
	end
end

function module.main:UPDATE_MOUSEOVER_UNIT()
	local sourceGUID = UnitGUID("mouseover")
	if sourceGUID and not fightData_maxHP[sourceGUID] then
		fightData_maxHP[sourceGUID] = UnitHealthMax("mouseover")

		if not guidData[sourceGUID] then
			guidData[sourceGUID] = UnitName("mouseover") or "nil"
		end
	end
end

local function GlobalRecordStart()
	if not VMRT.BossWatcher.enabled then
		return
	end
	module:UnregisterEvents('PLAYER_REGEN_DISABLED','PLAYER_REGEN_ENABLED','ENCOUNTER_START','ENCOUNTER_END')
	if fightData then
		_BW_End()
	end
	_BW_Start()

	print(L.BossWatcherRecordStart)
end

local function GlobalRecordEnd()
	if not VMRT.BossWatcher.enabled then
		return
	end
	_BW_End()
	module:RegisterEvents('PLAYER_REGEN_DISABLED','PLAYER_REGEN_ENABLED','ENCOUNTER_START','ENCOUNTER_END')
	print(L.BossWatcherRecordStop)
end

function module:slash(arg)
	if arg == "bw s" or arg == "bw start" or arg == "fl s" or arg == "fl start" then
		GlobalRecordStart()
		print( ExRT.F.CreateChatLink("BWGlobalRecordEnd",GlobalRecordEnd,L.BossWatcherStopRecord), L.BossWatcherStopRecord2 )
	elseif arg == "bw e" or arg == "bw end" or arg == "fl e" or arg == "fl end" then
		GlobalRecordEnd()
	elseif arg == "bw" or arg == "fl" then
		BWInterfaceFrameLoadFunc()
	elseif arg == "bw clear" or arg == "fl clear" or arg == "bw c" or arg == "fl c" then
		module:ClearData()
		print('Cleared')
	elseif arg == "bw reset" or arg == "fl reset" then
		VMRT.BossWatcher.SAVED_DATA = nil
		print('Cleared')
	elseif arg == "bw save" or arg == "fl save" then
		VMRT.BossWatcher.saveVariables = true
		VMRT.BossWatcher.SAVED_DATA = module.db.data
		print('Saved')
	elseif arg == "bw allenergy" or arg == "fl allenergy" then
		module.db.allEnergyMode = not module.db.allEnergyMode
		print('All Energy Mode',module.db.allEnergyMode)
	elseif arg == "bw phase" or arg == "fl phase" then
		if active_phase then
			active_phase = active_phase + 1
			print('Jump to phase',active_phase)
		end
	elseif arg:find("^bw ") or arg:find("^fl ") then
		ExRT.F:FightLog_Open()
	elseif arg == "help" then
		print("|cff00ff00/rt fl|r - open fight log tab")
		print("|cff00ff00/rt fl s|r - manual start logging fight for fight log")
		print("|cff00ff00/rt fl e|r - manual stop logging fight for fight log")
	end
end

function module:ClearData(isFirstLoad)
	module.db.lastFightID = module.db.lastFightID + 1
	module.db.nowNum = 1
	module.db.data = {
		{
			guids = {},
			raidguids = {},
			reaction = {},
			pets = {},
			encounterStartGlobal = time(),
			encounterStart = GetTime(),
			encounterEnd = GetTime()+1,
			isEnded = true,
			graphData = {},
			positionsData = {},
			segments = {
				[1] = {
					e=true,
					t=GetTime(),
				},
			},
			damage = {},
			damage_seen = {},
			heal = {},
			healFrom = {},
			switch = {},
			cast = {},
			interrupts = {},
			dispels = {},
			auras = {},
			power = {},
			dies = {},
			chat = {},
			resurrests = {},
			summons = {},
			aurabroken = {},
			deathLog = {},
			maxHP = {},
			reduction = {},
			tracking = {},
			fightID = module.db.lastFightID,
			other = {
				roles = {},
				rolesGUID = {},
			},
		},
	}
	if isFirstLoad then
		return
	end
	ExRT.F.ScheduleTimer(collectgarbage, 1, "collect")
	if BWInterfaceFrame and BWInterfaceFrame:IsShown() then
		BWInterfaceFrame:Hide()
		BWInterfaceFrame:Show()
	end
end

function BWInterfaceFrameLoad()
	--if InCombatLockdown() then
	--	print(L.SetErrorInCombat)
	--	return
	--end
	isBWInterfaceFrameLoaded = true

	if not module.db.data[1] then
		module:ClearData(true)
	end

	-- Some upvaules
	local ipairs,pairs,tonumber,tostring,format,date,min,sort,table = ipairs,pairs,tonumber,tostring,format,date,min,sort,table
	local GetSpellInfo = ExRT.F.GetSpellInfo or GetSpellInfo
	if ExRT.isClassic and not ExRT.isCata then
		local _GetSpellInfo = GetSpellInfo
		function GetSpellInfo(spellID)
			if type(spellID) == 'string' then
				local sN = _GetSpellInfo(spellID)
				if sN then
					return _GetSpellInfo(spellID)
				else
					return spellID,false,"Interface\\Icons\\INV_MISC_QUESTIONMARK"
				end
			else
				return _GetSpellInfo(spellID)
			end
		end
	end

	local CurrentFight = nil

	local BWInterfaceFrame_Name = 'GMRTBWInterfaceFrame'
	BWInterfaceFrame = ELib:Template("ExRTBWInterfaceFrame",UIParent)
	_G[BWInterfaceFrame_Name] = BWInterfaceFrame
	BWInterfaceFrame:SetPoint("CENTER",0,0)
	BWInterfaceFrame.HeaderText:SetText(L.BossWatcher)
	BWInterfaceFrame.backToInterface:SetText("<<")
	BWInterfaceFrame:SetMovable(true)
	BWInterfaceFrame:RegisterForDrag("LeftButton")
	BWInterfaceFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
	BWInterfaceFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
	BWInterfaceFrame:SetDontSavePosition(true)

	ELib:ShadowInside(BWInterfaceFrame)

	module.options.SecondFrame = BWInterfaceFrame

	BWInterfaceFrame.border = ELib:Shadow(BWInterfaceFrame,20)

	BWInterfaceFrame.DecorationLine = ELib:Frame(BWInterfaceFrame):Point("TOPLEFT",BWInterfaceFrame,0,-40):Point("BOTTOMRIGHT",BWInterfaceFrame,"TOPRIGHT",0,-60):Texture(1,1,1,1):TexturePoint('x')
	BWInterfaceFrame.DecorationLine.texture:SetGradient("VERTICAL",CreateColor(.24,.25,.30,1), CreateColor(.27,.28,.33,1))

	BWInterfaceFrame.backToInterface.tooltipText = L.BossWatcherBackToInterface
	BWInterfaceFrame.buttonClose.tooltipText = L.BossWatcherButtonClose

	BWInterfaceFrame:Hide()

	BWInterfaceFrame.bossButton:SetText(L.BossWatcherLastFight)
	BWInterfaceFrame.bossButton:SetWidth(BWInterfaceFrame.bossButton:GetTextWidth()+30)

	BWInterfaceFrame.phaseButton = ELib:Template("ExRTButtonTransparentTemplate",BWInterfaceFrame)
	BWInterfaceFrame.phaseButton:SetHeight(18)
	BWInterfaceFrame.phaseButton:SetPoint("LEFT",BWInterfaceFrame.bossButton,"RIGHT",10,0)
	BWInterfaceFrame.phaseButton:SetText(L.BossWatcherAllPhases.." |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:64:80:64:80|t")
	BWInterfaceFrame.phaseButton:SetWidth(BWInterfaceFrame.phaseButton:GetTextWidth()+30)

	local reportData = {{},{},{},{ {},{},{} },{},{},{},{},{}}
	local reportOptions = {}
	BWInterfaceFrame.report = ELib:Button(BWInterfaceFrame,L.BossWatcherCreateReport):Size(150,18):Point("TOPRIGHT",BWInterfaceFrame,"TOPRIGHT",-4,-18):Tooltip(L.BossWatcherCreateReportTooltip):OnClick(function ()
		local activeTab = BWInterfaceFrame.tab.selected

		---Tab with mobs fix
		if activeTab == 4 then
			local activeTabOnPage = BWInterfaceFrame.tab.tabs[4].infoTabs.selected
			for i=1,#reportData[4][activeTabOnPage] do
				reportData[4][activeTabOnPage][i] = reportData[4][activeTabOnPage][i]:gsub("||","")
			end
			ExRT.F:ToChatWindow(reportData[4][activeTabOnPage])
			return
		end

		for i=1,#reportData[activeTab] do
			reportData[activeTab][i] = reportData[activeTab][i]:gsub("||","")
		end
		ExRT.F:ToChatWindow(reportData[activeTab],nil,reportOptions[activeTab])
	end)
	BWInterfaceFrame.report:Hide()


	---- Helpful functions
	local function GetGUID(GUID)
		if GUID and CurrentFight.guids[GUID] and CurrentFight.guids[GUID] ~= "nil" then
			return CurrentFight.guids[GUID]
		else
			return L.BossWatcherUnknown
		end
	end

	local function GetPetsDB()
		return CurrentFight.pets
	end

	local function CloseDropDownMenus_fix()
		CloseDropDownMenus()
		return 4
	end

	local function timestampToFightTime(time)
		if not time then
			return 0
		end
		local fixTable = CurrentFight.timeFix
		if not fixTable and module.db.timeFix then
			fixTable = module.db.timeFix
		elseif not fixTable and not module.db.timeFix then
			return 0
		end
		local res = time - (fixTable[2] - fixTable[1] + CurrentFight.encounterStart) 
		return max(res,0)
	end

	local function GUIDtoText(patt,GUID)
		if GUID and GUID ~= "" then
			patt = patt or "%s"
			local _type = ExRT.F.GetUnitTypeByGUID(GUID)
			if _type == 0 then
				return ""
			elseif _type == 3 or _type == 5 then
				local mobSpawnID,mobSpawnID1,mobSpawnID2,mobSpawnID3 = nil
				local spawnID = GUID:match("%-([^%-]+)$")
				if spawnID then
					mobSpawnID = tonumber(spawnID, 16)
					mobSpawnID1 = tonumber(spawnID:sub(1,5), 16) or 0
					mobSpawnID2 = tonumber(spawnID:sub(6,8), 16) or 0
					mobSpawnID3 = tonumber(spawnID:sub(9), 16) or 0

					local unitType,_,serverID,instanceID,zoneUID,id,spawnID = strsplit("-", GUID or "")
					if id and unitType == "Creature" or unitType == "Vehicle" then
						--local spawnEpoch = GetServerTime() - (GetServerTime() % 2^23)
						local spawnEpochOffset = bit.band(tonumber(string.sub(spawnID, 5), 16), 0x7fffff)
						local spawnIndex = bit.rshift(bit.band(tonumber(string.sub(spawnID, 1, 5), 16), 0xffff8), 3)
						--local spawnTime = spawnEpoch + spawnEpochOffset
						
						--if spawnTime > GetServerTime() then
						--	spawnTime = spawnTime - ((2^23) - 1)
						--end
						
						--mobSpawnID2 = format("%X",spawnEpochOffset)
						mobSpawnID2 = spawnEpochOffset
						mobSpawnID3 = spawnIndex
					end
				end
				if mobSpawnID then
					--return format(patt,tostring(mobSpawnID)..", "..mobSpawnID2.."-"..mobSpawnID1)
					--return format(patt,mobSpawnID2.."-"..mobSpawnID3.."-"..mobSpawnID1)
					return format(patt,mobSpawnID2..":"..mobSpawnID3)
				else
					return format(patt,GUID)
				end
			else
				return format(patt,GUID)
			end
		else
			return ""
		end
	end

	local function SetSchoolColorsToLine(self,school)
		local isNotGradient = ExRT.F.table_find(module.db.schoolsDefault,school) or school == 0 or module.db.schoolsColors[school or -1]
		local isConfirmedGradient = module.db.schoolsColorsGradient[ school or -1 ]
		if isNotGradient and module.db.schoolsColors[school] then
			self:SetVertexColor(module.db.schoolsColors[school].r,module.db.schoolsColors[school].g,module.db.schoolsColors[school].b, 1)
		elseif isConfirmedGradient then
			local school1,school2 = isConfirmedGradient[1],isConfirmedGradient[2]
			self:SetVertexColor(1,1,1,1)
			self:SetGradient("HORIZONTAL",CreateColor(module.db.schoolsColors[school1].r,module.db.schoolsColors[school1].g,module.db.schoolsColors[school1].b,1), CreateColor(module.db.schoolsColors[school2].r,module.db.schoolsColors[school2].g,module.db.schoolsColors[school2].b,1))
		else
			local school1,school2 = nil
			for i=1,#module.db.schoolsDefault do
				local isSchool = bit.band(school,module.db.schoolsDefault[i]) > 0
				if isSchool and not school1 then
					school1 = module.db.schoolsDefault[i]
				elseif isSchool and not school2 then
					school2 = module.db.schoolsDefault[i]
				end
			end
			if school1 and school2 then
				self:SetVertexColor(1,1,1,1)
				self:SetGradient("HORIZONTAL",CreateColor(module.db.schoolsColors[school1].r,module.db.schoolsColors[school1].g,module.db.schoolsColors[school1].b,1), CreateColor(module.db.schoolsColors[school2].r,module.db.schoolsColors[school2].g,module.db.schoolsColors[school2].b,1))
			elseif school1 and not school2 then
				self:SetVertexColor(module.db.schoolsColors[school1].r,module.db.schoolsColors[school1].g,module.db.schoolsColors[school1].b, 1)
			else
				self:SetVertexColor(0.8,0.8,0.8, 1)
			end
		end
	end
	local function GetSchoolName(school)
		if not school or module.db.schoolsNames[school]	then
			return  module.db.schoolsNames[school or 0]
		else
			local school1,school2 = nil
			for i=1,#module.db.schoolsDefault do
				local isSchool = bit.band(school,module.db.schoolsDefault[i]) > 0
				if isSchool and not school1 then
					school1 = module.db.schoolsDefault[i]
				elseif isSchool and not school2 then
					school2 = module.db.schoolsDefault[i]
				end
			end
			if school1 and school2 then
				return module.db.schoolsNames[school1] .. "-" .. module.db.schoolsNames[school2]
			elseif school1 and not school2 then
				return module.db.schoolsNames[school1]
			else
				return module.db.schoolsNames[0]
			end
		end
	end
	local function GetUnitInfoByUnitFlagFix(unitFlag,infoType)
		if not unitFlag then
			return
		end
		return GetUnitInfoByUnitFlag(unitFlag,infoType)
	end
	local function GetFightLength(full)
		if full then
			if not CurrentFight.isEnded then
				return GetTime() - CurrentFight.encounterStart
			end
			return (CurrentFight.encounterEnd - CurrentFight.encounterStart)
		end
		local length = 0
		for i=1,#CurrentFight.segments do
			if CurrentFight.segments[i].e then
				length = length - CurrentFight.segments[i].t + (CurrentFight.segments[i+1] and CurrentFight.segments[i+1].t or (CurrentFight.isEnded and CurrentFight.encounterEnd or GetTime()) )
			end
		end
		if length == 0 then
			length = 0.01
		end
		return length
	end
	local function SubUTF8String(str,len)
		local strlen = ExRT.F.utf8len(str)
		if strlen > len then
			str = ExRT.F.utf8sub(str,1,len) .. "..."
		end
		return str
	end
	local function GetFightID(data,short)
		local r = tostring(data.encounterStart)
		if short then
			r = r .. "-" .. GetFightLength(true)
		else
			for i=1,#data.segments do
				if data.segments[i].e then
					r = r .. "," .. i
				end
			end
		end
		return r
	end
	local GetTargetIconText = ExRT.F.GetRaidTargetText

	---- Locals for functions in code below
	local SpellsPage_GetCastsNumber,AurasPage_IsAuraOn,Graph_AutoUpdateStep = nil



	---- Bugfix functions
	local _GetSpellLink = C_Spell and C_Spell.GetSpellLink or GetSpellLink
	local function GetSpellLink(spellID)
		local link = _GetSpellLink(spellID or 0)
		if link then
			return link
		end
		local spellName = GetSpellInfo(spellID or 0)
		return spellName or "Unk"
	end

	---- Update functions
	local function UpdateSegments(start,ending,isAdd,disableReload)
		if isAdd and start and ending then
			for i=1,#CurrentFight.segments do
				if (i>=start and i<=ending) then
					CurrentFight.segments[i].e = true
				end
			end
		else
			for i=1,#CurrentFight.segments do
				CurrentFight.segments[i].e = not start or not ending or (i>=start and i<=ending)
			end
		end
		if not disableReload then
			BWInterfaceFrame:Hide()
			BWInterfaceFrame:Show()	 
		end
	end
	local function UpdateSegments_SelectPhase(phase)
		local minX,maxX = #CurrentFight.segments,1
		for i=1,#CurrentFight.segments do
			CurrentFight.segments[i].e = CurrentFight.segments[i].p == phase
			if CurrentFight.segments[i].p == phase then
				if i < minX then
					minX = i
				end
				if i > maxX then
					maxX = i
				end
			end
		end
		if minX ~= #CurrentFight.segments or maxX ~= 1 then
			BWInterfaceFrame.GraphFrame.G.ZoomMinX = minX - 1
			BWInterfaceFrame.GraphFrame.G.ZoomMaxX = maxX + 1
		end
		BWInterfaceFrame:Hide()
		BWInterfaceFrame:Show()
	end

	local function UpdateSegmentsTime(start,ending,isAdd,disableReload)
		local s,e = nil,nil
		local totalSegments = #CurrentFight.segments
		for j=1,totalSegments - 1 do
			if CurrentFight.segments[j].t <= start and CurrentFight.segments[j+1].t > start and not s then
				s = j
				e = j
			elseif CurrentFight.segments[j].t <= ending and CurrentFight.segments[j+1].t > ending and s then
				e = j
				break
			end
		end
		if ending > CurrentFight.segments[totalSegments].t then
			e = totalSegments
		end
		if s and e then
			UpdateSegments(s,e,isAdd,disableReload)
		end
	end




	BWInterfaceFrame:SetScript("OnShow",function (self)
		local fightData = module.db.data[module.db.nowNum]
		local fightID = GetFightID(fightData)
		if self.nowFightID ~= fightID then
			CurrentFight = fightData
			local isInRecording = not fightData.isEnded
			if isInRecording then
				fightData.encounterEnd = GetTime()
				--print(L.BossWatcherCombatError)
				--return
			end
			self.nowFightID = fightID
			fightData.fightID = fightID
			local nowFightIDShort = GetFightID(CurrentFight,true)
			if nowFightIDShort ~= self.nowFightIDShort then
				BWInterfaceFrame.phaseButton:SetText(L.BossWatcherAllPhases.." |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:64:80:64:80|t")
				BWInterfaceFrame.phaseButton:SetWidth(BWInterfaceFrame.phaseButton:GetTextWidth()+30)
			end
			self.nowFightIDShort = nowFightIDShort
			local _time = ((isInRecording and GetTime() or fightData.encounterEnd) - fightData.encounterStart)
			self.bossButton:SetText( (fightData.encounterName or L.BossWatcherLastFight)..date(": %H:%M - ", fightData.encounterStartGlobal )..date("%H:%M", fightData.encounterStartGlobal + _time )..format(" (%dm%02ds)",floor(_time/60),_time%60 )..(isInRecording and " *" or "").." |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:64:80:64:80|t" )
			self.bossButton:SetWidth(self.bossButton:GetTextWidth()+30)
			for i=1,#reportData do
				if i ~= 4 then
					wipe(reportData[i])
				else
					wipe(reportData[4][1])
					wipe(reportData[4][2])
					wipe(reportData[4][3])
				end
			end
			if CurrentFight.segments.phaseNames then
				BWInterfaceFrame.phaseButton:Show()
			else
				BWInterfaceFrame.phaseButton:Hide()
			end
		end
		BWInterfaceFrame.tab:Show()
	end)
	BWInterfaceFrame:SetScript("OnHide",function (self)
		BWInterfaceFrame.tab:Hide()
	end)

	BWInterfaceFrame.bossButtonDropDown = CreateFrame("Frame", BWInterfaceFrame_Name.."BossButtonDropDown", nil, "UIDropDownMenuTemplate")
	BWInterfaceFrame.bossButton:SetScript("OnClick",function (self)
		local fightsList = {
			{
				text = L.BossWatcherSelectFight, 
				isTitle = true, 
				notCheckable = true, 
				notClickable = true 
			},
		}
		for i=1,#module.db.data do
			local colorCode = ""
			if i == module.db.nowNum then
				colorCode = "|cff00ff00"
			end
			local fightData = module.db.data[i]
			local _time = (fightData.isEnded and fightData.encounterEnd or GetTime()) - fightData.encounterStart
			fightsList[#fightsList + 1] = {
				text = i..". "..colorCode..(fightData.encounterName or L.BossWatcherLastFight)..date(": %H:%M - ", fightData.encounterStartGlobal )..date("%H:%M", fightData.encounterStartGlobal + _time )..format(" (%dm%02ds)",floor(_time/60),_time%60 )..(fightData.isEnded and "" or " *"),
				notCheckable = true,
				func = function() 
					module.db.nowNum = i
					self:SetText( (fightData.encounterName or L.BossWatcherLastFight)..date(": %H:%M - ", fightData.encounterStartGlobal )..date("%H:%M", fightData.encounterStartGlobal + _time )..format(" (%dm%02ds)",floor(_time/60),_time%60 )..(fightData.isEnded and "" or " *").." |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:64:80:64:80|t" )
					self:SetWidth(self:GetTextWidth()+30)
					if not fightData.isEnded then
						BWInterfaceFrame.nowFightID = -1
					end
					BWInterfaceFrame:Hide()
					BWInterfaceFrame:Show()
				end,
			}
		end
		fightsList[#fightsList + 1] = {
			text = L.cd2HistoryClear,
			notCheckable = true,
			func = function()
				StaticPopupDialogs["EXRT_FIGHTLOG_CLEAR"] = {
					text = L.cd2HistoryClear,
					button1 = L.YesText,
					button2 = L.NoText,
					OnAccept = function()
						module:ClearData()
					end,
					timeout = 0,
					whileDead = true,
					hideOnEscape = true,
					preferredIndex = 3,
				}
				StaticPopup_Show("EXRT_FIGHTLOG_CLEAR")
			end,
		}
		fightsList[#fightsList + 1] = {
			text = L.BossWatcherSelectFightClose,
			notCheckable = true,
			func = CloseDropDownMenus_fix,
		}
		if MenuUtil then
			MenuUtil.CreateContextMenu(BWInterfaceFrame.bossButtonDropDown, function(ownerRegion, rootDescription)
				for i=1,#fightsList do
					local menu = fightsList[i]
					if menu.isTitle then
						rootDescription:CreateTitle(menu.text)
					else
						rootDescription:CreateButton(menu.text, menu.func)
					end
				end
			end)
		else
			EasyMenu(fightsList, BWInterfaceFrame.bossButtonDropDown, "cursor", 10 , -15, "MENU")
		end
	end)
	BWInterfaceFrame.bossButton.tooltipText = L.BossWatcherSelectFight

	BWInterfaceFrame.phaseButton:SetScript("OnClick",function (self)
		local fightsList = {
			{
				text = L.BossWatcherAllPhases,
				notCheckable = true,
				func = function() 
					self:SetText( L.BossWatcherAllPhases.." |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:64:80:64:80|t" )
					self:SetWidth(self:GetTextWidth()+30)
					UpdateSegments()
				end,
			}
		}
		for i=1,#CurrentFight.segments.phaseNames do
			local name = CurrentFight.segments.phaseNames[i]
			if type(name)=='number' then
				if name < 0 then
					local ej_name = C_EncounterJournal.GetSectionInfo(-name)
					if ej_name then
						name = ej_name.title
					else
						name = L.BossWatcherPhase.." "..i
					end
				else
					name = L.BossWatcherPhase.." "..i
				end
			end
			fightsList[#fightsList + 1] = {
				text = name,
				notCheckable = true,
				func = function() 
					self:SetText( name.." |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:64:80:64:80|t" )
					self:SetWidth(self:GetTextWidth()+30)
					UpdateSegments_SelectPhase(i)
				end,
			}
		end
		fightsList[#fightsList + 1] = {
			text = L.BossWatcherSelectFightClose,
			notCheckable = true,
			func = CloseDropDownMenus_fix,
		}
		if MenuUtil then
			MenuUtil.CreateContextMenu(BWInterfaceFrame.bossButtonDropDown, function(ownerRegion, rootDescription)
				for i=1,#fightsList do
					local menu = fightsList[i]
					if menu.isTitle then
						rootDescription:CreateTitle(menu.text)
					else
						rootDescription:CreateButton(menu.text, menu.func)
					end
				end
			end)
		else
			EasyMenu(fightsList, BWInterfaceFrame.bossButtonDropDown, "cursor", 10 , -15, "MENU")
		end
	end)


	---- Tabs
	BWInterfaceFrame.tab = ELib:Tabs(BWInterfaceFrame,0,
		L.BossWatcherTabMobs,
		L.BossWatcherTabHeal,
		L.BossWatcherTabBuffsAndDebuffs,
		L.BossWatcherTabEnemy,
		L.BossWatcherTabPlayersSpells,
		L.BossWatcherTabEnergy,
		L.BossWatcherTabInterruptAndDispelShort,
		L.BossWatcherDeath,
		L.BossWatcherFrames,
		OTHER,
		L.BossWatcherTabSettings
	):Size(865,600):Point("TOP",0,-60):SetTo(1)

	BWInterfaceFrame.tab.tabs[7].button.tooltip = L.BossWatcherTabInterruptAndDispel
	BWInterfaceFrame.tab:SetBackdropBorderColor(0,0,0,0)
	BWInterfaceFrame.tab:SetBackdropColor(0,0,0,0)

	for i=1,#BWInterfaceFrame.tab.tabs do
		BWInterfaceFrame.tab.tabs[i].button.Left:SetWidth(11)
		BWInterfaceFrame.tab.tabs[i].button.Right:SetWidth(11)
	end

	BWInterfaceFrame.tab:Hide()

	---- Settings tab-button
	BWInterfaceFrame.tab.tabs[11]:SetScript("OnShow",function (self)
		if not module.options.isLoaded then
			module.options:GetScript("OnShow")(module.options)
		end
		module.options:SetParent(self)
		module.options:ClearAllPoints()
		module.options:SetPoint("TOPLEFT",5,-10)
		module.options:Show()
	end)


	---- TimeLine Frame
	BWInterfaceFrame.timeLineFrame = CreateFrame('Frame',nil,BWInterfaceFrame.tab)
	BWInterfaceFrame.timeLineFrame.width = 858
	BWInterfaceFrame.timeLineFrame:SetSize(BWInterfaceFrame.timeLineFrame.width,60)

	local TimeLine_Pieces = 60
	local function TimeLinePieceOnEnter(self)
		if self.tooltip and #self.tooltip > 0 then
			ELib.Tooltip.Show(self,"ANCHOR_RIGHT",L.BossWatcherTimeLineTooltipTitle..":",unpack(self.tooltip))
		end
	end
	local UpdateTimeLine, TimeLineFrame_ImprovedSelectSegment_GetSelected, TimeLineFrame_ImprovedSelectSegment_OnUpdate, TimeLineFrame_ImprovedSelectSegment_OnUpdate_Passive = nil
	do
		local TLframe = CreateFrame("Frame",nil,BWInterfaceFrame.timeLineFrame)
		BWInterfaceFrame.timeLineFrame.timeLine = TLframe
		TLframe:SetSize(BWInterfaceFrame.timeLineFrame.width,30)
		TLframe:SetPoint("TOP",0,0)
		do
			local tlWidth = BWInterfaceFrame.timeLineFrame.width/TimeLine_Pieces
			for i=1,TimeLine_Pieces do
				TLframe[i] = CreateFrame("Frame",nil,TLframe)
				TLframe[i]:SetSize(tlWidth,30)
				TLframe[i]:SetPoint("TOPLEFT",(i-1)*tlWidth,0)
				TLframe[i]:SetScript("OnEnter",TimeLinePieceOnEnter)
				TLframe[i]:SetScript("OnLeave",ELib.Tooltip.Hide)
			end
		end
		TLframe.texture = TLframe:CreateTexture(nil, "BACKGROUND",nil,0)
		--TLframe.texture:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\bar9.tga")
		--TLframe.texture:SetVertexColor(0.3, 1, 0.3, 1)
		TLframe.texture:SetColorTexture(1, 1, 1, 1)
		TLframe.texture:SetGradient("VERTICAL",CreateColor(1,0.82,0,.7), CreateColor(0.95,0.65,0,.7))
		TLframe.texture:SetAllPoints()

		TLframe.textLeft = ELib:Text(TLframe,"",12):Size(200,16):Point("BOTTOMLEFT",TLframe,"BOTTOMLEFT", 2, 2):Top():Color():Shadow()
		TLframe.textCenter = ELib:Text(TLframe,"",12):Size(200,16):Point("BOTTOM",TLframe,"BOTTOM", 0, 2):Top():Center():Color():Shadow()
		TLframe.textRight = ELib:Text(TLframe,"",12):Size(200,16):Point("BOTTOMRIGHT",TLframe,"BOTTOMRIGHT", -2, 2):Top():Right():Color():Shadow()

		TLframe.lifeUnderLine = TLframe:CreateTexture(nil, "BACKGROUND")
		TLframe.lifeUnderLine:SetColorTexture(1,1,1,1)
		TLframe.lifeUnderLine:SetGradient("VERTICAL",CreateColor(1,0.2,0.2,0), CreateColor(1,0.2,0.2, 0.7))
		TLframe.lifeUnderLine._SetPoint = TLframe.lifeUnderLine.SetPoint
		TLframe.lifeUnderLine.SetPoint = function(self,start,_end)
			self:ClearAllPoints()
			self:_SetPoint("TOPLEFT",self:GetParent(),"BOTTOMLEFT",start*BWInterfaceFrame.timeLineFrame.width,0)
			self:SetSize((_end-start)*BWInterfaceFrame.timeLineFrame.width,16)
			self:Show()
		end

		TLframe.arrow = CreateFrame("Frame",nil,TLframe)
		TLframe.arrow:SetSize(21,30)
		TLframe.arrow.G1 = TLframe.arrow:CreateTexture(nil, "BACKGROUND",nil,4)
		TLframe.arrow.G1:SetSize(4,30)
		TLframe.arrow.G1:SetPoint("LEFT",2,0)
		TLframe.arrow.G1:SetColorTexture(0,1,0)
		TLframe.arrow.G2 = TLframe.arrow:CreateTexture(nil, "BACKGROUND",nil,5)
		TLframe.arrow.G2:SetSize(2,30)
		TLframe.arrow.G2:SetPoint("LEFT",0,0)
		TLframe.arrow.G2:SetColorTexture(1,1,1)
		TLframe.arrow.G3 = TLframe.arrow:CreateTexture(nil, "BACKGROUND",nil,4)
		TLframe.arrow.G3:SetSize(15,30)
		TLframe.arrow.G3:SetPoint("LEFT",6,0)
		TLframe.arrow.G3:SetColorTexture(1,1,1)
		TLframe.arrow.G3:SetGradient("HORIZONTAL",CreateColor(0,1,0,1), CreateColor(0,1,0,0))
		TLframe.arrow:Hide()

		TLframe.timeSegments = {}
		local function TimeLine_UpdateSegments()
			local count = 0
			local totalSegments = #CurrentFight.segments
			for i=1,totalSegments do
				if CurrentFight.segments[i].e then
					count = count + 1
				end
			end

			if count == totalSegments then
				for i=1,#TLframe.timeSegments do
					TLframe.timeSegments[i]:Hide()
				end
				TLframe.ImprovedSelectSegment.ResetZoom:Hide()
			else
				local fightDuration = GetFightLength(true)
				local tlWidth,tlHeight = TLframe:GetWidth(),TLframe:GetHeight()
				for i=1,totalSegments do
					if not TLframe.timeSegments[i] then
						TLframe.timeSegments[i] = TLframe:CreateTexture(nil, "BACKGROUND",nil,1)
						TLframe.timeSegments[i]:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\bar9.tga")
						TLframe.timeSegments[i]:SetVertexColor(0.8, 0.8, 0.8, 1)
					end
					if CurrentFight.segments[i].e then
						TLframe.timeSegments[i]:Hide()
					else
						local timeStart = CurrentFight.segments[i].t - CurrentFight.encounterStart
						local timeEnd = (CurrentFight.segments[i+1] and CurrentFight.segments[i+1].t or (not CurrentFight.isEnded and GetTime() or CurrentFight.encounterEnd)) - CurrentFight.encounterStart
						local startPos = timeStart/fightDuration*tlWidth
						local endPos = timeEnd/fightDuration*tlWidth
						TLframe.timeSegments[i]:SetPoint("TOPLEFT",startPos,0)
						TLframe.timeSegments[i]:SetSize(max(endPos-startPos,0.5),tlHeight)
						TLframe.timeSegments[i]:Show()
					end
				end
				for i=totalSegments + 1,#TLframe.timeSegments do
					TLframe.timeSegments[i]:Hide()
				end
				TLframe.ImprovedSelectSegment.ResetZoom:Show()
			end
		end

		TLframe.labels = {}
		function TLframe:AddLabel(i,pos,type)
			local label = TLframe.labels[i]
			if not label then
				label = TLframe:CreateTexture(nil, "BACKGROUND")
				TLframe.labels[i] = label
				label:SetSize(3,25)
			end
			label:SetPoint("TOP",TLframe,"BOTTOMLEFT",BWInterfaceFrame.timeLineFrame.width*pos,0)
			if not type then
				label:SetColorTexture(.35,.38,1,.7)
			elseif type == 1 then
				label:SetColorTexture(.2,1,0,1)
			elseif type == 2 then
				label:SetColorTexture(1,.25,.3,.7)
			end
			label:Show()
		end
		function TLframe:HideLabels()
			for i=1,#TLframe.labels do
				TLframe.labels[i]:Hide()
			end
		end

		local EncountersPhases = {}

		TLframe.redLine = {}
		local function CreateRedLine(i)
			TLframe.redLine[i] = TLframe:CreateTexture(nil, "BACKGROUND",nil,3)
			TLframe.redLine[i]:SetColorTexture(0.7, 0.1, 0.1, 0.5)
			TLframe.redLine[i]:SetSize(2,30)
		end

		TLframe.blueLine = {}
		local function CreateBlueLine(i)
			TLframe.blueLine[i] = TLframe:CreateTexture(nil, "BACKGROUND",nil,4)
			TLframe.blueLine[i]:SetColorTexture(0.1, 0.1, 0.7, 0.5)
			TLframe.blueLine[i]:SetSize(3,30)
		end

		TLframe.phaseMarker = {}
		TLframe.phaseMarkerNum = 0
		TLframe.phaseMarkerMax = 0

		local function AddPhase(pos,phase)
			local currNum = TLframe.phaseMarkerNum + 1
			TLframe.phaseMarkerNum = currNum

			local l,l2,t = TLframe.phaseMarker[currNum],TLframe.phaseMarker[currNum+0.5],TLframe.phaseMarker[-currNum]
			if not l then
				l = TLframe:CreateTexture(nil, "BACKGROUND",nil,5)
				TLframe.phaseMarker[currNum] = l
				l:SetSize(2,30)
				l:SetColorTexture(1, 1, 1, 0.8)

				l2 = TLframe:CreateTexture(nil, "BACKGROUND",nil,5)
				TLframe.phaseMarker[currNum+0.5] = l2
				l2:SetSize(1,30)
				l2:SetColorTexture(0, 0, 0, 0.8)
				l2:SetPoint("TOPLEFT",l,"TOPRIGHT",0,0)

				t = ELib:Text(TLframe,"",10):Point("TOPLEFT",l,"TOPRIGHT",2,-1):Point("TOPRIGHT",TLframe,"TOPRIGHT",0,-1):Point("BOTTOM",TLframe):Left():Top():Color(1,1,1,1)
				t:SetMaxLines(1)
				TLframe.phaseMarker[-currNum] = t

				TLframe.phaseMarkerMax = max(currNum,TLframe.phaseMarkerMax)
			end
			local t_pos = BWInterfaceFrame.timeLineFrame.width * pos
			l:SetPoint("TOPLEFT",t_pos,0)
			t.pos = t_pos
			local phaseText = nil
			if type(phase)=='number' and phase < 0 then
				local name = C_EncounterJournal.GetSectionInfo(-phase)
				if name then
					phaseText = name.title
				end
			elseif type(phase)=='string' then
				phaseText = phase
			end
			local secondString 
			if currNum > 1 then
				local prev = TLframe.phaseMarker[-(currNum-1)]
				if prev.pos + prev:GetStringWidth() > t_pos then
					secondString = "|n"
				end
			end
			t:SetText((secondString or "")..(phaseText or (L.BossWatcherPhase.." "..phase)))
			if secondString then
				t:SetMaxLines(2)
			else
				t:SetMaxLines(1)
			end
			l:Show()
			l2:Show()
			t:Show()
		end

		function UpdateTimeLine()
			local fight_dur = GetFightLength(true)
			if fightData and fight_dur < 1.5 then
				fight_dur = GetTime() - CurrentFight.encounterStart
			end
			TLframe.textLeft:SetText( date("%H:%M:%S", CurrentFight.encounterStartGlobal) )
			TLframe.textRight:SetText( date("%M:%S", fight_dur) )
			TLframe.textCenter:SetText( date("%M:%S", fight_dur / 2) )

			TLframe.ImprovedSelectSegment:Show()
			for i=1,TimeLine_Pieces do
				TLframe[i]:Hide()
			end

			TLframe.phaseMarkerNum = 0
			for i=1,TLframe.phaseMarkerMax do
				TLframe.phaseMarker[i]:Hide()
				TLframe.phaseMarker[i+0.5]:Hide()
				TLframe.phaseMarker[-i]:Hide()
			end
			local CurrentEncountersPhases = CurrentFight.encounterID and EncountersPhases[CurrentFight.encounterID] or ExRT.NULL

			if CurrentFight.segments.phaseNames then
				local prev = CurrentFight.segments[1].p
				for i=2,#CurrentFight.segments do
					local sData = CurrentFight.segments[i]
					if prev ~= sData.p then
						local _time = sData.t - CurrentFight.encounterStart
						prev = sData.p

						local name = CurrentFight.segments.phaseNames[prev]
						if type(name)=='number' then
							if name < 0 then
								local ej_name = C_EncounterJournal.GetSectionInfo(-name)
								if ej_name then
									name = ej_name.title
								else
									name = L.BossWatcherPhase.." "..i
								end
							else
								name = L.BossWatcherPhase.." "..i
							end
						end

						AddPhase(_time / fight_dur,name or prev)
					end
				end
				CurrentEncountersPhases = ExRT.NULL
			end

			local redLineNum = 0
			for i=1,TimeLine_Pieces do
				if not TLframe[i].tooltip then
					TLframe[i].tooltip = {}
				end
				wipe(TLframe[i].tooltip)
			end

			if CurrentEncountersPhases.aura then
				local phasesAuras = CurrentEncountersPhases.aura
				for i,data in ipairs(CurrentFight.auras) do
					if phasesAuras[ data[6] ] then
						local phaseData = phasesAuras[ data[6] ]
						if (phaseData.isFade and data[8] == 2) or (not phaseData.isFade and data[8] == 1) then
							local _time = timestampToFightTime(data[1])
							AddPhase(_time / fight_dur,phaseData.phase)
						end
					end
				end
			end

			local addToToolipTable = {}
			local bossHpPerSegment = {}
			if CurrentFight.graphData then
				local lastSec = 0
				for sec,data in pairs(CurrentFight.graphData) do
					lastSec = max(lastSec,sec)
				end
				local antiSpam = {}

				local phaseHpStart = 1
				for sec=1,lastSec do
					local data = CurrentFight.graphData[sec]
					if data then
						local boss1 = data["boss1"]
						if boss1 then
							local hpMax = boss1.hpmax
							if hpMax ~= 0 and boss1.health then
								local tooltipIndex = sec / fight_dur
								tooltipIndex = min( floor( (TimeLine_Pieces - 0.01)*tooltipIndex + 1 ) , TimeLine_Pieces)

								local hp = boss1.health/hpMax
								if not bossHpPerSegment[tooltipIndex] then
									bossHpPerSegment[tooltipIndex] = (boss1.name or "boss1").."'s hp: "..format("%.1f%%",hp*100)
								end
								if CurrentEncountersPhases.hp then
									for i=phaseHpStart,#CurrentEncountersPhases.hp do
										local data = CurrentEncountersPhases.hp[i]
										if hp <= data.hp then
											AddPhase(sec / fight_dur,data.phase)
											phaseHpStart = i+1
											break
										end
									end
								end
							end
						end
						for i=2,5 do
							local boss = data["boss"..i]
							if boss then
								local hpMax = boss.hpmax
								if hpMax ~= 0 and boss.health then
									local hp = boss.health/hpMax
									local str = (boss.name or "boss"..i).."'s hp: "..format("%.1f%%",hp*100)

									local tooltipIndex = sec / fight_dur
									tooltipIndex = min( floor( (TimeLine_Pieces - 0.01)*tooltipIndex + 1 ) , TimeLine_Pieces)

									antiSpam[tooltipIndex] = antiSpam[tooltipIndex] or {}

									if not antiSpam[tooltipIndex]["boss"..i] then
										if not bossHpPerSegment[tooltipIndex] then
											bossHpPerSegment[tooltipIndex] = str
										else
											bossHpPerSegment[tooltipIndex] = bossHpPerSegment[tooltipIndex] .. "|n" .. str 
										end
										antiSpam[tooltipIndex]["boss"..i] = true
									end
								end
							end
						end
					end
				end
			end
			for mobGUID,mobData in pairs(CurrentFight.cast) do
				for i=1,#mobData do
					local castData = mobData[i]
					if castData[7] and ExRT.F.GetUnitInfoByUnitFlag(castData[7],3) ~= 16 then
						local _time = timestampToFightTime(castData[1])

						local tooltipIndex = _time / fight_dur

						if CurrentEncountersPhases.cast then
							local phaseData = CurrentEncountersPhases.cast[ castData[2] ]
							if phaseData and ((phaseData.isCastStart and castData[3] == 2) or (not phaseData.isCastStart and castData[3] == 1)) then
								AddPhase(tooltipIndex,phaseData.phase)
							end
							if phaseData and phaseData.next and ((phaseData.next.isCastStart and castData[3] == 2) or (not phaseData.next.isCastStart and castData[3] == 1)) then
								local newTime = _time + phaseData.next.time
								if newTime < fight_dur then
									AddPhase(newTime / fight_dur,phaseData.next.phase)
								end
							end
						end

						if CurrentFight.segments[castData.s].e then
							redLineNum = redLineNum + 1
							if not TLframe.redLine[redLineNum] then
								CreateRedLine(redLineNum)
							end
							TLframe.redLine[redLineNum]:SetPoint("TOPLEFT",TLframe,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*tooltipIndex,0)
							TLframe.redLine[redLineNum]:Show()

							tooltipIndex = min( floor( (TimeLine_Pieces - 0.01)*tooltipIndex + 1 ) , TimeLine_Pieces)

							local spellName,_,spellTexture = GetSpellInfo(castData[2])

							local targetInfo = ""
							if castData[4] and castData[4] ~= "" then
								targetInfo = " "..L.BossWatcherTimeLineOnText.." |c"..ExRT.F.classColorByGUID(castData[4])..GetGUID(castData[4]).."|r"
							end

							addToToolipTable[#addToToolipTable + 1] = {tooltipIndex,_time,"[" .. date("%M:%S", _time )  .. "] |c"..ExRT.F.classColorByGUID(mobGUID) .. GetGUID(mobGUID) .."|r" .. GUIDtoText("(%s)",mobGUID) .. ( castData[3] == 1 and " "..L.BossWatcherTimeLineCast.." " or " "..L.BossWatcherTimeLineCastStart.." " ) .. format("%s%s%s",spellTexture and "|T"..spellTexture..":0|t " or "",spellName or "???"," ["..castData[2].."]") .. targetInfo }
						end
					end
				end
			end
			for _,chatData in ipairs(CurrentFight.chat) do
				local _time = min( max(chatData[4] - CurrentFight.encounterStart,0) , CurrentFight.encounterEnd)

				local tooltipIndex = _time / fight_dur

				if CurrentEncountersPhases.chat then
					local phaseData = CurrentEncountersPhases.chat[ chatData[3] ]
					if phaseData then
						AddPhase(tooltipIndex,phaseData.phase)
					end
				end

				if CurrentFight.segments[chatData.s].e then
					redLineNum = redLineNum + 1
					if not TLframe.redLine[redLineNum] then
						CreateRedLine(redLineNum)
					end
					TLframe.redLine[redLineNum]:SetPoint("TOPLEFT",TLframe,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*tooltipIndex,0)
					TLframe.redLine[redLineNum]:Show()

					tooltipIndex = min( floor( (TimeLine_Pieces - 0.01)*tooltipIndex + 1 ) , TimeLine_Pieces)

					local spellName,_,spellTexture = GetSpellInfo(chatData[3])

					addToToolipTable[#addToToolipTable + 1] = {tooltipIndex,_time,"[" .. date("%M:%S", _time )  .. "] "..  L.BossWatcherChatSpellMsg .. " " .. format("%s%s%s",spellTexture and "|T"..spellTexture..":0|t " or "",spellName or "???"," ["..chatData[3].."]") }
				end
			end
			for _,resData in ipairs(CurrentFight.resurrests) do
				if CurrentFight.segments[resData.s].e then
					local _time = timestampToFightTime(resData[4])

					local tooltipIndex = _time / fight_dur
					redLineNum = redLineNum + 1
					if not TLframe.redLine[redLineNum] then
						CreateRedLine(redLineNum)
					end
					TLframe.redLine[redLineNum]:SetPoint("TOPLEFT",TLframe,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*tooltipIndex,0)
					TLframe.redLine[redLineNum]:Show()

					tooltipIndex = min( floor( (TimeLine_Pieces - 0.01)*tooltipIndex + 1 ) , TimeLine_Pieces)
					local spellName,_,spellTexture = GetSpellInfo(resData[3])

					addToToolipTable[#addToToolipTable + 1] = {tooltipIndex,_time,"[" .. date("%M:%S", _time )  .. "] |c"..ExRT.F.classColorByGUID(resData[1]) .. GetGUID(resData[1]) .."|r" ..  GUIDtoText("(%s)",resData[1]) .. " ".. L.BossWatcherTimeLineCast.. " " .. format("%s%s%s",spellTexture and "|T"..spellTexture..":0|t " or "",spellName or "???"," ["..resData[3].."]") .. " "..L.BossWatcherTimeLineOnText.." |c"..ExRT.F.classColorByGUID(resData[2])..GetGUID(resData[2]).."|r" }
				end
			end
			for i=(redLineNum+1),#TLframe.redLine do
				TLframe.redLine[i]:Hide()
			end

			local blueLineNum = 0
			for i=1,#CurrentFight.dies do
				if CurrentFight.segments[CurrentFight.dies[i].s].e and ExRT.F.GetUnitInfoByUnitFlag(CurrentFight.dies[i][2],1) == 1024 then
					local _time = timestampToFightTime(CurrentFight.dies[i][3])

					local tooltipIndex = _time / fight_dur

					blueLineNum = blueLineNum + 1
					if not TLframe.blueLine[blueLineNum] then
						CreateBlueLine(blueLineNum)
					end
					TLframe.blueLine[blueLineNum]:SetPoint("TOPLEFT",TLframe,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*tooltipIndex,0)
					TLframe.blueLine[blueLineNum]:Show()

					tooltipIndex = min ( floor( (TimeLine_Pieces - 0.01)*tooltipIndex + 1 ) , TimeLine_Pieces)

					addToToolipTable[#addToToolipTable + 1] = {tooltipIndex,_time,"[" .. date("%M:%S", _time )  .. "] |cffee5555" .. GetGUID(CurrentFight.dies[i][1]) .. GUIDtoText("(%s)",CurrentFight.dies[i][1])  .. " "..L.BossWatcherTimeLineDies.."|r"}
				end
			end
			for i=(blueLineNum+1),#TLframe.blueLine do
				TLframe.blueLine[i]:Hide()
			end

			for i=1,TimeLine_Pieces do
				if bossHpPerSegment[i] then
					table.insert(TLframe[i].tooltip,{bossHpPerSegment[i],1,1,1})
				end
			end
			table.sort(addToToolipTable,function (a,b) return a[2] < b[2] end)
			for i=1,#addToToolipTable do
				if TLframe[ addToToolipTable[i][1] ] then
					table.insert(TLframe[ addToToolipTable[i][1] ].tooltip,{addToToolipTable[i][3],1,1,1})
				end
			end

			TimeLine_UpdateSegments()
		end

		TLframe.ImprovedSelectSegment = CreateFrame("Button",nil,TLframe)
		TLframe.ImprovedSelectSegment:SetAllPoints()
		TLframe.ImprovedSelectSegment:Hide()

		TLframe.ImprovedSelectSegment.ResetZoom = CreateFrame("Button",nil,TLframe.ImprovedSelectSegment)
		TLframe.ImprovedSelectSegment.ResetZoom:SetSize(200,13)
		TLframe.ImprovedSelectSegment.ResetZoom:SetPoint("TOPRIGHT",TLframe.ImprovedSelectSegment,"BOTTOMRIGHT",-1,4)
		TLframe.ImprovedSelectSegment.ResetZoom.Text = ELib:Text(TLframe.ImprovedSelectSegment.ResetZoom,"["..L.BossWatcherGraphZoomReset.."]",11):Size(200,13):Point("RIGHT",0,0):Right():Top():Color():Outline()
		TLframe.ImprovedSelectSegment.ResetZoom:SetWidth( TLframe.ImprovedSelectSegment.ResetZoom.Text:GetStringWidth() )
		TLframe.ImprovedSelectSegment.ResetZoom:SetScript("OnClick",function (self)
			BWInterfaceFrame.GraphFrame.G.ZoomMinX = nil
			BWInterfaceFrame.GraphFrame.G.ZoomMaxX = nil
			UpdateSegments()
		end)
		TLframe.ImprovedSelectSegment.ResetZoom:Hide()

		TLframe.ImprovedSelectSegment.hoverTime = ELib:Text(TLframe.ImprovedSelectSegment,"",11):Size(200,16):Center():Top():Color():Outline()

		TLframe.ImprovedSelectSegment.Texture = TLframe:CreateTexture(nil, "BACKGROUND",nil,2)
		--TLframe.ImprovedSelectSegment.Texture:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\bar9.tga")
		--TLframe.ImprovedSelectSegment.Texture:SetVertexColor(0, 0.65, 0.9, .7)
		TLframe.ImprovedSelectSegment.Texture:SetColorTexture(1, 1, 1, 1)
		TLframe.ImprovedSelectSegment.Texture:SetGradient("VERTICAL",CreateColor(0.3,0.75,0.90,.7), CreateColor(0,0.62,0.90,.7))
		TLframe.ImprovedSelectSegment.Texture:SetHeight(30)
		TLframe.ImprovedSelectSegment.Texture:Hide()

		function TimeLineFrame_ImprovedSelectSegment_GetSelected(self)
			local fightDuration = GetFightLength(true)
			local timeLineWidth = self:GetWidth()
			local start = self.mouseDowned / timeLineWidth
			local ending = ExRT.F.GetCursorPos(self) / timeLineWidth
			if ending > start then
				ending = min(ending,1)
				start = max(start,0)
			else
				start = min(start,1)
				ending = max(ending,0)
			end

			start = ExRT.F.Round(start * fightDuration)
			ending = ExRT.F.Round(ending * fightDuration)

			return start,ending
		end
		function TimeLineFrame_ImprovedSelectSegment_OnUpdate(self)
			local x = ExRT.F.GetCursorPos(self)
			local width = x - self.mouseDowned
			if width > 0 then
				width = min(width,self:GetWidth()-self.mouseDowned)
				self.Texture:SetWidth(width)
				self.Texture:SetPoint("TOPLEFT",TLframe,"TOPLEFT", self.mouseDowned ,0)

				local start,ending = TimeLineFrame_ImprovedSelectSegment_GetSelected(self)

				ELib.Tooltip.Show(self,"ANCHOR_CURSOR",format("%d:%02d - %d:%02d",start / 60,start % 60,ending / 60,ending % 60))
			elseif width < 0 then
				width = -width
				width = min(width,self.mouseDowned)
				self.Texture:SetWidth(width)
				self.Texture:SetPoint("TOPLEFT",TLframe,"TOPLEFT", self.mouseDowned-width,0)

				local start,ending = TimeLineFrame_ImprovedSelectSegment_GetSelected(self)
				ELib.Tooltip.Show(self,"ANCHOR_CURSOR",format("%d:%02d - %d:%02d",ending / 60,ending % 60,start / 60,start % 60))
			else
				self.Texture:SetWidth(1)
				ELib.Tooltip:Hide()
			end
		end
		TLframe.ImprovedSelectSegment:SetScript("OnMouseDown",function (self)
			self.mouseDowned = ExRT.F.GetCursorPos(self)
			self.Texture:SetPoint("TOPLEFT",TLframe,"TOPLEFT", self.mouseDowned ,0)
			self.Texture:SetWidth(1)
			self.Texture:Show()
			self:SetScript("OnUpdate",TimeLineFrame_ImprovedSelectSegment_OnUpdate)
			self.hoverTime:Hide()
		end)
		TLframe.ImprovedSelectSegment:SetScript("OnMouseUp",function (self)
			self:SetScript("OnUpdate",nil)
			self.Texture:Hide()
			ELib.Tooltip:Hide()
			if not self.mouseDowned then
				return
			end
			local start,ending = TimeLineFrame_ImprovedSelectSegment_GetSelected(self)
			self.mouseDowned = nil
			if ending < start then
				start,ending = ending,start
			end
			start = start + 1
			ending = ending + 1

			UpdateSegments(start,ending,IsShiftKeyDown())
		end)

		function TimeLineFrame_ImprovedSelectSegment_OnUpdate_Passive(self)
			local timeLineWidth = self:GetWidth()
			local fightDuration = GetFightLength(true)
			local x = ExRT.F.GetCursorPos(self)
			local time = ExRT.F.Round(x / timeLineWidth * fightDuration)
			self.hoverTime:SetFormattedText("%d:%02d",time / 60,time % 60)
			self.hoverTime:SetPoint("TOP",self,"TOPLEFT",x,-2)
			self.hoverTime:Show()
			local segmentNow = ceil(x / timeLineWidth * 60  + 0.01)
			if segmentNow ~= self.lastSegment then
				self.lastSegment = segmentNow
				ELib.Tooltip:Hide()
			else
				return
			end
			local frame = TLframe[segmentNow]
			if frame then
				TimeLinePieceOnEnter(frame)
			end
		end
		TLframe.ImprovedSelectSegment:SetScript("OnEnter",function (self)
			if self.mouseDowned then 
				return
			end
			self.lastSegment = nil
			self:SetScript("OnUpdate",TimeLineFrame_ImprovedSelectSegment_OnUpdate_Passive)
		end)
		TLframe.ImprovedSelectSegment:SetScript("OnLeave",function (self)
			self.hoverTime:Hide()
			if self.mouseDowned then
				return
			end
			ELib.Tooltip:Hide()
			self:SetScript("OnUpdate",nil)
		end)
	end

	BWInterfaceFrame.timeLineFrame:SetScript("OnShow",function (self)
		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			UpdateTimeLine()
			self.lastFightID = BWInterfaceFrame.nowFightID
		end
	end)

	---- Graph Frame
	BWInterfaceFrame.GraphFrame = CreateFrame('Frame',nil,BWInterfaceFrame.tab)
	BWInterfaceFrame.GraphFrame:SetSize(860,200)
	BWInterfaceFrame.GraphFrame:SetPoint("TOP",0,-80)
	BWInterfaceFrame.GraphFrame:Hide()
	BWInterfaceFrame.GraphFrame.G = ExRT.lib.CreateGraph(BWInterfaceFrame.GraphFrame,790,180,"TOPLEFT",50,-5,true)
	BWInterfaceFrame.GraphFrame.G.fixMissclickZoom = true
	BWInterfaceFrame.GraphFrame.G.DisableReloadOnResetZoom = true
	BWInterfaceFrame.GraphFrame.G.backgroundHighlight = {}
	BWInterfaceFrame.GraphFrame.G.ResetZoom:Point("TOPRIGHT",-100,10)

	BWInterfaceFrame.GraphFrame.G.highlightHideButton = ELib:Button(BWInterfaceFrame.GraphFrame.G,"",1)
	BWInterfaceFrame.GraphFrame.G.highlightHideButton:SetSize(16,16)
	BWInterfaceFrame.GraphFrame.G.highlightHideButton.background = BWInterfaceFrame.GraphFrame.G.highlightHideButton:CreateTexture(nil, "BACKGROUND")
	BWInterfaceFrame.GraphFrame.G.highlightHideButton.background:SetAllPoints()
	BWInterfaceFrame.GraphFrame.G.highlightHideButton.background:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128")
	BWInterfaceFrame.GraphFrame.G.highlightHideButton.background:SetTexCoord(0.5,0.5625,0.5,0.625)
	BWInterfaceFrame.GraphFrame.G.highlightHideButton:SetScript("OnEnter",function(self)
		self.background:SetVertexColor(.7,0,0,1)
	end)
	BWInterfaceFrame.GraphFrame.G.highlightHideButton:SetScript("OnLeave",function(self)
		self.background:SetVertexColor(1,1,1,.7)
	end)
	BWInterfaceFrame.GraphFrame.G.highlightHideButton:SetScript("OnClick",function(self)
		local parent = self:GetParent()
		parent.highlight = nil
		parent:OnAfterReload()
	end)
	BWInterfaceFrame.GraphFrame.G.highlightHideButton:Hide()

	function BWInterfaceFrame.GraphFrame.G:OnBeforeReload()
		if not self.data[1] then
			return
		end
		local tooltipX = {}
		for i=1,#self.data[1] do
			tooltipX[i] = format("%d:%02d",i / 60,i % 60)
		end
		self.data.tooltipX = tooltipX
	end
	function BWInterfaceFrame.GraphFrame.G:OnAfterReload()
		if not self.highlight or not self.range or not self.range.maxX then
			for i=1,#self.backgroundHighlight do
				self.backgroundHighlight[i]:Hide()
			end
			self.highlightHideButton:Hide()
			return
		end
		local count = 0
		for i=1,#self.highlight,2 do
			local posStart,posEnd = self.highlight[i],self.highlight[i+1]
			if not (posStart > self.range.maxX or posEnd < self.range.minX) then
				if posStart < self.range.minX then
					posStart = self.range.minX
				end
				if posEnd > self.range.maxX then
					posEnd = self.range.maxX
				end
				count = count + 1
				local background = self.backgroundHighlight[count]
				if not background then
					background = self:CreateTexture(nil, "BACKGROUND",nil,2)
					self.backgroundHighlight[count] = background
					background:SetPoint("TOP",0,0)
					background:SetPoint("BOTTOM",0,0)
					background:SetColorTexture(0.7, 0.65, 0.9, .3)
					if count == 1 then
						self.highlightHideButton:SetPoint("TOPRIGHT",background,2,-2)
					end
				end
				local posX = (posStart - self.range.minX) / (self.range.maxX - self.range.minX) * self:GetWidth()
				local width = (posEnd - posStart) / (self.range.maxX - self.range.minX) * self:GetWidth()
				background:SetPoint("LEFT",posX,0)
				background:SetWidth(width)
				background:Show()
				if count == 1 then
					self.highlightHideButton:Show()
				end
			end
		end
		for i=count+1,#self.backgroundHighlight do
			self.backgroundHighlight[i]:Hide()
		end
		if count == 0 then
			self.highlightHideButton:Hide()
		end
	end
	function BWInterfaceFrame.GraphFrame.G:Zoom(start,ending)
		if ending == start then
			self.ZoomMinX = nil
			self.ZoomMaxX = nil
		else
			self.ZoomMinX = start
			self.ZoomMaxX = ending
		end

		UpdateSegments(start,ending)
	end
	function BWInterfaceFrame.GraphFrame.G:OnResetZoom()
		UpdateSegments()
	end
	BWInterfaceFrame.GraphFrame.stepSlider = ELib:Slider(BWInterfaceFrame.GraphFrame,"",true):Point("BOTTOMRIGHT",BWInterfaceFrame.GraphFrame.G,"BOTTOMLEFT",-10,20):Size(100):Range(1,10):SetTo(1):OnChange(function(self)
		local graph = self:GetParent().G
		self:Tooltip(L.BossWatcherGraphicsStep.."\n"..floor(self:GetValue() + 0.5))
		self:tooltipReload()
		if graph.IgnoreStepSliderFix then
			return
		end
		graph.step = floor(self:GetValue() + 0.5)
		graph:Reload()
	end):Tooltip(L.BossWatcherGraphicsStep.."\n1")

	function Graph_AutoUpdateStep()
		local fightDuration = GetFightLength()
		local step = 1
		if fightDuration >= 360 then
			step = 3
		elseif fightDuration >= 180 then
			step = 2
		end
		local graph = BWInterfaceFrame.GraphFrame.G
		graph.IgnoreStepSliderFix = true
		graph.step = step
		BWInterfaceFrame.GraphFrame.stepSlider:SetValue(step)
		graph.IgnoreStepSliderFix = nil
	end



	local tab = nil
	---- Damage Tab
	tab = BWInterfaceFrame.tab.tabs[1]

	local sourceVar,destVar = {},{}
	local DamageTab_SetLine = nil

	local DamageTab_Variables = {
		Last_Func = nil,
		Last_doEnemy = nil,
		ShowAll = false,
		Back_Func = nil,
		Back_destVar = nil,
		Back_sourceVar = nil,

		state_friendly = true,
		state_spells = false,
		state_byTarget = false,
		state_spellsTarget = false,
	}

	local DamageTab_UpdatePage

	local function DamageTab_GetGUIDsReport(list,isDest)
		local result = ""
		for GUID,_ in pairs(list) do
			if result ~= "" then
				result = result..", "
			end
			local time = ""
			if isDest and ExRT.F.GetUnitTypeByGUID(GUID) ~= 0 and CurrentFight.damage_seen[GUID] then
				time = date(" (%M:%S)", timestampToFightTime( CurrentFight.damage_seen[GUID] ))
			end
			result = result .. GetGUID(GUID) .. time
		end
		if result ~= "" then
			return result
		end
	end
	local function DamageTab_UpdateDropDown(arr,dropDown)
		local count = ExRT.F.table_len(arr)
		if count == 0 then
			dropDown:SetText(L.BossWatcherAll)
		elseif count == 1 then
			local GUID = nil
			for g,_ in pairs(arr) do
				GUID = g
			end
			local name = GetGUID(GUID)
			local flags = CurrentFight.reaction[GUID]
			local isPlayer = GetUnitInfoByUnitFlagFix(flags,1) == 1024
			local isNPC = GetUnitInfoByUnitFlagFix(flags,2) == 512
			if isPlayer then
				name = "|c"..ExRT.F.classColorByGUID(GUID)..name
			elseif isNPC then
				name = name .. date(" %M:%S", timestampToFightTime( CurrentFight.damage_seen[GUID] )) .. GUIDtoText(" [%s]",GUID)
			end
			dropDown:SetText(name)
		else
			dropDown:SetText(L.BossWatcherSeveral)
		end
	end

	local function DamageTab_UpdateDropDowns()
		DamageTab_UpdateDropDown(sourceVar,BWInterfaceFrame.tab.tabs[1].sourceDropDown)
		DamageTab_UpdateDropDown(destVar,BWInterfaceFrame.tab.tabs[1].targetDropDown)
	end

	local function DamageTab_UpdateChecks()
		local tab = BWInterfaceFrame.tab.tabs[1]
		for _,c in pairs({tab.chkFriendly,tab.chkEnemy,tab.chkSpellsTargets,tab.bySource,tab.byTarget,tab.bySpell}) do
			c:SetChecked(false)
		end
		if DamageTab_Variables.state_spellsTarget then
			tab.chkSpellsTargets:SetChecked(true)
		elseif DamageTab_Variables.state_friendly then
			tab.chkFriendly:SetChecked(true)
		else
			tab.chkEnemy:SetChecked(true)
		end
		if DamageTab_Variables.state_spells then
			tab.bySpell:SetChecked(true)
		end
		if DamageTab_Variables.state_byTarget then
			tab.byTarget:SetChecked(true)
		elseif not DamageTab_Variables.state_spells then
			tab.bySource:SetChecked(true)
		end
	end
	local function DamageTab_Temp_SortingBy2Param(a,b)
		return a[2] > b[2]
	end

	local function DamageTab_ReloadGraph(data,fightLength,linesData,isSpell)
		local graphData = {}
		for key,spellData in pairs(data) do
			local newData
			if isSpell then
				local spellID = key
				local isPet = 1
				if (not ExRT.isClassic or ExRT.isCata) and spellID < -1 then
					isPet = -1
					spellID = -spellID
				end
				local spellName,_,spellIcon = GetSpellInfo(spellID)
				if spellID == -1 then
					spellName = L.BossWatcherReportTotal
				elseif spellName then
					spellName = "|T"..(spellIcon or "")..":0|t "..spellName
				else
					spellName = spellID
				end
				newData = {
					info_spellID = type(spellID)=='number' and spellID*isPet or spellID,
					name = spellName,
					total_damage = 0,
					hide = true,
				}
			else
				local sourceGUID = key
				local name,r,g,b = nil
				if sourceGUID == -1 then
					name = L.BossWatcherReportTotal
				else
					local class
					name = GetGUID(sourceGUID)
					if sourceGUID ~= "" then
						class = select(2,GetPlayerInfoByGUID(sourceGUID))
					end
					name = "|c".. ExRT.F.classColor(class) .. name .. "|r"
					if class then
						local classColorArray = type(CUSTOM_CLASS_COLORS)=="table" and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
						r,g,b = classColorArray.r,classColorArray.g,classColorArray.b
					end
				end
				newData = {
					info_spellID = sourceGUID,
					name = name,
					total_damage = 0,
					hide = true,
					r = r,
					g = g,
					b = b,
				}
			end
			graphData[#graphData+1] = newData
			local total_damage = 0
			for i=1,fightLength do
				newData[i] = {i,spellData[i] or 0}
				total_damage = total_damage + (spellData[i] or 0)
			end
			newData.total_damage = total_damage
		end
		sort(graphData,function(a,b) return a.total_damage>b.total_damage end)
		local findPos = ExRT.F.table_find(graphData,-1,'info_spellID')
		if findPos then
			graphData[ findPos ].hide = nil
			graphData[ findPos ].specialLine = true
		end
		for i=1,3 do
			if linesData[i] then
				findPos = ExRT.F.table_find(graphData,linesData[i][isSpell and "spell" or "guid"],'info_spellID')
				if findPos then
					graphData[ findPos ].hide = nil
				end
			end
		end
		BWInterfaceFrame.GraphFrame.G.data = graphData
		BWInterfaceFrame.GraphFrame.G:Reload()
	end

	local function DamageTab_UpdateLines_GetUnit(damage,graph,source,dest,header,secondHeader)
		header = header or "guid"
		local sourceDamage

		for i=1,#damage do
			if damage[i][header] == source and (not secondHeader or damage[i].info == secondHeader) then
				sourceDamage = i
				break
			end
		end

		if not sourceDamage then
			sourceDamage = #damage + 1
			damage[sourceDamage] = {
				[header] = source,
				info = secondHeader,
				eff = 0,
				total = 0,
				count = 0,
				overkill = 0,
				blocked = 0,
				absorbed = 0,
				crit = 0,
				critcount = 0,
				critmax = 0,
				critover = 0,
				hitmax = 0,
				parry = 0,
				dodge = 0,
				miss = 0,
				targets = {},
			}
		end
		sourceDamage = damage[sourceDamage]

		local destPos

		local targets = sourceDamage.targets
		for i=1,#targets do
			if targets[i][1] == dest then
				destPos = i
				break
			end
		end

		if not destPos then
			destPos = #sourceDamage.targets + 1
			sourceDamage.targets[destPos] = {dest,0}
		end

		if not graph[ source ] then
			graph[ source ] = {}
		end

		return sourceDamage, sourceDamage.targets[destPos]
	end

	local function DamageTab_UpdateLinesPlayers()
		ExRT.F.dprint("Damage Update: Players",GetTime())
		local doEnemy = DamageTab_Variables.state_friendly
		local isReverse = DamageTab_Variables.state_byTarget

		DamageTab_UpdateDropDowns()
		DamageTab_UpdateChecks()

		local damage = {}
		local total = 0
		local totalOver = 0
		local graph = {[-1]={}}
		for destGUID,destData in pairs(CurrentFight.damage) do
			if ExRT.F.table_len(destVar) == 0 or destVar[destGUID] then
				for destReaction,destReactData in pairs(destData) do
					local isEnemy = false
					if GetUnitInfoByUnitFlagFix(destReaction,2) == 512 then
						isEnemy = true
					end
					if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
						for sourceGUID,sourceData in pairs(destReactData) do
							local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
							if owner then
								sourceGUID = owner
							end
							if ExRT.F.table_len(sourceVar) == 0 or sourceVar[sourceGUID] then
								local source = isReverse and destGUID or sourceGUID
								local dest = isReverse and sourceGUID or destGUID

								local sourceDamage, destPos = DamageTab_UpdateLines_GetUnit(damage,graph,source,dest,"guid")

								for spellID,spellSegments in pairs(sourceData) do
									for segment,spellAmount in pairs(spellSegments) do
										if CurrentFight.segments[segment].e then
											sourceDamage.eff = sourceDamage.eff + spellAmount.amount - spellAmount.overkill
											sourceDamage.total = sourceDamage.total + spellAmount.amount + spellAmount.blocked + spellAmount.absorbed
											sourceDamage.overkill = sourceDamage.overkill + spellAmount.overkill
											sourceDamage.blocked = sourceDamage.blocked + spellAmount.blocked
											sourceDamage.absorbed = sourceDamage.absorbed + spellAmount.absorbed
											sourceDamage.crit = sourceDamage.crit + spellAmount.crit
											total = total + spellAmount.amount - spellAmount.overkill
											totalOver = totalOver + spellAmount.overkill + spellAmount.blocked + spellAmount.absorbed

											local damgeCount = spellAmount.amount + (DamageTab_Variables.ShowAll and (spellAmount.blocked+spellAmount.absorbed) or -spellAmount.overkill)
											destPos[2] = destPos[2] + damgeCount

											if not graph[ source ][segment] then
												graph[ source ][segment] = 0
											end
											if not graph[ -1 ][segment] then
												graph[ -1 ][segment] = 0
											end
											graph[ source ][segment] = graph[ source ][segment] + damgeCount
											graph[ -1 ][segment] = graph[ -1 ][segment] + damgeCount
										end
									end
								end
							end
						end
					end
				end
			end
		end
		local totalIsFull = 1
		total = max(total,1)
		if total == 1 and #damage == 0 then
			total = 0
			totalIsFull = 0
		end

		local _max = nil
		reportOptions[1] = L.BossWatcherReportDPS
		wipe(reportData[1])
		reportData[1][1] = (DamageTab_GetGUIDsReport(sourceVar) or L.BossWatcherAllSources).." > "..(DamageTab_GetGUIDsReport(destVar,true) or L.BossWatcherAllTargets)
		local activeFightLength = GetFightLength()

		if DamageTab_Variables.ShowAll then
			total = total + totalOver
			sort(damage,function(a,b) return a.total>b.total end)
			_max = damage[1] and damage[1].total or 0
		else
			sort(damage,function(a,b) return a.eff>b.eff end)
			_max = damage[1] and damage[1].eff or 0
		end
		reportData[1][2] = L.BossWatcherReportTotal.." - "..ExRT.F.shortNumber(total).."@1@ ("..floor(total / activeFightLength)..")@1#"
		DamageTab_SetLine({
			line = 1,
			name = L.BossWatcherReportTotal,
			num = total,
			total = total,
			max = total,
			alpha = DamageTab_Variables.ShowAll and totalOver,
			dps = total / activeFightLength,
			spellID = -1,
			check = BWInterfaceFrame.GraphFrame:IsShown(),
			checkState = true,
		})
		for i=#damage,1,-1 do
			if damage[i].total == 0 then
				tremove(damage,i)
			end
		end
		for i=1,#damage do
			local damageLine = damage[i]
			local class = nil
			if damageLine.guid and damageLine.guid ~= "" then
				class = select(2,GetPlayerInfoByGUID(damageLine.guid))
			end
			local icon = ""
			if class and CLASS_ICON_TCOORDS[class] then
				icon = {"Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES",unpack(CLASS_ICON_TCOORDS[class])}
			end
			local tooltipData = {GetGUID(damageLine.guid),
				{L.BossWatcherDamageTooltipOverkill,ExRT.F.shortNumber(damageLine.overkill)},
				{L.BossWatcherDamageTooltipBlocked,ExRT.F.shortNumber(damageLine.blocked)},
				{L.BossWatcherDamageTooltipAbsorbed,ExRT.F.shortNumber(damageLine.absorbed)},
				{L.BossWatcherDamageTooltipTotal,ExRT.F.shortNumber(damageLine.total)},
				{" "," "},
				{L.BossWatcherDamageTooltipFromCrit,format("%s (%.1f%%)",ExRT.F.shortNumber(damageLine.crit),max(damageLine.crit/max(1,damageLine.total)*100))},
			}
			sort(damageLine.targets,DamageTab_Temp_SortingBy2Param)
			if #damageLine.targets > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {isReverse and L.BossWatcherDamageTooltipSources or L.BossWatcherDamageTooltipTargets," "}
			end
			for j=1,min(5,#damageLine.targets) do
				tooltipData[#tooltipData + 1] = {SubUTF8String(GetGUID(damageLine.targets[j][1]),20)..GUIDtoText(" [%s]",damageLine.targets[j][1]),format("%s (%.1f%%)",ExRT.F.shortNumber(damageLine.targets[j][2]),min(damageLine.targets[j][2] / max(1,(DamageTab_Variables.ShowAll and damageLine.total or damageLine.eff))*100,100))}
			end

			local currDamage = DamageTab_Variables.ShowAll and damageLine.total or damageLine.eff
			local dps = currDamage/activeFightLength
			DamageTab_SetLine({
				line = i+1,
				icon = icon,
				name = GetGUID(damageLine.guid)..GUIDtoText(" [%s]",damageLine.guid),
				num = currDamage,
				alpha = DamageTab_Variables.ShowAll and (damageLine.total - damageLine.eff),
				total = total,
				max = _max,
				dps = dps,
				class = class,
				sourceGUID = damageLine.guid,
				tooltip = tooltipData,
				check = BWInterfaceFrame.GraphFrame:IsShown(),
				checkState = i <= 3,
			})
			reportData[1][#reportData[1]+1] = i..". "..GetGUID(damageLine.guid).." - "..ExRT.F.shortNumber(currDamage).."@1@ ("..floor(dps)..")@1#"
		end
		for i=#damage+2,#BWInterfaceFrame.tab.tabs[1].lines do
			BWInterfaceFrame.tab.tabs[1].lines[i]:Hide()
		end
		BWInterfaceFrame.tab.tabs[1].scroll:Height((#damage+1) * 20)

		DamageTab_Variables.graphCache = {graph,#CurrentFight.segments,damage,false}
		if BWInterfaceFrame.GraphFrame:IsShown() then
			DamageTab_ReloadGraph(graph,#CurrentFight.segments,damage,false)
		end
	end
	local function DamageTab_UpdateLinesSpells()
		local doEnemy = DamageTab_Variables.state_friendly

		DamageTab_UpdateDropDowns()
		DamageTab_UpdateChecks()

		local damage = {}
		local total = 0
		local totalOver = 0
		local graph = {[-1]={}}
		for destGUID,destData in pairs(CurrentFight.damage) do
			if ExRT.F.table_len(destVar) == 0 or destVar[destGUID] then
				for destReaction,destReactData in pairs(destData) do
					local isEnemy = false
					if GetUnitInfoByUnitFlagFix(destReaction,2) == 512 then
						isEnemy = true
					end
					if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
						for sourceGUID,sourceData in pairs(destReactData) do
							local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
							if owner then
								sourceGUID = owner
							end
							if ExRT.F.table_len(sourceVar) == 0 or sourceVar[sourceGUID] then
								for spellID,spellSegments in pairs(sourceData) do
									local sourceDamage, destPos = DamageTab_UpdateLines_GetUnit(damage,graph,spellID,destGUID,"spell",owner and "pet")

									for segment,spellAmount in pairs(spellSegments) do
										if CurrentFight.segments[segment].e then
											sourceDamage.total = sourceDamage.total + spellAmount.amount + spellAmount.blocked + spellAmount.absorbed
											sourceDamage.eff = sourceDamage.eff + spellAmount.amount - spellAmount.overkill
											sourceDamage.count = sourceDamage.count + spellAmount.count
											sourceDamage.overkill = sourceDamage.overkill + spellAmount.overkill
											sourceDamage.blocked = sourceDamage.blocked + spellAmount.blocked
											sourceDamage.absorbed = sourceDamage.absorbed + spellAmount.absorbed
											sourceDamage.crit = sourceDamage.crit + spellAmount.crit
											sourceDamage.critcount = sourceDamage.critcount + spellAmount.critcount
											if sourceDamage.critmax < spellAmount.critmax then
												sourceDamage.critmax = spellAmount.critmax
											end
											sourceDamage.critover = sourceDamage.critover + spellAmount.critover
											if sourceDamage.hitmax < spellAmount.hitmax then
												sourceDamage.hitmax = spellAmount.hitmax
											end
											sourceDamage.parry = sourceDamage.parry + spellAmount.parry
											sourceDamage.dodge = sourceDamage.dodge + spellAmount.dodge
											sourceDamage.miss = sourceDamage.miss + spellAmount.miss
											total = total + spellAmount.amount - spellAmount.overkill
											totalOver = totalOver + spellAmount.overkill + spellAmount.blocked + spellAmount.absorbed

											local damgeCount = spellAmount.amount + (DamageTab_Variables.ShowAll and (spellAmount.blocked+spellAmount.absorbed) or -spellAmount.overkill)

											destPos[2] = destPos[2] + damgeCount

											if not graph[ spellID ][segment] then
												graph[ spellID ][segment] = 0
											end
											if not graph[ -1 ][segment] then
												graph[ -1 ][segment] = 0
											end

											graph[ spellID ][segment] = graph[ spellID ][segment] + damgeCount
											graph[ -1 ][segment] = graph[ -1 ][segment] + damgeCount

										end
									end
								end
							end
						end
					end
				end
			end
		end
		local totalIsFull = 1
		total = max(total,1)
		if total == 1 and #damage == 0 then
			total = 0
			totalIsFull = 0
		end
		local _max = nil
		reportOptions[1] = L.BossWatcherReportDPS
		wipe(reportData[1])
		reportData[1][1] = (DamageTab_GetGUIDsReport(sourceVar) or L.BossWatcherAllSources).." > "..(DamageTab_GetGUIDsReport(destVar,true) or L.BossWatcherAllTargets)
		local activeFightLength = GetFightLength()
		if DamageTab_Variables.ShowAll then
			total = total + totalOver
			sort(damage,function(a,b) return a.total>b.total end)
			_max = damage[1] and damage[1].total or 0
		else
			sort(damage,function(a,b) return a.eff>b.eff end)
			_max = damage[1] and damage[1].eff or 0
		end
		reportData[1][2] = L.BossWatcherReportTotal.." - "..ExRT.F.shortNumber(total).."@1@ ("..floor(total / activeFightLength)..")@1#"
		DamageTab_SetLine({
			line = 1,
			name = L.BossWatcherReportTotal,
			num = total,
			total = total,
			max = total,
			alpha = DamageTab_Variables.ShowAll and totalOver,
			dps = total / activeFightLength,
			spellID = -1,
			check = BWInterfaceFrame.GraphFrame:IsShown(),
			checkState = true,
		})
		for i=#damage,1,-1 do
			if damage[i].total == 0 then
				tremove(damage,i)
			end
		end
		local castsCount = SpellsPage_GetCastsNumber(ExRT.F.table_len(sourceVar) > 0 and sourceVar,ExRT.F.table_len(destVar) > 0 and destVar)
		for i=1,#damage do
			local damageLine = damage[i]
			local isPetAbility = damageLine.info == "pet"
			local spellID = damageLine.spell

			local isDoT = (not ExRT.isClassic or ExRT.isCata) and spellID < 0
			if isDoT then
				spellID = -spellID
			end
			local spellName,_,spellIcon = GetSpellInfo(spellID)
			local defSpellName = spellName
			if isPetAbility then
				spellName = L.BossWatcherPetText..": "..spellName
			end
			if isDoT then
				spellName = spellName .. " ["..L.BossWatcherDoT.."]"
			end
			if damageLine.info and damageLine.info ~= "pet" then
				spellName = GetGUID(damageLine.info)..": "..spellName
			end
			local school = module.db.spellsSchool[ spellID ] or 0
			local tooltipData = {
				{spellName,spellIcon},
				{L.BossWatcherDamageTooltipCount,damageLine.count},
				{L.BossWatcherDamageTooltipMaxHit,damageLine.hitmax},
				{L.BossWatcherDamageTooltipMidHit,ExRT.F.Round((damageLine.eff-damageLine.crit+damageLine.critover)/max(damageLine.count-damageLine.critcount,1))},
				{L.BossWatcherDamageTooltiCritCount,format("%d (%.1f%%)",damageLine.critcount,damageLine.critcount/damageLine.count*100)},
				{L.BossWatcherDamageTooltiCritAmount,ExRT.F.shortNumber(damageLine.crit - damageLine.critover)},
				{L.BossWatcherDamageTooltiMaxCrit,damageLine.critmax},
				{L.BossWatcherDamageTooltiMidCrit,ExRT.F.Round((damageLine.crit - damageLine.critover)/max(damageLine.critcount,1))},
				{L.BossWatcherDamageTooltipParry,format("%d (%.1f%%)",damageLine.parry,damageLine.parry/damageLine.count*100)},
				{L.BossWatcherDamageTooltipDodge,format("%d (%.1f%%)",damageLine.dodge,damageLine.dodge/damageLine.count*100)},
				{L.BossWatcherDamageTooltipMiss,format("%d (%.1f%%)",damageLine.miss,damageLine.miss/damageLine.count*100)},
				{L.BossWatcherDamageTooltipOverkill,ExRT.F.shortNumber(damageLine.overkill)},
				{L.BossWatcherDamageTooltipBlocked,ExRT.F.shortNumber(damageLine.blocked)},
				{L.BossWatcherDamageTooltipAbsorbed,ExRT.F.shortNumber(damageLine.absorbed)},
				{L.BossWatcherDamageTooltipTotal,ExRT.F.shortNumber(damageLine.total)},
				{L.BossWatcherSchool,GetSchoolName(school)},
			}
			local casts = castsCount[ spellID ] or castsCount[ defSpellName ]
			if casts then
				tinsert(tooltipData,2,{L.BossWatcherDamageTooltipCastsCount,casts})
				tinsert(tooltipData,3,{L.BossWatcherPerCast,ExRT.F.shortNumber(damageLine.eff / casts)})
			end

			sort(damageLine.targets,DamageTab_Temp_SortingBy2Param)
			if #damageLine.targets > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherDamageTooltipTargets," "}
			end
			for j=1,min(5,#damageLine.targets) do
				tooltipData[#tooltipData + 1] = {SubUTF8String(GetGUID(damageLine.targets[j][1]),20)..GUIDtoText(" [%s]",damageLine.targets[j][1]),format("%s (%.1f%%)",ExRT.F.shortNumber(damageLine.targets[j][2]),min(damageLine.targets[j][2] / max(1,DamageTab_Variables.ShowAll and damageLine.total or damageLine.eff)*100,100))}
			end

			local currDamage = DamageTab_Variables.ShowAll and damageLine.total or damageLine.eff
			local dps = currDamage/activeFightLength
			DamageTab_SetLine({
				line = i+1,
				icon = spellIcon,
				name = spellName,
				num = currDamage,
				alpha = DamageTab_Variables.ShowAll and (damageLine.total - damageLine.eff),
				total = total,
				max = _max,
				dps = dps,
				spellID = spellID,
				school = school,
				isDoT = isDoT,
				tooltip = tooltipData,
				check = BWInterfaceFrame.GraphFrame:IsShown(),
				checkState = i <= 3,
			})
			reportData[1][#reportData[1]+1] = i..". "..(isPetAbility and L.BossWatcherPetText..": " or "")..(damageLine.info and damageLine.info ~= "pet" and GetGUID(damageLine.info)..": " or "")..GetSpellLink(spellID).." - "..ExRT.F.shortNumber(currDamage).."@1@ ("..floor(dps)..")@1#"
		end
		for i=#damage+2,#BWInterfaceFrame.tab.tabs[1].lines do
			BWInterfaceFrame.tab.tabs[1].lines[i]:Hide()
		end
		BWInterfaceFrame.tab.tabs[1].scroll:Height((#damage+1) * 20)

		DamageTab_Variables.graphCache = {graph,#CurrentFight.segments,damage,true}
		if BWInterfaceFrame.GraphFrame:IsShown() then
			DamageTab_ReloadGraph(graph,#CurrentFight.segments,damage,true)
		end
	end

	local function DamageTab_UpdateLinesSpellToTargets()
		local doEnemy = false
		DamageTab_UpdateDropDowns()
		DamageTab_UpdateChecks()

		local spellIDnow,spellIDnow_Name = nil,""
		for spellID,_ in pairs(sourceVar) do
			spellIDnow = spellID
		end
		if spellIDnow then
			spellIDnow_Name = GetSpellInfo(spellIDnow) or ""
			BWInterfaceFrame.tab.tabs[1].sourceDropDown:SetText(spellIDnow_Name)
		else
			BWInterfaceFrame.tab.tabs[1].sourceDropDown:SetText(L.BossWatcherSelect)
		end
		local damage = {}
		local total = 0
		local totalOver = 0
		local totalCount = 0
		local graph = {[-1]={}}
		for destGUID,destData in pairs(CurrentFight.damage) do
			for destReaction,destReactData in pairs(destData) do
				local isEnemy = GetUnitInfoByUnitFlagFix(destReaction,2) == 512
				if (doEnemy and isEnemy) or (not doEnemy and not isEnemy) then
					for sourceGUID,sourceData in pairs(destReactData) do
						for spellID,spellSegments in pairs(sourceData) do
							if sourceVar[spellID] or sourceVar[-spellID] then
								local inDamagePos = ExRT.F.table_find(damage,destGUID,1)
								if not inDamagePos then
									inDamagePos = #damage + 1
									damage[inDamagePos] = {destGUID,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,guid=destGUID,total=0,sources={}}
								end
								if not graph[ destGUID ] then
									graph[ destGUID ] = {}
								end

								for segment,spellAmount in pairs(spellSegments) do
									if CurrentFight.segments[segment].e then
										damage[inDamagePos].total = damage[inDamagePos].total + spellAmount.amount + spellAmount.blocked + spellAmount.absorbed
										damage[inDamagePos][2] = damage[inDamagePos][2] + spellAmount.amount - spellAmount.overkill	--amount
										damage[inDamagePos][3] = damage[inDamagePos][3] + spellAmount.count	--count
										damage[inDamagePos][4] = damage[inDamagePos][4] + spellAmount.overkill	--overkill
										damage[inDamagePos][5] = damage[inDamagePos][5] + spellAmount.blocked	--blocked
										damage[inDamagePos][6] = damage[inDamagePos][6] + spellAmount.absorbed	--absorbed
										damage[inDamagePos][7] = damage[inDamagePos][7] + spellAmount.crit	--crit
										damage[inDamagePos][8] = damage[inDamagePos][8] + spellAmount.critcount	--crit count
										damage[inDamagePos][9] = max(damage[inDamagePos][9],spellAmount.critmax)--crit max
										damage[inDamagePos][13] = max(damage[inDamagePos][13],spellAmount.hitmax)--hit max
										damage[inDamagePos][14] = damage[inDamagePos][14] + spellAmount.parry	--parry
										damage[inDamagePos][15] = damage[inDamagePos][15] + spellAmount.dodge	--dodge
										damage[inDamagePos][16] = damage[inDamagePos][16] + spellAmount.miss	--other miss
										total = total + spellAmount.amount - spellAmount.overkill
										totalOver = totalOver + spellAmount.overkill + spellAmount.blocked + spellAmount.absorbed
										totalCount = totalCount + spellAmount.count

										if not graph[ destGUID ][segment] then
											graph[ destGUID ][segment] = 0
										end
										if not graph[ -1 ][segment] then
											graph[ -1 ][segment] = 0
										end

										local damgeCount = spellAmount.count
										graph[ destGUID ][segment] = graph[ destGUID ][segment] + damgeCount
										graph[ -1 ][segment] = graph[ -1 ][segment] + damgeCount

										local source
										for i=1,#damage[inDamagePos].sources do
											if damage[inDamagePos].sources[i][1] == sourceGUID then
												source = damage[inDamagePos].sources[i]
												break
											end
										end
										if not source then
											source = {sourceGUID,0}
											damage[inDamagePos].sources[ #damage[inDamagePos].sources+1 ] = source
										end
										source[2] = source[2] + spellAmount.amount + (DamageTab_Variables.ShowAll and (spellAmount.blocked + spellAmount.absorbed) or -spellAmount.overkill) 
									end
								end
							end
						end
					end
				end
			end
		end
		local totalIsFull = 1
		total = max(total,1)
		if total == 1 and #damage == 0 then
			total = 0
			totalIsFull = 0
		end
		local _max = nil
		reportOptions[1] = L.BossWatcherReportCount
		wipe(reportData[1])
		reportData[1][1] = GetSpellLink(spellIDnow).." > "..L.BossWatcherAllTargets

		if DamageTab_Variables.ShowAll then
			total = total + totalOver
			sort(damage,function(a,b) return (a[2]+a[4]+a[5]+a[6])>(b[2]+b[4]+b[5]+b[6]) end)
			_max = damage[1] and (damage[1][2]+damage[1][4]+damage[1][5]+damage[1][6]) or 0
		else
			sort(damage,function(a,b) return a[2]>b[2] end)
			_max = damage[1] and damage[1][2] or 0
		end
		reportData[1][2] = L.BossWatcherReportTotal.." - "..ExRT.F.shortNumber(total).."@1@ ("..floor(totalCount)..")@1#"
		DamageTab_SetLine({
			line = 1,
			name = L.BossWatcherReportTotal,
			num = total,
			total = total,
			max = total,
			alpha = DamageTab_Variables.ShowAll and totalOver,
			dps = totalCount,
			spellID = -1,
			check = BWInterfaceFrame.GraphFrame:IsShown(),
			checkState = true,
		})
		for i=#damage,1,-1 do
			if damage[i].total == 0 then
				tremove(damage,i)
			end
		end
		for i=1,#damage do
			local class = nil
			if damage[i][1] and damage[i][1] ~= "" then
				class = select(2,GetPlayerInfoByGUID(damage[i][1]))
			end
			local icon = ""
			if class and CLASS_ICON_TCOORDS[class] then
				icon = {"Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES",unpack(CLASS_ICON_TCOORDS[class])}
			end
			local tooltipData = {GetGUID(damage[i][1]),
				{L.BossWatcherDamageTooltipCount,damage[i][3]},
				{L.BossWatcherDamageTooltipMaxHit,damage[i][13]},
				{L.BossWatcherDamageTooltipMidHit,ExRT.F.Round((damage[i][2]-damage[i][7]+damage[i][4])/max(damage[i][3]-damage[i][8],1))},
				{L.BossWatcherDamageTooltiCritCount,format("%d (%.1f%%)",damage[i][8],damage[i][8]/damage[i][3]*100)},
				{L.BossWatcherDamageTooltiCritAmount,ExRT.F.shortNumber(damage[i][7])},
				{L.BossWatcherDamageTooltiMaxCrit,damage[i][9]},
				{L.BossWatcherDamageTooltiMidCrit,ExRT.F.Round(damage[i][7]/max(damage[i][8],1))},
				{L.BossWatcherDamageTooltipParry,format("%d (%.1f%%)",damage[i][14],damage[i][14]/damage[i][3]*100)},
				{L.BossWatcherDamageTooltipDodge,format("%d (%.1f%%)",damage[i][15],damage[i][15]/damage[i][3]*100)},
				{L.BossWatcherDamageTooltipMiss,format("%d (%.1f%%)",damage[i][16],damage[i][16]/damage[i][3]*100)},
				{L.BossWatcherDamageTooltipOverkill,ExRT.F.shortNumber(damage[i][4])},
				{L.BossWatcherDamageTooltipBlocked,ExRT.F.shortNumber(damage[i][5])},
				{L.BossWatcherDamageTooltipAbsorbed,ExRT.F.shortNumber(damage[i][6])},
				{L.BossWatcherDamageTooltipTotal,ExRT.F.shortNumber(damage[i][4]+damage[i][5]+damage[i][6]+damage[i][2])},
			}
			sort(damage[i].sources,DamageTab_Temp_SortingBy2Param)
			if #damage[i].sources > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherDamageTooltipSources," "}
			end
			for j=1,min(5,#damage[i].sources) do
				tooltipData[#tooltipData + 1] = {SubUTF8String(GetGUID(damage[i].sources[j][1]),20)..GUIDtoText(" [%s]",damage[i].sources[j][1]),format("%s (%.1f%%)",ExRT.F.shortNumber(damage[i].sources[j][2]),min(damage[i].sources[j][2] / max(1,(DamageTab_Variables.ShowAll and damage[i].total or damage[i][2]))*100,100))}
			end

			local currDamage = damage[i][2]+(DamageTab_Variables.ShowAll and (damage[i][4]+damage[i][5]+damage[i][6]) or 0)
			DamageTab_SetLine({
				line = i+1,
				icon = icon,
				name = GetGUID(damage[i][1])..GUIDtoText(" [%s]",damage[i][1]),
				num = currDamage,
				alpha = DamageTab_Variables.ShowAll and (damage[i][4]+damage[i][5]+damage[i][6]),
				total = total,
				max = _max,
				dps = damage[i][3],
				class = class,
				sourceGUID = damage[i][1],
				doEnemy = doEnemy,
				tooltip = tooltipData,
				check = BWInterfaceFrame.GraphFrame:IsShown(),
				checkState = i <= 3,
			})
			reportData[1][#reportData[1]+1] = i..". "..GetGUID(damage[i][1]).." - "..ExRT.F.shortNumber(currDamage).."@1@ ("..(damage[i][3]-damage[i][11])..")@1#"
		end
		for i=#damage+2,#BWInterfaceFrame.tab.tabs[1].lines do
			BWInterfaceFrame.tab.tabs[1].lines[i]:Hide()
		end
		BWInterfaceFrame.tab.tabs[1].scroll:Height((#damage+1) * 20)


		DamageTab_Variables.graphCache = {graph,#CurrentFight.segments,damage,false}
		if BWInterfaceFrame.GraphFrame:IsShown() then
			DamageTab_ReloadGraph(graph,#CurrentFight.segments,damage,false)
		end
	end

	local function DamageTab_ShowDamageToTarget(GUID)
		local button = BWInterfaceFrame.tab.tabs[1].button
		local func = button:GetScript("OnClick")

		DamageTab_Variables.state_friendly = true
		DamageTab_Variables.state_spells = false
		DamageTab_Variables.state_byTarget = false
		DamageTab_Variables.state_spellsTarget = false

		func(button)

		DamageTab_UpdatePage(true,function()
			destVar[GUID] = true
		end)
	end

	local function DamageTab_DPS_SelectDropDownSource(self,arg)
		ELib:DropDownClose()
		wipe(sourceVar)
		if arg then
			sourceVar[arg] = true

			if IsShiftKeyDown() then
				local name = CurrentFight.guids[arg]
				if name then
					for GUID,GUIDname in pairs(CurrentFight.guids) do
						if GUIDname == name then
							sourceVar[GUID] = true
						end
					end
				end
			elseif IsControlKeyDown() then
				local name = CurrentFight.guids[arg]
				if name then
					sourceVar[arg] = nil
					for GUID,GUIDname in pairs(CurrentFight.guids) do
						if GUIDname ~= name then
							sourceVar[GUID] = true
						end
					end
				end
			end
		end
		DamageTab_UpdatePage()
	end
	local function DamageTab_DPS_SelectDropDownDest(self,arg)
		ELib:DropDownClose()
		wipe(destVar)
		if arg then
			destVar[arg] = true

			if IsShiftKeyDown() then
				local name = CurrentFight.guids[arg]
				if name then
					for GUID,GUIDname in pairs(CurrentFight.guids) do
						if GUIDname == name then
							destVar[GUID] = true
						end
					end
				end
			elseif IsControlKeyDown() then
				local name = CurrentFight.guids[arg]
				if name then
					destVar[arg] = nil
					for GUID,GUIDname in pairs(CurrentFight.guids) do
						if GUIDname ~= name then
							destVar[GUID] = true
						end
					end
				end
			end
		end
		DamageTab_UpdatePage()
	end

	local function DamageTab_DPS_SelectDropDownSource_Spell(self,spellID)
		wipe(sourceVar)
		sourceVar[spellID] = true
		DamageTab_UpdatePage()
		ELib:DropDownClose()
	end

	local function DamageTab_DPS_CheckDropDownSource(self,checked)
		if checked then
			sourceVar[self.arg1] = true
		else
			sourceVar[self.arg1] = nil
		end
		DamageTab_UpdatePage()
	end
	local function DamageTab_DPS_CheckDropDownDest(self,checked)
		if checked then
			destVar[self.arg1] = true
		else
			destVar[self.arg1] = nil
		end
		DamageTab_UpdatePage()
	end

	local function DamageTab_HideArrow()
		BWInterfaceFrame.timeLineFrame.timeLine.arrow:Hide()
	end
	local function DamageTab_ShowArrow(self,pos)
		if pos then
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:SetPoint("TOPLEFT",BWInterfaceFrame.timeLineFrame.timeLine,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*pos,0)
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:Show()
		end
	end

	local function DamageTab_HoverDropDownSpell(self,spellID)
		if not spellID then
			return
		end
		ELib.Tooltip.Link(self,"spell:"..spellID)
	end

	local function DamageTab_DPS(disableUpdateVars)
		local doEnemy = DamageTab_Variables.state_friendly
		local isBySpellDamage = DamageTab_Variables.state_spellsTarget
		if isBySpellDamage then
			doEnemy = false
		end

		local reaction = 512 
		if not doEnemy then 
			reaction = 256 
		end

		if not CurrentFight.damage then	--First load fix
			return
		end

		local sourceTable = {}
		local destTable = {}
		for destGUID,destData in pairs(CurrentFight.damage) do
			for destReaction,destReactData in pairs(destData) do
				if GetUnitInfoByUnitFlagFix(destReaction,2) == reaction then
					for sourceGUID,sourceData in pairs(destReactData) do
						local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
						if owner then
							sourceGUID = owner
						end
						for spellID,spellSegments in pairs(sourceData) do
							for segment,spellAmount in pairs(spellSegments) do
								if CurrentFight.segments[segment].e then
									if not ExRT.F.table_find(destTable,destGUID,1) then
										destTable[#destTable + 1] = {destGUID,CurrentFight.damage_seen[destGUID] or 0}
									end
									if not isBySpellDamage and not ExRT.F.table_find(sourceTable,sourceGUID,1) then
										sourceTable[#sourceTable + 1] = {sourceGUID,GetGUID(sourceGUID)}
									elseif isBySpellDamage then
										if spellID < 0 then
											spellID = -spellID
										end
										if not ExRT.F.table_find(sourceTable,spellID,1) then
											local spellName,_,spellIcon = GetSpellInfo(spellID)
											sourceTable[#sourceTable + 1] = {spellID,spellName,spellIcon}
										end

									end
								end
							end
						end
					end
				end
			end
		end
		sort(sourceTable,function(a,b) return a[2]<b[2] end)
		sort(destTable,function(a,b) return a[2]<b[2] end)
		wipe(BWInterfaceFrame.tab.tabs[1].sourceDropDown.List)
		wipe(BWInterfaceFrame.tab.tabs[1].targetDropDown.List)
		if not isBySpellDamage then
			BWInterfaceFrame.tab.tabs[1].sourceDropDown.List[1] = {text = L.BossWatcherAll,func = DamageTab_DPS_SelectDropDownSource,padding = 16}
			BWInterfaceFrame.tab.tabs[1].targetDropDown.List[1] = {text = L.BossWatcherAll,func = DamageTab_DPS_SelectDropDownDest,padding = 16}
			for i=1,#sourceTable do
				local isPlayer = ExRT.F.GetUnitTypeByGUID(sourceTable[i][1]) == 0
				local classColor = ""
				if isPlayer then
					classColor = "|c"..ExRT.F.classColorByGUID(sourceTable[i][1])
				end
				BWInterfaceFrame.tab.tabs[1].sourceDropDown.List[i+1] = {
					text = classColor..sourceTable[i][2]..GUIDtoText(" [%s]",sourceTable[i][1]),
					arg1 = sourceTable[i][1],
					func = DamageTab_DPS_SelectDropDownSource,
					checkFunc = DamageTab_DPS_CheckDropDownSource,
					checkable = true,
				}
			end
			BWInterfaceFrame.tab.tabs[1].targetDropDown:Show()
			BWInterfaceFrame.tab.tabs[1].targetText:Show()
		else
			for i=1,#sourceTable do
				local spellColorTable = module.db.schoolsColors[ module.db.spellsSchool[ sourceTable[i][1] ] or 0 ] or module.db.schoolsColors[0]
				local spellColor = "|cff"..format("%02x%02x%02x",spellColorTable.r*255,spellColorTable.g*255,spellColorTable.b*255)
				BWInterfaceFrame.tab.tabs[1].sourceDropDown.List[i] = {
					text = spellColor..sourceTable[i][2],
					arg1 = sourceTable[i][1],
					func = DamageTab_DPS_SelectDropDownSource_Spell,
					icon = sourceTable[i][3],
					hoverFunc = DamageTab_HoverDropDownSpell,
					hoverArg = sourceTable[i][1],
					leaveFunc = GameTooltip_Hide,
				}
			end
			BWInterfaceFrame.tab.tabs[1].targetDropDown:Hide()
			BWInterfaceFrame.tab.tabs[1].targetText:Hide()
			wipe(sourceVar)
			wipe(destVar)
			return
		end
		for i=1,#destTable do
			local isPlayer = ExRT.F.GetUnitTypeByGUID(destTable[i][1]) == 0
			local classColor = ""
			if isPlayer then
				classColor = "|c"..ExRT.F.classColorByGUID(destTable[i][1])
			end
			BWInterfaceFrame.tab.tabs[1].targetDropDown.List[i+1] = {
				text = classColor.. date("%M:%S ", timestampToFightTime( CurrentFight.damage_seen[destTable[i][1]] ))..GetGUID(destTable[i][1])..GUIDtoText(" [%s]",destTable[i][1]),
				arg1 = destTable[i][1],
				func = DamageTab_DPS_SelectDropDownDest,
				hoverFunc = DamageTab_ShowArrow,
				leaveFunc = DamageTab_HideArrow,
				hoverArg = timestampToFightTime( CurrentFight.damage_seen[destTable[i][1]] ) / GetFightLength(true),
				checkFunc = DamageTab_DPS_CheckDropDownDest,
				checkable = true,
			}
		end
		if not disableUpdateVars then
			wipe(sourceVar)
			wipe(destVar)
		end
	end

	function DamageTab_UpdatePage(updateLists,midFunc,disableUpdateVars)
		ExRT.F.dprint("Damage Tab: Update Page",GetTime())
		if updateLists then
			DamageTab_DPS(disableUpdateVars)
		end
		if midFunc then
			midFunc()
		end
		if DamageTab_Variables.state_spellsTarget then
			DamageTab_UpdateLinesSpellToTargets()
		elseif DamageTab_Variables.state_spells then
			DamageTab_UpdateLinesSpells()
		else
			DamageTab_UpdateLinesPlayers()
		end
	end

	tab.chkFriendly = ELib:Radio(tab,L.BossWatcherFriendly,true):Point(15,-50):AddButton():OnClick(function(self) 
		DamageTab_Variables.state_friendly = true
		DamageTab_Variables.state_spellsTarget = false
		BWInterfaceFrame.tab.tabs[1].chkEnemy:SetChecked(false)
		BWInterfaceFrame.tab.tabs[1].chkSpellsTargets:SetChecked(false)
		self:SetChecked(true)

		DamageTab_UpdatePage(true)
	end)
	tab.chkEnemy = ELib:Radio(tab,L.BossWatcherHostile):Point(15,-65):AddButton():OnClick(function(self) 
		DamageTab_Variables.state_friendly = false
		DamageTab_Variables.state_spellsTarget = false
		BWInterfaceFrame.tab.tabs[1].chkFriendly:SetChecked(false)
		BWInterfaceFrame.tab.tabs[1].chkSpellsTargets:SetChecked(false)
		self:SetChecked(true)

		DamageTab_UpdatePage(true)
	end)
	tab.chkSpellsTargets = ELib:Radio(tab,L.BossWatcherDamageDamageSpellToFriendly):Point(15,-80):AddButton():OnClick(function(self) 
		DamageTab_Variables.state_friendly = true
		DamageTab_Variables.state_spellsTarget = true
		BWInterfaceFrame.tab.tabs[1].chkFriendly:SetChecked(false)
		BWInterfaceFrame.tab.tabs[1].chkEnemy:SetChecked(false)
		self:SetChecked(true)

		DamageTab_UpdatePage(true)
	end)

	tab.bySource = ELib:Radio(tab,L.BossWatcherBySource,true):Point(200,-50):AddButton():OnClick(function(self) 
		DamageTab_Variables.state_byTarget = false
		DamageTab_Variables.state_spells = false
		BWInterfaceFrame.tab.tabs[1].byTarget:SetChecked(false)
		BWInterfaceFrame.tab.tabs[1].bySpell:SetChecked(false)
		self:SetChecked(true)

		DamageTab_UpdatePage(true)
	end)
	tab.byTarget = ELib:Radio(tab,L.BossWatcherByTarget):Point(200,-65):AddButton():OnClick(function(self) 
		DamageTab_Variables.state_byTarget = true
		DamageTab_Variables.state_spells = false
		BWInterfaceFrame.tab.tabs[1].bySource:SetChecked(false)
		BWInterfaceFrame.tab.tabs[1].bySpell:SetChecked(false)
		self:SetChecked(true)

		DamageTab_UpdatePage(true)
	end)
	tab.bySpell = ELib:Radio(tab,L.BossWatcherBySpell):Point(200,-80):AddButton():OnClick(function(self) 
		DamageTab_Variables.state_byTarget = false
		DamageTab_Variables.state_spells = true
		BWInterfaceFrame.tab.tabs[1].bySource:SetChecked(false)
		BWInterfaceFrame.tab.tabs[1].byTarget:SetChecked(false)
		self:SetChecked(true)

		DamageTab_UpdatePage(true)
	end)


	tab.sourceDropDown = ELib:DropDown(tab,250,20):Size(195):Point(430,-50):SetText(L.BossWatcherAll):Tooltip(L.BossWatcherDropdownsHoldShiftSource)
	tab.sourceText = ELib:Text(tab,L.BossWatcherSource..":",12):Size(100,20):Point("RIGHT",tab.sourceDropDown,"LEFT",-6,0):Right():Color():Shadow()

	tab.targetDropDown = ELib:DropDown(tab,250,20):Size(195):Point(430,-75):SetText(L.BossWatcherAll):Tooltip(L.BossWatcherDropdownsHoldShiftDest)
	tab.targetText = ELib:Text(tab,L.BossWatcherTarget..":",12):Size(100,20):Point("TOPRIGHT",tab.targetDropDown,"TOPLEFT",-6,0):Right():Color():Shadow()


	function tab.sourceDropDown:additionalToggle()
		for i=2,#self.List do
			self.List[i].checkState = sourceVar[ self.List[i].arg1 ]
		end
	end
	function tab.targetDropDown:additionalToggle()
		for i=2,#self.List do
			self.List[i].checkState = destVar[ self.List[i].arg1 ]
		end
	end

	tab.showOverallChk = ELib:Check(tab,"|cffffffff"..L.BossWatcherOverdamage):Point(650,-50):Tooltip(L.BossWatcherDamageShowOver):OnClick(function (self)
		if self:GetChecked() then
			DamageTab_Variables.ShowAll = true
		else
			DamageTab_Variables.ShowAll = false
		end
		DamageTab_UpdatePage()
	end)

	tab.showGraphChk = ELib:Check(tab,"|cffffffff"..L.BossWatcherTabGraphics.." ",VMRT.BossWatcher.optionsDamageGraph):Point(650,-75):OnClick(function (self)
		local tab1 = BWInterfaceFrame.tab.tabs[1]
		if self:GetChecked() then
			tab1.scroll:Point("TOP",0,-305)
			BWInterfaceFrame.GraphFrame:Show()
		else
			tab1.scroll:Point("TOP",0,-100)
			BWInterfaceFrame.GraphFrame:Hide()
		end
		VMRT.BossWatcher.optionsDamageGraph = self:GetChecked()
		if DamageTab_Variables.graphCache then
			DamageTab_ReloadGraph(unpack(DamageTab_Variables.graphCache))
		end
	end)

	tab.scroll = ELib:ScrollFrame(tab):Point("TOP",0,VMRT.BossWatcher.optionsDamageGraph and -305 or -100):Point("BOTTOM",0,10):Height(600)
	tab.scroll:SetWidth(835)
	tab.scroll.C:SetWidth(835)
	tab.lines = {}

	local function DamageTab_RightClick_BackFunction()
		if not DamageTab_Variables.Back_state then
			DamageTab_UpdatePage(true)
			return
		end
		DamageTab_Variables.state_friendly = DamageTab_Variables.Back_state[1]
		DamageTab_Variables.state_spells = DamageTab_Variables.Back_state[2]
		DamageTab_Variables.state_spellsTarget = DamageTab_Variables.Back_state[3]
		DamageTab_Variables.state_byTarget = DamageTab_Variables.Back_state[4]

		DamageTab_UpdatePage(true,function()
			sourceVar = DamageTab_Variables.Back_state[5]
			destVar = DamageTab_Variables.Back_state[6]
		end)
		DamageTab_Variables.Back_state = nil
	end

	tab.scroll:SetScript("OnMouseUp",function(self,button)
		if button == "RightButton" then
			DamageTab_RightClick_BackFunction()
		end
	end)

	local function DamageTab_Line_Check_OnClick(self)
		local spellID = self:GetParent().spellID or self:GetParent().sourceGUID
		if not spellID then
			return
		end
		local graphData = BWInterfaceFrame.GraphFrame.G.data
		if self:GetParent().isDoT and type(spellID) == 'number' then
			spellID = -spellID
		end
		local findPos = ExRT.F.table_find(graphData,spellID,'info_spellID')
		if findPos then
			graphData[ findPos ].hide = not self:GetChecked()
		end
		BWInterfaceFrame.GraphFrame.G:Reload()
	end
	local function DamageTab_Line_OnClick(self,button)
		if button == "RightButton" then
			DamageTab_RightClick_BackFunction()
			return
		end
		local x,y = ExRT.F.GetCursorPos(self)
		if (self.check and self.check:IsShown() or (self:GetParent().check and self:GetParent().check:IsShown())) and x <= 30 then
			return
		end
		local GUID = self.sourceGUID
		local tooltip = self.spellLink

		local parent = self:GetParent()
		if parent.isMain then
			GUID = parent.sourceGUID
			tooltip = parent.spellLink
		end
		if parent.isMain and IsShiftKeyDown() and tooltip and tooltip:find("spell:") then
			local spellID = tooltip:match("%d+")
			if spellID then
				ExRT.F.LinkSpell(spellID)
				return
			end
		end
		if GUID then
			if not DamageTab_Variables.state_spells then
				DamageTab_Variables.Back_state = {
					DamageTab_Variables.state_friendly,
					DamageTab_Variables.state_spells,
					DamageTab_Variables.state_spellsTarget,
					DamageTab_Variables.state_byTarget,
					ExRT.F.table_copy2(sourceVar),
					ExRT.F.table_copy2(destVar),
				}
				DamageTab_Variables.state_spells = true
				DamageTab_UpdatePage(true,function()
					if DamageTab_Variables.state_byTarget then
						wipe(destVar)
						destVar[GUID] = true
					else
						wipe(sourceVar)
						sourceVar[GUID] = true
					end
				end,true)
			end
		end
	end
	local function DamageTab_LineOnEnter(self)
		if self.tooltip then
			GameTooltip:SetOwner(self,"ANCHOR_LEFT")
			local firstLine = self.tooltip[1]
			if type(firstLine) == "table" then
				firstLine = (firstLine[2] and "|T"..firstLine[2]..":18|t " or "")..firstLine[1]
			end
			GameTooltip:SetText(firstLine)
			for i=2,#self.tooltip do
				if type(self.tooltip[i]) == "table" then
					GameTooltip:AddDoubleLine(self.tooltip[i][1],self.tooltip[i][2],1,1,1,1,1,1,1,1)
				else
					GameTooltip:AddLine(self.tooltip[i])
				end
			end
			GameTooltip:Show()
		end
	end
	local function DamageTab_Line_OnEnter(self)
		local parent = self:GetParent()
		if parent.spellLink then
			GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
			GameTooltip:SetHyperlink(parent.spellLink)
			GameTooltip:Show()
		elseif parent.name:IsTruncated() then
			GameTooltip:SetOwner(self,"ANCHOR_LEFT")
			GameTooltip:SetText(parent.name:GetText())
			GameTooltip:Show()
		elseif parent.tooltip then
			DamageTab_LineOnEnter(parent)
		end
	end
	function DamageTab_SetLine(dataTable)
		local i,icon,name,overall_num,overall,total,dps,class,sourceGUID,spellLink,tooltip,school,overall_black,showCheck,checkState,spellID,isDoT

		i = dataTable.line
		icon = dataTable.icon or ""
		name = dataTable.name
		total = dataTable.num
		overall_num = dataTable.num / max(dataTable.total,1)
		overall = dataTable.num / max(dataTable.max,1)
		if dataTable.alpha then
			overall_black = dataTable.alpha / max(dataTable.num,1)
		end
		dps = dataTable.dps
		class = dataTable.class
		sourceGUID = dataTable.sourceGUID
		if dataTable.spellID and dataTable.spellID ~= -1 then
			spellLink = "spell:"..dataTable.spellID
		end
		tooltip = dataTable.tooltip
		school = dataTable.school
		showCheck = dataTable.check
		checkState = dataTable.checkState
		spellID = dataTable.spellID
		isDoT = dataTable.isDoT

		local line = BWInterfaceFrame.tab.tabs[1].lines[i]
		if not line then
			line = CreateFrame("Button",nil,BWInterfaceFrame.tab.tabs[1].scroll.C)
			BWInterfaceFrame.tab.tabs[1].lines[i] = line
			line:SetSize(815,20)
			line:SetPoint("TOPLEFT",0,-(i-1)*20)

			line.leftSide = CreateFrame("Frame",nil,line)
			line.leftSide:SetSize(1,20)
			line.leftSide:SetPoint("LEFT",5,0)

			line.check = ELib:Check(line,""):Point("TOPLEFT",5,-2)
			line.check:SetSize(16,16)
			line.check:SetScript("OnClick",DamageTab_Line_Check_OnClick)

			line.overall_num = ELib:Text(line,"45.76%",12):Size(70,20):Point(250,0):Right():Color():Shadow()

			line.icon = ELib:Icon(line,nil,18):Point("TOPLEFT",line.leftSide,0,-1)
			line.name = ELib:Text(line,"name",12):Size(0,20):Point("TOPLEFT",line.leftSide,25,0):Point("TOPRIGHT",line.overall_num,"TOPLEFT",0,0):Color():Shadow()
			line.name:SetMaxLines(1)

			line.name_tooltip = CreateFrame('Button',nil,line)
			line.name_tooltip:SetAllPoints(line.name)
			line.overall = line:CreateTexture(nil, "BACKGROUND")
			line.overall:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\bar24.tga")
			line.overall:SetSize(300,16)
			line.overall:SetPoint("TOPLEFT",325,-2)
			line.overall_black = line:CreateTexture(nil, "BACKGROUND")
			line.overall_black:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\bar24b.tga")
			line.overall_black:SetSize(300,16)
			line.overall_black:SetPoint("LEFT",line.overall,"RIGHT",0,0)

			line.total = ELib:Text(line,"125.46M",12):Size(95,20):Point(630,0):Color():Shadow()
			line.dps = ELib:Text(line,"34576.43",12):Size(100,20):Point(725,0):Color():Shadow()

			line.back = line:CreateTexture(nil, "BACKGROUND")
			line.back:SetAllPoints()
			if i%2 == 0 then
				line.back:SetColorTexture(0.3, 0.3, 0.3, 0.1)
			end
			line.name_tooltip:SetScript("OnClick",DamageTab_Line_OnClick)
			line.name_tooltip:SetScript("OnEnter",DamageTab_Line_OnEnter)
			line.name_tooltip:SetScript("OnLeave",GameTooltip_Hide)
			line:SetScript("OnClick",DamageTab_Line_OnClick)
			line:SetScript("OnEnter",DamageTab_LineOnEnter)
			line:SetScript("OnLeave",GameTooltip_Hide)
			line:RegisterForClicks("AnyUp")

			line.isMain = true
		end
		if type(icon) == "table" then
			line.icon.texture:SetTexture(icon[1] or "Interface\\Icons\\INV_MISC_QUESTIONMARK")
			line.icon.texture:SetTexCoord(unpack(icon,2,5))
		else
			line.icon.texture:SetTexture(icon or "Interface\\Icons\\INV_MISC_QUESTIONMARK")
			line.icon.texture:SetTexCoord(0,1,0,1)
		end
		line.name:SetText(name or "")
		line.overall_num:SetFormattedText("%.2f%%",overall_num and overall_num * 100 or 0)
		if overall_black and overall_black > 0 then
			local width = 300*(overall or 1)
			local normal_width = width * (1 - overall_black)
			line.overall:SetWidth(max(normal_width,1))
			line.overall_black:SetWidth(max(width-normal_width,1))
			line.overall_black:Show()
			if normal_width == 0 then
				line.overall:Hide()
				line.overall_black:SetPoint("TOPLEFT",325,-2)
			else
				line.overall:Show()
				line.overall_black:ClearAllPoints()
				line.overall_black:SetPoint("LEFT",line.overall,"RIGHT",0,0)
			end
		else
			line.overall:Show()
			line.overall_black:Hide()
			line.overall:SetWidth(max(300*(overall or 1),1))
		end
		line.total:SetText(total and ExRT.F.shortNumber(total) or "")
		do
			dps = dps or 0
			if PlayerGetTimerunningSeasonID and PlayerGetTimerunningSeasonID() == 2 then
				line.dps:SetFormattedText("%.1f%s",dps / (dps >= 1000000 and 1000000 or 1000),dps > 1000000 and "m" or "k")
			else
				line.dps:SetFormattedText("%s.%s",FormatLargeNumber(floor(dps)),format("%.2f",dps % 1):gsub("^.-%.",""))
			end
		end
		line.overall:SetGradient("HORIZONTAL",CreateColor(0,0,0,0), CreateColor(0,0,0,0))
		line.overall_black:SetGradient("HORIZONTAL",CreateColor(0,0,0,0), CreateColor(0,0,0,0))
		if class then
			local classColorArray = type(CUSTOM_CLASS_COLORS)=="table" and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
			if classColorArray then
				line.overall:SetVertexColor(classColorArray.r,classColorArray.g,classColorArray.b, 1)
				line.overall_black:SetVertexColor(classColorArray.r,classColorArray.g,classColorArray.b, 1)
			else
				line.overall:SetVertexColor(0.8,0.8,0.8, 1)
				line.overall_black:SetVertexColor(0.8,0.8,0.8, 1)
			end
		else
			line.overall:SetVertexColor(0.8,0.8,0.8, 1)
			line.overall_black:SetVertexColor(0.8,0.8,0.8, 1)
		end
		if school then
			SetSchoolColorsToLine(line.overall,school)
			SetSchoolColorsToLine(line.overall_black,school)
		end
		if showCheck then
			line.leftSide:SetPoint("LEFT",25,0)
			line.check:SetChecked(checkState)
			line.check:Show()
		else
			line.leftSide:SetPoint("LEFT",5,0)
			line.check:Hide()
		end
		line.sourceGUID = sourceGUID
		line.spellID = spellID
		line.spellLink = spellLink
		line.tooltip = tooltip
		line.isDoT = isDoT
		line:Show()
	end


	tab:SetScript("OnShow",function (self)
		BWInterfaceFrame.timeLineFrame:ClearAllPoints()
		BWInterfaceFrame.timeLineFrame:SetPoint("TOP",self,"TOP",0,-10)
		BWInterfaceFrame.timeLineFrame:Show()

		BWInterfaceFrame.report:Show()

		BWInterfaceFrame.GraphFrame:SetPoint("TOP",0,-105)
		if BWInterfaceFrame.tab.tabs[1].showGraphChk:GetChecked() then
			BWInterfaceFrame.GraphFrame:Show()
		end

		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			local currFightIDShort = GetFightID(CurrentFight,true)
			local disableUpdateVars = nil
			if currFightIDShort == self.lastFightShortID then
				disableUpdateVars = true
			end
			self.lastFightShortID = currFightIDShort
			DamageTab_Variables.graphCache = nil
			Graph_AutoUpdateStep()
			DamageTab_UpdatePage(true,nil,disableUpdateVars)
			self.lastFightID = BWInterfaceFrame.nowFightID
		elseif DamageTab_Variables.graphCache then
			ExRT.F.dprint("Damage Page <Show>: Update Graph",GetTime())
			DamageTab_ReloadGraph(unpack(DamageTab_Variables.graphCache))
		end
	end)
	tab:SetScript("OnHide",function (self)
		BWInterfaceFrame.timeLineFrame:Hide()
		BWInterfaceFrame.report:Hide()
		BWInterfaceFrame.GraphFrame:Hide()
	end)




	---- Auras Tab
	tab = BWInterfaceFrame.tab.tabs[3]
	local aurasTab = tab

	local AurasTab_Variables = {
		FilterSource = 0x0111,
		FilterSourceGUID = {},
		FilterDest = 0x0110,
		FilterDestGUID = {},
		NameWidth = 188,
		WorkWidth = 650,
		TotalLines = 28,
		IsFriendly = true,

		buffsFilters = {
			[1] = {[-1]=L.BossWatcherFilterOnlyBuffs,}, --> Only buffs
			[2] = {[-1]=L.BossWatcherFilterOnlyDebuffs,}, --> Only debuffs
			[3] = {[-1]=L.BossWatcherFilterBySpellID,}, --> By spellID
			[4] = {[-1]=L.BossWatcherFilterBySpellName,}, --> By spellName
			[5] = {
				[-1]=L.BossWatcherFilterTaunts,
				[-2]={62124,17735,97827,56222,51399,49560,6795,355,115546,116189,185245},
			},
			[6] = {
				[-1]=L.BossWatcherFilterStun,
				[-2]={853,105593,91797,408,119381,89766,118345,46968,107570,5211,44572,119392,122057,113656,108200,108194,30283,118905,20549,119072,115750},
			},
			[7] = {
				[-1]=L.BossWatcherFilterPersonal,
				[-2]={148467,31224,110788,55694,47585,31850,115610,122783,642,5277,118038,104773,115176,48707,1966,61336,120954,871,106922,30823,6229,22812,498},
			},
			[8] = {
				[-1]=L.BossWatcherFilterRaidSaves,
				[-2]={145629,114192,114198,81782,108281,97463,31821,15286,115213,44203,64843,76577},
			},
			[9] = {
				[-1]=L.BossWatcherFilterPotions,
				[-2]={279152,279153,279151,269853,250878,252753,251316,251231,300714,298225,298317,300741,298146,298152,298153,298154,298155,
					307159,307162,307163,307164,307160,307161,307497,307494,307496,307495,322302,344314,307199,342890,307196,307195},
			},
			[10] = {
				[-1]="DPS CD",
				[-2]={31884,162264,26297,266091,1719,47568,193530,80353,190319,113860,188592,194223,295840,296962},
			},
		},
		buffsFilterStatus = {
			[1] = true,
		},
	}
	AurasTab_Variables.TotalWidth = AurasTab_Variables.NameWidth + AurasTab_Variables.WorkWidth
	--[[
	0x0001 - hostile
	0x0010 - friendly
	0x0100 - pets & guards
	0x1000 - by GUID
	]]

	for i=5,#AurasTab_Variables.buffsFilters do
		for _,sID in ipairs(AurasTab_Variables.buffsFilters[i][-2]) do
			AurasTab_Variables.buffsFilters[i][sID] = true
		end
	end

	local UpdateBuffsPage,UpdateBuffPageDB

	tab.DecorationLine = ELib:DecorationLine(tab,true):Point("TOPLEFT",tab,"TOPLEFT",3,-9):Point("RIGHT",tab,-3,0):Size(0,20)

	tab.headerTab = ELib:Tabs(tab,0,
		L.BossWatcherBuff,
		L.BossWatcherDebuff
	):Size(850,555):Point("TOP",0,-29):SetTo(1)
	tab.headerTab:SetBackdropBorderColor(0,0,0,0)
	tab.headerTab:SetBackdropColor(0,0,0,0)

	tab.headerTab.tabs[1].button.additionalFunc = function()
		AurasTab_Variables.buffsFilterStatus[1] = true
		AurasTab_Variables.buffsFilterStatus[2] = false
		UpdateBuffPageDB()
		UpdateBuffsPage()
	end
	tab.headerTab.tabs[2].button.additionalFunc = function()
		AurasTab_Variables.buffsFilterStatus[1] = false
		AurasTab_Variables.buffsFilterStatus[2] = true
		UpdateBuffPageDB()
		UpdateBuffsPage()
	end

	tab.timeLine = {}

	do
		local scheduledUpdate
		tab.nameFilterEditBox = ELib:Edit(tab.DecorationLine:GetParent()):Point("RIGHT",tab.DecorationLine,"RIGHT",-50,0):Size(150,16):AddSearchIcon():OnChange(function (self,isUser)
			if not isUser then
				return
			end
			local text = self:GetText()
			for key,val in pairs(AurasTab_Variables.buffsFilters[4]) do
				if key ~= -1 then
					AurasTab_Variables.buffsFilters[4][key] = nil
				end
			end
			for key,val in pairs(AurasTab_Variables.buffsFilters[3]) do
				if key ~= -1 then
					AurasTab_Variables.buffsFilters[3][key] = nil
				end
			end
			local lines = {strsplit(",", text)}
			for i=1,#lines do
				if lines[i] ~= "" then
					local s = lines[i]
					if tonumber(s) then
						AurasTab_Variables.buffsFilters[3][ tonumber(s) ] = true
					else
						AurasTab_Variables.buffsFilters[4][ strlower(s) ] = true
					end
				end
			end
			if (ExRT.F.table_len(AurasTab_Variables.buffsFilters[4]) + ExRT.F.table_len(AurasTab_Variables.buffsFilters[3])) > 2 then
				AurasTab_Variables.buffsFilterStatus[4] = true
				if not scheduledUpdate then
					scheduledUpdate = C_Timer.NewTimer(1,function()
						scheduledUpdate = nil
						UpdateBuffPageDB()
						UpdateBuffsPage()
					end)
				end
			else
				AurasTab_Variables.buffsFilterStatus[4] = false
				if scheduledUpdate then
					scheduledUpdate:Cancel()
				end
				scheduledUpdate = nil
				UpdateBuffPageDB()
				UpdateBuffsPage()
				return
			end
		end)
	end

	tab.chkFriendly = ELib:Radio(tab,L.BossWatcherFriendly,true):Point(15,-35):AddButton():OnClick(function(self) 
		aurasTab.chkEnemy:SetChecked(false)
		self:SetChecked(true)

		AurasTab_Variables.IsFriendly = true
		AurasTab_Variables.FilterDest = 0x0110

		UpdateBuffPageDB()
		UpdateBuffsPage()
	end)
	tab.chkEnemy = ELib:Radio(tab,L.BossWatcherHostile):Point(15,-50):AddButton():OnClick(function(self) 
		aurasTab.chkFriendly:SetChecked(false)
		self:SetChecked(true)

		AurasTab_Variables.IsFriendly = false
		AurasTab_Variables.FilterDest = 0x0101

		UpdateBuffPageDB()
		UpdateBuffsPage()
	end)

	local function AurasTab_ActivateAnyPage(tab,check)
		local f1,f2 = UpdateBuffsPage,UpdateBuffPageDB
		UpdateBuffsPage,UpdateBuffPageDB = ExRT.NULLfunc, ExRT.NULLfunc
		aurasTab.headerTab.tabs[tab].button:Click()
		aurasTab[check == 1 and "chkFriendly" or "chkEnemy"]:Click()
		UpdateBuffsPage,UpdateBuffPageDB = f1,f2
	end

	tab.sourceDropDown = ELib:DropDown(tab,250,20):Size(190):Point(240,-38):SetText(L.BossWatcherAll)
	tab.sourceText = ELib:Text(tab,L.BossWatcherSource..":",12):Size(100,20):Point("TOPRIGHT",tab.sourceDropDown,"TOPLEFT",-6,0):Right():Color():Shadow()

	tab.targetDropDown = ELib:DropDown(tab,250,20):Size(190):Point(520,-38):SetText(L.BossWatcherAll)
	tab.targetText = ELib:Text(tab,L.BossWatcherTarget..":",12):Size(100,20):Point("TOPRIGHT",tab.targetDropDown,"TOPLEFT",-6,0):Right():Color():Shadow()

	tab.filterDropDown = ELib:DropDown(tab,150,#AurasTab_Variables.buffsFilters-3):Size(125):Point(725,-38):SetText(L.BossWatcherBuffsAndDebuffsFilterFilter)
	tab.filterDropDown.List[1] = {text = RESET,func = function()
		ELib:DropDownClose()
		for i=5,#AurasTab_Variables.buffsFilters do
			AurasTab_Variables.buffsFilterStatus[i] = false
		end
		UpdateBuffPageDB(true)
		UpdateBuffsPage()
	end,padding = 16}
	do
		local Activate = {
			[5] = {2,2},
			[7] = {1,1},
			[8] = {1,1},
			[9] = {1,1},
		}
		local function OnClick(_,arg)
			ELib:DropDownClose()
			for i=5,#AurasTab_Variables.buffsFilters do
				AurasTab_Variables.buffsFilterStatus[i] = nil
			end
			AurasTab_Variables.buffsFilterStatus[arg] = not AurasTab_Variables.buffsFilterStatus[arg]
			if Activate[arg] then
				AurasTab_ActivateAnyPage(unpack(Activate[arg]))
			end
			UpdateBuffPageDB(true)
			UpdateBuffsPage()
		end
		local function OnEnter(self,i)
			local sList = AurasTab_Variables.buffsFilters[i][-2]
			if not sList then
				sList = {}
				for sid,_ in pairs(AurasTab_Variables.buffsFilters[i]) do
					if sid > 0 then
						sList[#sList + 1] = sid
					end
				end
			end
			if #sList == 0 then
				return
			end
			local sList2 = {}
			if #sList <= 35 then
				for j=1,#sList do
					local sID,_,sT=GetSpellInfo(sList[j])
					if sID then
						sList2[#sList2 + 1] = "|T"..sT..":0|t |cffffffff"..sID.."|r"
					end
				end
			else
				local count = 1
				for j=1,#sList do
					local sID,_,sT=GetSpellInfo(sList[j])
					if sID then
						if not sList2[count] then
							sList2[count] = {"|T"..sT..":0|t |cffffffff"..sID.."|r"}
						elseif not sList2[count].right then
							sList2[count].right = "|cffffffff"..sID.."|r |T"..sT..":0|t"
							count = count + 1
						end
					end
				end
			end
			ELib.Tooltip.Show(self,"ANCHOR_LEFT",L.BossWatcherFilterTooltip..":",unpack(sList2))
		end
		for i=5,#AurasTab_Variables.buffsFilters do
			tab.filterDropDown.List[i-3] = {
				text = AurasTab_Variables.buffsFilters[i][-1],
				arg1 = i,
				func = OnClick,
				checkFunc = function(self,checked)
					AurasTab_Variables.buffsFilterStatus[i] = checked
					UpdateBuffPageDB(true)
					UpdateBuffsPage()
				end,
				checkable = true,
				hoverFunc = OnEnter,
				leaveFunc = ELib.Tooltip.Hide,
				hoverArg = i,
			}
		end
	end
	function tab.filterDropDown.additionalToggle(self)
		for i=2,#self.List do
			self.List[i].checkState = AurasTab_Variables.buffsFilterStatus[3+i]
		end
	end

	function tab.sourceDropDown.additionalToggle(self)
		for i=2,#self.List do
			self.List[i].checkState = AurasTab_Variables.FilterSourceGUID[self.List[i].arg1]
		end
	end
	function tab.targetDropDown.additionalToggle(self)
		for i=2,#self.List do
			self.List[i].checkState = AurasTab_Variables.FilterDestGUID[self.List[i].arg1]
		end
	end

	local function AurasTab_UpdateDropDownText(dropDown,arr)
		local count = ExRT.F.table_len(arr)
		if count == 0 then
			dropDown:SetText(L.BossWatcherAll)
		elseif count == 1 then
			local GUID = nil
			for g,_ in pairs(arr) do
				GUID = g
			end
			local name = GetGUID(GUID)
			local flags = CurrentFight.reaction[GUID]
			local isPlayer = flags and ExRT.F.GetUnitInfoByUnitFlag(flags,1) == 1024
			local isNPC = flags and ExRT.F.GetUnitInfoByUnitFlag(flags,2) == 512
			if isPlayer then
				name = "|c"..ExRT.F.classColorByGUID(GUID)..name
			elseif isNPC then
				name = name .. GUIDtoText(" [%s]",GUID)
			end
			dropDown:SetText(name)
		else
			dropDown:SetText(L.BossWatcherSeveral)
		end
	end
	local function AurasTab_UpdateDropDownsTexts()
		AurasTab_UpdateDropDownText(aurasTab.sourceDropDown,AurasTab_Variables.FilterSourceGUID)
		AurasTab_UpdateDropDownText(aurasTab.targetDropDown,AurasTab_Variables.FilterDestGUID)

		local anyFilter = nil
		for i=5,#AurasTab_Variables.buffsFilters do
			if AurasTab_Variables.buffsFilterStatus[i] then
				anyFilter = true
				break
			end
		end
		aurasTab.filterDropDown:SetText((anyFilter and "|cff00ff00" or "")..L.BossWatcherBuffsAndDebuffsFilterFilter)
	end


	local function AurasTab_SelectDropDownSource(self,arg)
		ELib:DropDownClose()
		wipe(AurasTab_Variables.FilterSourceGUID)
		if not arg then
			AurasTab_Variables.FilterSource = 0x0111
		elseif IsShiftKeyDown() then
			AurasTab_Variables.FilterSource = 0x1000
			AurasTab_Variables.FilterSourceGUID[arg] = true
			local name = CurrentFight.guids[arg]
			if name then
				for GUID,GUIDname in pairs(CurrentFight.guids) do
					if GUIDname == name then
						AurasTab_Variables.FilterSourceGUID[arg] = true
					end
				end
			end
		else
			AurasTab_Variables.FilterSource = 0x1000
			AurasTab_Variables.FilterSourceGUID[arg] = true
		end
		UpdateBuffPageDB(true)
		UpdateBuffsPage()
	end
	local function AurasTab_SelectDropDownDest(self,arg)
		ELib:DropDownClose()
		wipe(AurasTab_Variables.FilterDestGUID)
		if not arg then
			if AurasTab_Variables.IsFriendly then
				AurasTab_Variables.FilterDest = 0x0110
			else
				AurasTab_Variables.FilterDest = 0x0101
			end
		elseif IsShiftKeyDown() then
			AurasTab_Variables.FilterDest = 0x1000
			AurasTab_Variables.FilterDestGUID[arg] = true
			local name = CurrentFight.guids[arg]
			if name then
				for GUID,GUIDname in pairs(CurrentFight.guids) do
					if GUIDname == name then
						AurasTab_Variables.FilterDestGUID[arg] = true
					end
				end
			end
		else
			AurasTab_Variables.FilterDest = 0x1000
			AurasTab_Variables.FilterDestGUID[arg] = true
		end
		UpdateBuffPageDB(true)
		UpdateBuffsPage()
	end

	local function AurasTab_CheckDropDownSource(self,checked)
		if checked then
			AurasTab_Variables.FilterSource = 0x1000
			AurasTab_Variables.FilterSourceGUID[self.arg1] = true
		else
			AurasTab_Variables.FilterSourceGUID[self.arg1] = nil
			if ExRT.F.table_len(AurasTab_Variables.FilterSourceGUID) == 0 then
				AurasTab_Variables.FilterSource = 0x0111
			end
		end
		UpdateBuffPageDB(true)
		UpdateBuffsPage()
	end
	local function AurasTab_CheckDropDownDest(self,checked)
		if checked then
			AurasTab_Variables.FilterDest = 0x1000
			AurasTab_Variables.FilterDestGUID[self.arg1] = true
		else
			AurasTab_Variables.FilterDestGUID[self.arg1] = nil
			if ExRT.F.table_len(AurasTab_Variables.FilterDestGUID) == 0 then
				if AurasTab_Variables.IsFriendly then
					AurasTab_Variables.FilterDest = 0x0110
				else
					AurasTab_Variables.FilterDest = 0x0101
				end
			end
		end
		UpdateBuffPageDB(true)
		UpdateBuffsPage()
	end

	for i=1,11 do
		local line = CreateFrame("Frame",nil,tab)
		tab.timeLine[i] = line
		line:SetPoint("TOPLEFT",AurasTab_Variables.NameWidth+(i-1)*(AurasTab_Variables.WorkWidth/10)-1,-72)
		line:SetSize(2,AurasTab_Variables.TotalLines * 18 + 14)

		line.texture = line:CreateTexture(nil, "BACKGROUND")
		line.texture:SetColorTexture(1, 1, 1, 0.3)
		line.texture:SetAllPoints()

		line.timeText = ELib:Text(line,"",11):Size(200,12):Point("TOPRIGHT",line,"TOPLEFT",-1,-1):Right():Top():Color()
	end

	tab.redDeathLine = {}
	local function CreateRedDeathLine(i)
		if not aurasTab.redDeathLine[i] then
			local line = aurasTab:CreateTexture(nil, "BACKGROUND",0,-4)
			aurasTab.redDeathLine[i] = line
			line:SetColorTexture(1, 0.3, 0.3, 1)
			line:SetSize(2,AurasTab_Variables.TotalLines * 18 + 14)
			line:Hide()
		end
	end

	tab.linesRightClickMenu = {
		{ text = "Spell", isTitle = true, notCheckable = true, notClickable = true },
		{ text = L.BossWatcherSendToChat, func = function() 
			if aurasTab.linesRightClickMenuData then
				local chat_type = ExRT.F.chatType(true)
				SendChatMessage(aurasTab.linesRightClickMenuData[1],chat_type)
				for i=2,#aurasTab.linesRightClickMenuData do
					SendChatMessage(ExRT.F.clearTextTag(aurasTab.linesRightClickMenuData[i]),chat_type)
				end
			end
			CloseDropDownMenus()
		end, notCheckable = true },
		{  text = L.BossWatcherOnlySegmentsWithAura, func = function() 
			CloseDropDownMenus()
			local buffData = aurasTab.linesRightClickLineData
			if not buffData then
				return
			end
			local table1 = {}
			for i=1,#buffData[5] do
				table1[#table1+1] = buffData[5][i][3]
				table1[#table1+1] = buffData[5][i][4]
			end
			local len = #table1
			for i=1,len,2 do
				local time_start,time_end = table1[i],table1[i+1]
				if time_start then
					for j=i+2,len,2 do
						local new_start,new_end = table1[j],table1[j+1]
						if new_start then
							if new_start <= time_start and new_end > time_start then
								time_start = new_start
								time_end = max(time_end,new_end)

								table1[j] = nil
								table1[j+1] = nil
							elseif new_start > time_start and new_start <= time_end then
								time_end = max(time_end,new_end)

								table1[j] = nil
								table1[j+1] = nil
							end
						end
					end
					table1[i] = time_start
					table1[i+1] = time_end
				end
			end
			UpdateSegments(-1,-1,false,true)
			for i=1,len,2 do
				if table1[i] then
					UpdateSegmentsTime(table1[i]+CurrentFight.encounterStart,table1[i+1]+CurrentFight.encounterStart,true,true)
				end
			end
			UpdateSegments(-1,-1,true,false)
		end, notCheckable = true },
		{ text = L.BossWatcherAddToGraph, func = function() 
			CloseDropDownMenus()
			local buffData = aurasTab.linesRightClickLineData
			if not buffData then
				return
			end
			local table1 = {}
			for i=1,#buffData[5] do
				table1[#table1+1] = buffData[5][i][3]
				table1[#table1+1] = buffData[5][i][4]
			end
			local len = #table1
			for i=1,len,2 do
				local time_start,time_end = table1[i],table1[i+1]
				if time_start then
					for j=i+2,len,2 do
						local new_start,new_end = table1[j],table1[j+1]
						if new_start then
							if new_start <= time_start and new_end > time_start then
								time_start = new_start
								time_end = max(time_end,new_end)

								table1[j] = nil
								table1[j+1] = nil
							elseif new_start > time_start and new_start <= time_end then
								time_end = max(time_end,new_end)

								table1[j] = nil
								table1[j+1] = nil
							end
						end
					end
					table1[i] = time_start
					table1[i+1] = time_end
				end
			end
			local table2 = {}
			for i=1,len,2 do
				if table1[i] then
					table2[#table2 + 1] = table1[i]
					table2[#table2 + 1] = table1[i + 1]
				end
			end
			BWInterfaceFrame.GraphFrame.G.highlight = table2
		end, notCheckable = true },
		{ text = L.BossWatcherAurasMoreInfoText, func = function() 
			if aurasTab.linesRightClickMoreInfoData then
				aurasTab.linesRightClickMoreInfo:Update()
				aurasTab.linesRightClickMoreInfo:ShowClick()
			end
			CloseDropDownMenus()
		end, notCheckable = true },
		{ text = L.minimapmenuclose, func = function() CloseDropDownMenus() end, notCheckable = true },
	}
	tab.linesRightClickMenuDropDown = CreateFrame("Frame", BWInterfaceFrame_Name.."AurasTab".."LinesRightClickMenuDropDown", nil, "UIDropDownMenuTemplate")

	tab.linesRightClickMoreInfo = ELib:Popup(L.BossWatcherAurasMoreInfoText):Size(300,375)
	tab.linesRightClickMoreInfo.ScrollFrame = ELib:ScrollFrame(tab.linesRightClickMoreInfo):Size(285,320):Point("TOP",0,-25):Height(400)
	--tab.linesRightClickMoreInfo.ScrollFrame.backdrop:Hide()
	tab.linesRightClickMoreInfo.lines = {}
	tab.linesRightClickMoreInfo.anchor = "TOPRIGHT"
	tab.linesRightClickMoreInfo.reportButton = ELib:Button(tab.linesRightClickMoreInfo,L.BossWatcherCreateReport):Size(292,20):Point("BOTTOM",0,5):Tooltip(L.BossWatcherCreateReportTooltip):OnClick(function (self)
		ExRT.F:ToChatWindow(aurasTab.linesRightClickMoreInfo.report)
		aurasTab.linesRightClickMoreInfo:Hide()
	end)
	do
		local function LineOnEnter(self)
			if self.name:IsTruncated() then
				GameTooltip:SetOwner(self,"ANCHOR_LEFT")
				GameTooltip:SetText(self.name:GetText())
				GameTooltip:Show()
 			end
		end
		local function SetLine(i,name,count)
			if not aurasTab.linesRightClickMoreInfo.lines[i] then
				local line = CreateFrame("Button",nil,aurasTab.linesRightClickMoreInfo.ScrollFrame.C)
				aurasTab.linesRightClickMoreInfo.lines[i] = line
				line:SetSize(270,20)
				line:SetPoint("TOPLEFT",0,-(i-1)*20)

				line.name = ELib:Text(line,"name",11):Size(210,20):Point(10,0):Color():Shadow()
				line.count = ELib:Text(line,"name",12):Size(40,20):Point(220,0):Center():Color():Shadow()

				line.back = line:CreateTexture(nil, "BACKGROUND")
				line.back:SetAllPoints()
				if i%2==0 then
					line.back:SetColorTexture(0.3, 0.3, 0.3, 0.1)
				end

				line:SetScript("OnEnter",LineOnEnter)
				line:SetScript("OnLeave",GameTooltip_Hide)
			end
			aurasTab.linesRightClickMoreInfo.lines[i].name:SetText(i..". "..name)
			aurasTab.linesRightClickMoreInfo.lines[i].count:SetText(count)

			aurasTab.linesRightClickMoreInfo.lines[i]:Show()
		end
		tab.linesRightClickMoreInfo.Update = function(self)
			local spellID = aurasTab.linesRightClickMoreInfoData
			self.title:SetText(GetSpellInfo(spellID) or "?")
			local data = {}
			for i,sourceData in ipairs(CurrentFight.auras) do
				if sourceData[6] == spellID and (sourceData[8] == 1 or sourceData[8] == 3) and (not aurasTab.filterS or (aurasTab.filterS == 1 and sourceData[4]) or (aurasTab.filterS == 2 and not sourceData[4]) or aurasTab.filterS == sourceData[2]) then
					local inPos = ExRT.F.table_find(data,sourceData[3],1)
					if not inPos then
						inPos = #data + 1
						data[inPos] = {sourceData[3],0,0}
					end
					data[inPos][2] = data[inPos][2] + 1
				end
			end
			for destGUID,destData in pairs(CurrentFight.damage) do
				for destReaction,destReactData in pairs(destData) do
					for sourceGUID,sourceData in pairs(destReactData) do
						if not aurasTab.filterS or aurasTab.filterS == sourceGUID then
							if sourceData[spellID] then
								for segment,spellAmount in pairs(sourceData[spellID]) do
									local missed = spellAmount.parry + spellAmount.dodge + spellAmount.miss
									if missed > 0 then
										local inPos = ExRT.F.table_find(data,destGUID,1)
										if not inPos then
											inPos = #data + 1
											data[inPos] = {destGUID,0,0}
										end
										data[inPos][3] = data[inPos][3] + 1
									end
								end
							end
						end
					end
				end
			end
			sort(data,function(a,b)return a[2]>b[2]end)
			local report = {}
			aurasTab.linesRightClickMoreInfo.report = report
			report[1] = GetSpellLink(spellID)
			for i=1,#data do
				local isPlayer = ExRT.F.GetUnitTypeByGUID(data[i][1]) == 0
				local classColor = ""
				if isPlayer then
					classColor = "|c"..ExRT.F.classColorByGUID(data[i][1])
				end
				SetLine(i,classColor..GetGUID(data[i][1])..GUIDtoText(" [%s]",data[i][1]),data[i][2]..(data[i][3] > 0 and "+"..data[i][3] or ""))
				report[#report+1] = i..". "..GetGUID(data[i][1]).." - "..data[i][2]..(data[i][3] > 0 and "+"..data[i][3] or "")
			end
			for i=#data+1,#aurasTab.linesRightClickMoreInfo.lines do
				aurasTab.linesRightClickMoreInfo.lines[i]:Hide()
			end
			aurasTab.linesRightClickMoreInfo.ScrollFrame:SetNewHeight(#data * 20)
		end
	end

	local BuffsLineUptimeTempTable = {}
	local function BuffsLinesOnUpdate(self)
		local x,y = ExRT.F.GetCursorPos(self)
		if ExRT.F.IsInFocus(self,x,y) then
			for j=1,AurasTab_Variables.TotalLines do
				if aurasTab.lines[j] ~= self then
					aurasTab.lines[j].hl:Hide()
				end
			end
			self.hl:Show()
			if x <= AurasTab_Variables.NameWidth then
				if GameTooltip:IsShown() then
					local _,spellID = GameTooltip:GetSpell()
					if spellID == self.spellID then
						return
					end
				end
				GameTooltip:SetOwner(self, "ANCHOR_RIGHT", -AurasTab_Variables.WorkWidth, 0)
				if type(self.spellLink) == "string" and not self.spellLink:find("spell:") then
					GameTooltip:AddLine(self.spellLink)
				else
					GameTooltip:SetHyperlink(self.spellLink)
				end

				local greenCount = #self.greenTooltips
				for i=1,greenCount do
					BuffsLineUptimeTempTable[(i-1)*2+1] = self.greenTooltips[i][1]
					BuffsLineUptimeTempTable[(i-1)*2+2] = self.greenTooltips[i][2]
				end
				for i=1,greenCount do
					local iPos = (i-1)*2+1
					if BuffsLineUptimeTempTable[iPos] then
						for j=1,greenCount do
							local jPos = (j-1)*2+1
							if i~=j and BuffsLineUptimeTempTable[jPos] then
								if BuffsLineUptimeTempTable[jPos] <= BuffsLineUptimeTempTable[iPos] and BuffsLineUptimeTempTable[jPos+1] > BuffsLineUptimeTempTable[iPos] then
									BuffsLineUptimeTempTable[iPos] = BuffsLineUptimeTempTable[jPos]
									BuffsLineUptimeTempTable[iPos+1] = max(BuffsLineUptimeTempTable[jPos+1],BuffsLineUptimeTempTable[iPos+1])
									BuffsLineUptimeTempTable[jPos] = nil
									BuffsLineUptimeTempTable[jPos+1] = nil
								end
								if BuffsLineUptimeTempTable[jPos] and BuffsLineUptimeTempTable[jPos+1] >= BuffsLineUptimeTempTable[iPos+1] and BuffsLineUptimeTempTable[jPos] < BuffsLineUptimeTempTable[iPos+1] then
									BuffsLineUptimeTempTable[iPos] = min(BuffsLineUptimeTempTable[jPos],BuffsLineUptimeTempTable[iPos])
									BuffsLineUptimeTempTable[iPos+1] = BuffsLineUptimeTempTable[jPos+1]
									BuffsLineUptimeTempTable[jPos] = nil
									BuffsLineUptimeTempTable[jPos+1] = nil
								end
							end
						end
					end
				end
				local uptime = 0
				for i=1,greenCount do
					local iPos = (i-1)*2+1
					if BuffsLineUptimeTempTable[iPos] then
						uptime = uptime + (BuffsLineUptimeTempTable[iPos+1] - BuffsLineUptimeTempTable[iPos])
					end
				end
				uptime = uptime / AurasTab_Variables.WorkWidth

				GameTooltip:AddLine(L.BossWatcherBuffsAndDebuffsTooltipUptimeText..": "..format("%.2f%% (%.1f %s)",uptime*100,uptime*GetFightLength(true),L.BossWatcherBuffsAndDebuffsSecondsText))
				GameTooltip:AddLine(L.BossWatcherBuffsAndDebuffsTooltipCountText..": "..(self.greenCount or 0))
				GameTooltip:AddLine("Spell ID: "..(self.spellID or 0))
				GameTooltip:Show()
			else
				if not self.tooltip then
					self.tooltip = {}
				end
				table.wipe(self.tooltip)
				local owner = nil
				local _min,_max = AurasTab_Variables.NameWidth+AurasTab_Variables.WorkWidth,AurasTab_Variables.NameWidth
				for j = 1,#self.greenTooltips do
					local greenTooltip = self.greenTooltips[j]

					local rightPos = greenTooltip[2]
					local leftPos = greenTooltip[1]
					if rightPos - leftPos < 2 then
						rightPos = leftPos + 2
					end
					if x >= leftPos and x <= rightPos then
						local sourceClass = ExRT.F.classColorByGUID(greenTooltip[5])
						local destClass = ExRT.F.classColorByGUID(greenTooltip[6])
						local duration = (greenTooltip[4] - greenTooltip[3])
						table.insert(self.tooltip, date("[%M:%S", greenTooltip[3] ) .. format(".%03d",(greenTooltip[3]*1000)%1000).. " - "..date("%M:%S", greenTooltip[3]+duration ).. format(".%03d",((greenTooltip[3]+duration)*1000)%1000).."] " .. "|c" .. sourceClass .. GetGUID(greenTooltip[5])..GUIDtoText(" (%s)",greenTooltip[5]).."|r "..L.BossWatcherBuffsAndDebuffsTextOn.." |c".. destClass .. GetGUID(greenTooltip[6])..GUIDtoText(" (%s)",greenTooltip[6]).."|r")
						if greenTooltip[7] and greenTooltip[7] ~= 1 then
							self.tooltip[#self.tooltip] = self.tooltip[#self.tooltip] .. " (".. greenTooltip[7] ..")"
						end
						self.tooltip[#self.tooltip] = self.tooltip[#self.tooltip] .. format(" <%.1f%s>",duration,L.BossWatcherBuffsAndDebuffsSecondsText)
						owner = greenTooltip[1]

						_min = min(_min,leftPos)
						_max = max(_max,rightPos)
					end
				end
				if #self.tooltip > 0 then
					table.sort(self.tooltip,function(a,b) return a < b end)
					ELib.Tooltip.Show(self,{"ANCHOR_LEFT",owner or 0,0},L.BossWatcherBuffsAndDebuffsTooltipTitle..":",unpack(self.tooltip))
				else
					GameTooltip_Hide()
				end
			end
		end
	end
	local function BuffsLinesOnLeave(self)
		GameTooltip_Hide()
		self.hl:Hide()
	end
	local function BuffsLinesOnClick(self,button)
		local x,y = ExRT.F.GetCursorPos(self)
		if x > 0 and x < AurasTab_Variables.TotalWidth and y > 0 and y < 18 then
			if x <= AurasTab_Variables.NameWidth then
				ExRT.F.LinkSpell(nil,self.spellLink)
			elseif button == "RightButton" then
				if GameTooltip:IsShown() then
					if aurasTab.linesRightClickMenuData then
						wipe(aurasTab.linesRightClickMenuData)
					else
						aurasTab.linesRightClickMenuData = {}
					end
					table.insert(aurasTab.linesRightClickMenuData , self.spellLink)
					for j=2, GameTooltip:NumLines() do
						table.insert(aurasTab.linesRightClickMenuData , _G["GameTooltipTextLeft"..j]:GetText())
					end
					aurasTab.linesRightClickMenu[1].text = self.spellName
				else
					aurasTab.linesRightClickMenuData = nil
				end
				aurasTab.linesRightClickMoreInfoData = self.spellID
				aurasTab.linesRightClickLineData = self.lineData
				if MenuUtil then
					MenuUtil.CreateContextMenu(aurasTab.linesRightClickMenuDropDown, function(ownerRegion, rootDescription)
						for i=1,#aurasTab.linesRightClickMenu do
							if aurasTab.linesRightClickMenu[i].isTitle then
								rootDescription:CreateTitle(aurasTab.linesRightClickMenu[i].text)
							else
								rootDescription:CreateButton(aurasTab.linesRightClickMenu[i].text, aurasTab.linesRightClickMenu[i].func)
							end
						end
					end)
				else
					EasyMenu(aurasTab.linesRightClickMenu, aurasTab.linesRightClickMenuDropDown, "cursor", 10 , -15, "MENU")
				end
			end
		end
	end

	tab.lines = {}
	for i=1,AurasTab_Variables.TotalLines do
		local line = CreateFrame("Button",nil,tab)
		tab.lines[i] = line
		line:SetSize(AurasTab_Variables.TotalWidth,18)
		line:SetPoint("TOPLEFT", 0, -18*(i-1)-84)

		line.spellIcon = line:CreateTexture(nil, "BACKGROUND")
		line.spellIcon:SetSize(16,16)
		line.spellIcon:SetPoint("TOPLEFT", 5, -1)

		line.spellText = ELib:Text(line,"",11):Size(AurasTab_Variables.NameWidth-23,18):Point(23,0):Color()

		line.green = {}
		line.greenFrame = {}
		line.greenCount = 0

		line.greenTooltips = {}

		ExRT.lib.CreateHoverHighlight(line)
		line.hl:SetAlpha(.5)

		line:SetScript("OnUpdate", BuffsLinesOnUpdate) 
		line:SetScript("OnLeave", BuffsLinesOnLeave)
		line:RegisterForClicks("RightButtonUp","LeftButtonUp")
		line:SetScript("OnClick", BuffsLinesOnClick)
	end

	tab.scrollBar = ELib:ScrollBar(tab):Size(16,AurasTab_Variables.TotalLines*18):Point("TOPRIGHT",-5,-84):Range(1,2)

	local function CreateBuffGreen(i,j)
		aurasTab.lines[i].green[j] = aurasTab.lines[i]:CreateTexture(nil, "BACKGROUND",nil,5)
		aurasTab.lines[i].green[j]:SetColorTexture(1, 0.82, 0, 0.7)
		aurasTab.lines[i].greenFrame[j] = CreateFrame("Frame",nil,aurasTab.lines[i])
	end

	local function buffsFunc_isPetOrGuard(flag)
		if not flag then
			return false
		end
		local res = ExRT.F.GetUnitInfoByUnitFlag(flag,1)
		if res == 4096 or res == 8192 then
			return true
		end
	end
	local function buffsFunc_findStringInArray(array,str)
		for array_str,_ in pairs(array) do
			if type(array_str) == "string" and (array_str == str or str:find(array_str)) then
				return true
			end
		end
	end


	function UpdateBuffPageDB(notUpdateTargetsList)
		--upvaules
		local currFight = CurrentFight
		local buffsFilterStatus = AurasTab_Variables.buffsFilterStatus

		AurasTab_UpdateDropDownsTexts()

		local fightDuration = GetFightLength(true)
		for i=1,10 do
			aurasTab.timeLine[i+1].timeText:SetText( date("%M:%S", fightDuration*(i/10) ) )
		end

		local _F_sourceGUID = bit.band(AurasTab_Variables.FilterSource,0xF000) > 0
		local _F_sourceFriendly = bit.band(AurasTab_Variables.FilterSource,0x00F0) > 0
		local _F_sourceHostile = bit.band(AurasTab_Variables.FilterSource,0x000F) > 0
		local _F_sourcePets = bit.band(AurasTab_Variables.FilterSource,0x0F00) > 0

		local _F_destGUID = bit.band(AurasTab_Variables.FilterDest,0xF000) > 0
		local _F_destFriendly = bit.band(AurasTab_Variables.FilterDest,0x00F0) > 0
		local _F_destHostile = bit.band(AurasTab_Variables.FilterDest,0x000F) > 0
		local _F_destPets = bit.band(AurasTab_Variables.FilterDest,0x0F00) > 0

		local sourceList,destList = {},{}

		local buffTable = {}
		for i,sourceData in ipairs(CurrentFight.auras) do 
			local spellID = sourceData[6]
			local spellName,_,spellTexture = GetSpellInfo(spellID)
			local filterStatus = true
			for j=5,#AurasTab_Variables.buffsFilters do
				filterStatus = filterStatus and (not buffsFilterStatus[j] or AurasTab_Variables.buffsFilters[j][spellID])
			end
			if ((not _F_sourceGUID and ((_F_sourcePets or not buffsFunc_isPetOrGuard(currFight.reaction[ sourceData[2] ])) and ((_F_sourceFriendly and sourceData[4]) or (_F_sourceHostile and not sourceData[4])))) or (sourceData[2] and AurasTab_Variables.FilterSourceGUID[ sourceData[2] ])) and
				((not _F_destGUID and ((_F_destPets or not buffsFunc_isPetOrGuard(currFight.reaction[ sourceData[3] ])) and ((_F_destFriendly and sourceData[5]) or (_F_destHostile and not sourceData[5])))) or (sourceData[3] and AurasTab_Variables.FilterDestGUID[ sourceData[3] ])) and
				(not buffsFilterStatus[1] or sourceData[7] == 'BUFF') and
				(not buffsFilterStatus[2] or sourceData[7] == 'DEBUFF') and
				(not buffsFilterStatus[4] or (AurasTab_Variables.buffsFilters[3][spellID] or buffsFunc_findStringInArray(AurasTab_Variables.buffsFilters[4],strlower(spellName)))) and
				filterStatus then

				local time_ = timestampToFightTime( sourceData[1] )
				local time_postion = time_ / fightDuration
				local type_ = sourceData[8]

				local buffTablePos
				for j=1,#buffTable do
					if buffTable[j][1] == spellID then
						buffTablePos = j
						break
					end
				end
				if not buffTablePos then
					buffTablePos = #buffTable + 1
					buffTable[buffTablePos] = {spellID,spellName,spellTexture,{},{}}
				end

				local sourceGUID = sourceData[2] or 0
				local destGUID = sourceData[3] or 0
				local sourceDest = sourceGUID .. destGUID
				local buffTableBuffPos
				for j=1,#buffTable[buffTablePos][4] do
					if buffTable[buffTablePos][4][j][1] == sourceDest then
						buffTableBuffPos = j
						break
					end
				end
				if not buffTableBuffPos then
					buffTableBuffPos = #buffTable[buffTablePos][4] + 1
					buffTable[buffTablePos][4][buffTableBuffPos] = {sourceDest,sourceGUID,destGUID,{}}
				end

				local eventPos = #buffTable[buffTablePos][4][buffTableBuffPos][4] + 1

				if type_ == 3 or type_ == 4 then
					buffTable[buffTablePos][4][buffTableBuffPos][4][eventPos] = {0,time_,time_postion,sourceData[9] or 1}
					type_ = 1
					eventPos = eventPos + 1
				end
				buffTable[buffTablePos][4][buffTableBuffPos][4][eventPos] = {type_ % 2,time_,time_postion,sourceData[9] or 1}

				sourceList[sourceGUID] = true
				destList[destGUID] = true
			end
			if ((_F_sourceFriendly and sourceData[4]) or (_F_sourceHostile and not sourceData[4])) and
				((_F_destFriendly and sourceData[5]) or (_F_destHostile and not sourceData[5])) and
				(not buffsFilterStatus[1] or sourceData[7] == 'BUFF') and
				(not buffsFilterStatus[2] or sourceData[7] == 'DEBUFF') and
				(not buffsFilterStatus[4] or (AurasTab_Variables.buffsFilters[3][spellID] or buffsFunc_findStringInArray(AurasTab_Variables.buffsFilters[4],strlower(spellName)))) and
				filterStatus then

				local sourceGUID = sourceData[2] or 0
				local destGUID = sourceData[3] or 0
				sourceList[sourceGUID] = true
				destList[destGUID] = true
			end
		end

		sort(buffTable,function(a,b) return a[2] < b[2] end)

		for i=1,#buffTable do 
			local buffTableI = buffTable[i]

			for j=1,#buffTableI[4] do
				local buffTableJ = buffTableI[4][j]

				local maxEvents = #buffTableJ[4]
				if maxEvents > 0 and buffTableJ[4][1][1] == 0 then
					local newLine = #buffTableI[5] + 1
					buffTableI[5][newLine] = {
						AurasTab_Variables.NameWidth,
						AurasTab_Variables.NameWidth+AurasTab_Variables.WorkWidth*buffTableJ[4][1][3],
						0,
						buffTableJ[4][1][2],
						buffTableJ[2],
						buffTableJ[3],
						1,
					}
				end
				for k=1,maxEvents do
					if buffTableJ[4][k][1] == 1 then
						local endOfTime = nil
						for n=(k+1),maxEvents do
							if buffTableJ[4][n][1] == 0 and not endOfTime then
								endOfTime = n
								--break
							end
						end
						local newLine = #buffTableI[5] + 1
						buffTableI[5][newLine] = {
							AurasTab_Variables.NameWidth+AurasTab_Variables.WorkWidth*buffTableJ[4][k][3],
							AurasTab_Variables.NameWidth+AurasTab_Variables.WorkWidth*(endOfTime and buffTableJ[4][endOfTime][3] or 1),
							buffTableJ[4][k][2],
							endOfTime and buffTableJ[4][endOfTime][2] or fightDuration,
							buffTableJ[2],
							buffTableJ[3],
							buffTableJ[4][k][4],
						}
						--startPos,endPos,startTime,endTime,sourceGUID,destGUID,stacks
					end
				end
			end
		end

		--> Death Line
		for i=1,#aurasTab.redDeathLine do
			aurasTab.redDeathLine[i]:Hide()
		end
		if _F_destGUID and ExRT.F.table_len(AurasTab_Variables.FilterDestGUID) > 0 then
			local j = 0
			for i=1,#CurrentFight.dies do
				if AurasTab_Variables.FilterDestGUID[ CurrentFight.dies[i][1] ] then
					j = j + 1
					CreateRedDeathLine(j)
					local time_ = timestampToFightTime( CurrentFight.dies[i][3] )
					local pos = AurasTab_Variables.NameWidth + time_/fightDuration*AurasTab_Variables.WorkWidth - 1
					aurasTab.redDeathLine[j]:SetPoint("TOPLEFT",pos,-42-25)
					aurasTab.redDeathLine[j]:Show()
				end
			end
		end

		aurasTab.scrollBar:Range(1,max(#buffTable-AurasTab_Variables.TotalLines+1,1))
		aurasTab.db = buffTable

		if notUpdateTargetsList then
			return
		end
		local sourceTable,destTable = {},{}
		for sourceGUID,_ in pairs(sourceList) do
			sourceTable[#sourceTable+1] = {sourceGUID,GetGUID(sourceGUID),sourceGUID:find("^Player")}
		end
		for destGUID,_ in pairs(destList) do
			destTable[#destTable+1] = {destGUID,GetGUID(destGUID),destGUID:find("^Player")}
		end
		sort(sourceTable,function(a,b) if a[3]==b[3] then return a[2]<b[2] else return a[3] end end)
		sort(destTable,function(a,b) if a[3]==b[3] then return a[2]<b[2] else return a[3] end end)

		wipe(aurasTab.sourceDropDown.List)
		wipe(aurasTab.targetDropDown.List)
		aurasTab.sourceDropDown.List[1] = {text = L.BossWatcherAll,func = AurasTab_SelectDropDownSource,padding = 16}
		aurasTab.targetDropDown.List[1] = {text = L.BossWatcherAll,func = AurasTab_SelectDropDownDest,padding = 16}
		for i=1,#sourceTable do
			local isPlayer = ExRT.F.GetUnitTypeByGUID(sourceTable[i][1]) == 0
			local classColor = ""
			if isPlayer then
				classColor = "|c"..ExRT.F.classColorByGUID(sourceTable[i][1])
			end
			aurasTab.sourceDropDown.List[i+1] = {
				text = classColor..sourceTable[i][2]..GUIDtoText(" [%s]",sourceTable[i][1]),
				arg1 = sourceTable[i][1],
				func = AurasTab_SelectDropDownSource,
				checkFunc = AurasTab_CheckDropDownSource,
				checkable = true,
			}
		end
		for i=1,#destTable do
			local isPlayer = ExRT.F.GetUnitTypeByGUID(destTable[i][1]) == 0
			local classColor = ""
			if isPlayer then
				classColor = "|c"..ExRT.F.classColorByGUID(destTable[i][1])
			end
			aurasTab.targetDropDown.List[i+1] = {
				text = classColor..destTable[i][2]..GUIDtoText(" [%s]",destTable[i][1]),
				arg1 = destTable[i][1],
				func = AurasTab_SelectDropDownDest,
				checkFunc = AurasTab_CheckDropDownDest,
				checkable = true,
			}
		end

		--ExRT.F.ScheduleTimer(collectgarbage, 1, "collect")
	end

	function UpdateBuffsPage()
		local currTab = aurasTab
		if not currTab.db then
			return
		end

		local minVal = ExRT.F.Round(currTab.scrollBar:GetValue())
		local buffTable2 = currTab.db

		local linesCount = 0
		for i=1,AurasTab_Variables.TotalLines do
			for j=1,currTab.lines[i].greenCount do
				currTab.lines[i].green[j]:Hide()
			end
			currTab.lines[i].greenCount = 0
			table.wipe(currTab.lines[i].greenTooltips)
		end
		for i=minVal,#buffTable2 do
			local data = buffTable2[i]
			linesCount = linesCount + 1
			local Line = currTab.lines[linesCount]
			Line.spellIcon:SetTexture(data[3])
			Line.spellText:SetText(data[2] or "???")
			Line.spellLink = GetSpellLink(data[1])
			Line.spellName = data[2] or "Spell"
			Line.spellID = data[1]
			Line.lineData = data

			for j=1,#data[5] do
				Line.greenCount = Line.greenCount + 1
				local n = Line.greenCount

				if not Line.green[n] then
					CreateBuffGreen(linesCount,n)
				end

				Line.green[n]:SetPoint("TOPLEFT",data[5][j][1],0)
				Line.green[n]:SetSize(max(data[5][j][2]-data[5][j][1],0.1),18)
				Line.green[n]:Show()

				Line.greenTooltips[#Line.greenTooltips+1] = data[5][j]
			end

			Line:Show()
			if linesCount >= AurasTab_Variables.TotalLines then
				break
			end
		end
		for i=(linesCount+1),AurasTab_Variables.TotalLines do
			local line = currTab.lines[i]
			line:Hide()
			line.lineData = nil
		end
		currTab.scrollBar:UpdateButtons()
	end

	tab.scrollBar:SetScript("OnValueChanged",UpdateBuffsPage)
	tab:SetScript("OnMouseWheel",function (self,delta)
		if delta > 0 then
			aurasTab.scrollBar.buttonUP:Click("LeftButton")
		else
			aurasTab.scrollBar.buttonDown:Click("LeftButton")
		end
	end)

	function AurasPage_IsAuraOn(destGUID,auraSpellID,fightTime)
		local isOnNow = false
		local aurasTable = CurrentFight.auras
		for j=1,#aurasTable do
			if aurasTable[j][6] == auraSpellID and aurasTable[j][3] == destGUID then
				if aurasTable[j][8] == 1 or aurasTable[j][8] == 2 then
					isOnNow = true
				else
					isOnNow = false
				end
			end
			local thisTime = timestampToFightTime( aurasTable[j][1] )
			if thisTime > fightTime then
				return isOnNow
			end
		end
		return isOnNow
	end

	tab:SetScript("OnShow",function (self)
		if BWInterfaceFrame.nowFightIDShort ~= self.lastFightID then
			UpdateBuffPageDB()
			self.lastFightID = BWInterfaceFrame.nowFightIDShort
		end
		UpdateBuffsPage()
	end)





	---- Mobs Info & Switch
	tab = BWInterfaceFrame.tab.tabs[4]
	local mobsTab = tab

	local Enemy_GUIDnow,Enemy_LifeTime = nil

	tab.targetsList = ELib:ScrollList(tab):Point(14,-76):Size(282,513)
	tab.targetsList.GUIDs = {}

	tab.DecorationLine = ELib:DecorationLine(tab,true):Point("TOPLEFT",tab.targetsList,"TOPRIGHT",0,2):Point("RIGHT",tab,-5,0):Size(0,37)

	tab.selectedMob = ELib:Text(tab.DecorationLine:GetParent(),"",11):Size(530,12):Point("TOPLEFT",tab.DecorationLine,"TOPLEFT",5,-5):Color():Top()
	tab.infoTabs = ELib:Tabs(tab,0,
		L.BossWatcherSwitchBySpell,
		L.BossWatcherSwitchByTarget,
		L.BossWatcherDamageSwitchTabInfo
	):Size(530,465):Point(295,-111):SetTo(1)
	tab.infoTabs:SetBackdropBorderColor(0,0,0,0)
	tab.infoTabs:SetBackdropColor(0,0,0,0)

	tab.switchSpellBox = ELib:MultiEdit(tab.infoTabs.tabs[1]):Size(540,415):Point(13,-10):Hyperlinks()
	tab.switchTargetBox = ELib:MultiEdit(tab.infoTabs.tabs[2]):Size(540,415):Point(13,-10)
	tab.infoBoxText = ELib:Text(tab.infoTabs.tabs[3],L.BossWatcherDamageSwitchTabInfoNoInfo,12):Size(540,415):Point(13,-13):Top():Color()

	tab.toDamageButton = ELib:Button(tab.infoTabs,L.BossWatcherShowDamageToTarget):Size(548,20):Point("BOTTOMLEFT",tab.targetsList,"BOTTOMRIGHT",8,-2):OnClick(function (self)
		if not Enemy_GUIDnow then
			return
		end
		DamageTab_ShowDamageToTarget(Enemy_GUIDnow)
	end)
	tab.toSegmentsButton = ELib:Button(tab.infoTabs,L.BossWatcherOnlySegmentsWithEnemy):Size(548,20):Point("BOTTOM",tab.toDamageButton,"TOP",0,5):OnClick(function (self)
		if not Enemy_LifeTime then
			return
		end
		UpdateSegmentsTime(unpack(Enemy_LifeTime))
	end)

	function tab.targetsList:SetListValue(index)
		local destGUID = self.GUIDs[index]

		Enemy_GUIDnow = destGUID
		Enemy_LifeTime = {timestampToFightTime( CurrentFight.damage_seen[destGUID] )+CurrentFight.encounterStart,CurrentFight.encounterEnd or GetTime()}
		mobsTab.toSegmentsButton:SetEnabled(true)
		mobsTab.toDamageButton:SetEnabled(true)

		wipe(reportData[4][1])
		wipe(reportData[4][2])
		wipe(reportData[4][3])

		local _time = timestampToFightTime(CurrentFight.damage_seen[destGUID])
		local fight_dur = GetFightLength(true)

		mobsTab.selectedMob:SetText(GetGUID(destGUID).." "..date("%M:%S", _time )..GUIDtoText(" (%s)",destGUID))

		_time = _time / fight_dur

		local textResult = ""
		local textResult2 = ""
		if CurrentFight.switch[destGUID] then
			local switchTable = {}

			if CurrentFight.switch[destGUID][1] then
				for sourceGUID,sourceData in pairs(CurrentFight.switch[destGUID][1]) do
					if ExRT.F.GetUnitTypeByGUID(sourceGUID) == 0 and not ExRT.F.table_find(switchTable,sourceGUID,3) then
						table.insert(switchTable,{GetGUID(sourceGUID),timestampToFightTime(sourceData[1]),sourceGUID,sourceData[2],sourceData[3]})
					end
				end
			end
			table.sort(switchTable,function(a,b) return a[2] < b[2] end)
			if #switchTable > 0 then
				textResult = L.BossWatcherReportCast.." [" .. date("%M:%S", switchTable[1][2] ) .."]:|n"
				reportData[4][1][1] = GetGUID(destGUID).." > ".. L.BossWatcherReportCast.." [" .. date("%M:%S", switchTable[1][2] ) .."]:"
				for i=1,#switchTable do
					local spellName = GetSpellInfo(switchTable[i][4] or 0)
					textResult = textResult ..i..". ".."|c".. ExRT.F.classColorByGUID(switchTable[i][3]).. switchTable[i][1] .. GUIDtoText(" <%s>",switchTable[i][3]) .. "|r (".. format("%.3f",switchTable[i][2]-switchTable[1][2])..", |Hspell:"..(switchTable[i][4] or 0).."|h"..(spellName or "?").."|h, "..((switchTable[i][5] == 1 and DAMAGE:lower()) or (switchTable[i][5] == 2 and ACTION_SPELL_CAST_SUCCESS:lower()) or (switchTable[i][5] == 3 and ACTION_SPELL_CAST_START:lower()) or "unk")..")"
					reportData[4][1][#reportData[4][1]+1] = i..". "..switchTable[i][1] .. "(" .. format("%.3f",switchTable[i][2]-switchTable[1][2])..", "..GetSpellLink(switchTable[i][4] or 0)..")"
					if i ~= #switchTable then
						textResult = textResult .. "|n"
					end
				end
				textResult = textResult .. "\n\n"
			end

			wipe(switchTable)
			if CurrentFight.switch[destGUID][2] then
				for sourceGUID,sourceData in pairs(CurrentFight.switch[destGUID][2]) do
					if ExRT.F.GetUnitTypeByGUID(sourceGUID) == 0 and not ExRT.F.table_find(switchTable,sourceGUID,3) then
						table.insert(switchTable,{GetGUID(sourceGUID),sourceData[1] - CurrentFight.encounterStart,sourceGUID,sourceData[2]})
					end
				end
			end
			table.sort(switchTable,function(a,b) return a[2] < b[2] end)
			if #switchTable > 0 then
				textResult2 = textResult2 .. L.BossWatcherReportSwitch.." [" .. date("%M:%S", switchTable[1][2] ) .."]:|n"
				reportData[4][2][1] = GetGUID(destGUID).." > ".. L.BossWatcherReportSwitch.." [" .. date("%M:%S", switchTable[1][2] ) .."]:"
				for i=1,#switchTable do
					textResult2 = textResult2 ..i..". ".. "|c".. ExRT.F.classColorByGUID(switchTable[i][3]).. switchTable[i][1] .. GUIDtoText(" <%s>",switchTable[i][3]) .. "|r (".. format("%.3f",switchTable[i][2]-switchTable[1][2])..")"
					reportData[4][2][#reportData[4][2]+1] = i..". ".. switchTable[i][1].."(" .. format("%.3f",switchTable[i][2]-switchTable[1][2])..")"
					if i ~= #switchTable then
						textResult2 = textResult2 .. "|n"
					end
				end
			end
		end
		mobsTab.switchSpellBox:SetText(textResult):ToTop()
		mobsTab.switchTargetBox:SetText(textResult2):ToTop()

		--> Other Info
		textResult = ""
		reportData[4][3][1] = GetGUID(destGUID)..":"
		for i=1,#CurrentFight.dies do
			if CurrentFight.dies[i][1]==destGUID then
				textResult = textResult .. L.BossWatcherDamageSwitchTabInfoRIP..": ".. date("%M:%S", timestampToFightTime(CurrentFight.dies[i][3]) ) .. date(" (%H:%M:%S)", CurrentFight.dies[i][3] ) .. "\n"
				reportData[4][3][#reportData[4][3]+1] = L.BossWatcherDamageSwitchTabInfoRIP..": ".. date("%M:%S", timestampToFightTime(CurrentFight.dies[i][3]) ) .. date(" (%H:%M:%S)", CurrentFight.dies[i][3] )

				local raidTarget = module.db.raidTargets[ CurrentFight.dies[i][4] or 0 ]
				if raidTarget then
					textResult = textResult .. L.BossWatcherMarkOnDeath..": "..GetTargetIconText(raidTarget).." ".. string.gsub( L["raidtargeticon"..raidTarget] , "[{}]", "" ) .."\n"
					reportData[4][3][#reportData[4][3]+1] = L.BossWatcherMarkOnDeath..": "..string.gsub( L["raidtargeticon"..raidTarget] , "[{}]", "" )
				end

				Enemy_LifeTime[2] = timestampToFightTime(CurrentFight.dies[i][3])+CurrentFight.encounterStart
			end
		end
		local mobID = ExRT.F.GUIDtoID(destGUID)
		local mobSpawnID1,mobSpawnID2,mobSpawnID3,mobSpawnID4 = 0,0,0,0
		do
			local spawnString = destGUID:match("%-([^%-]+)$") or "0"
			if spawnString then
				mobSpawnID1 = tonumber(spawnString:sub(1,5), 16) or 0
				mobSpawnID2 = tonumber(spawnString:sub(6), 16) or 0
				mobSpawnID3 = tonumber(spawnString, 16) or 0

				local copyStr = spawnString
				while copyStr:find("^0") do
					copyStr = copyStr:gsub("^0","")
				end
				mobSpawnID4 = tonumber(string.reverse(copyStr), 16) or 0
			end
		end


		textResult = textResult .. "Mob ID: ".. mobID .. "\n"

		local unitType,_,serverID,instanceID,zoneUID,id,spawnID = strsplit("-", destGUID or "")
		if id and unitType == "Creature" or unitType == "Vehicle" then
			local spawnEpoch = GetServerTime() - (GetServerTime() % 2^23)
			local spawnEpochOffset = bit.band(tonumber(string.sub(spawnID, 5), 16), 0x7fffff)
			local spawnIndex = bit.rshift(bit.band(tonumber(string.sub(spawnID, 1, 5), 16), 0xffff8), 3)
			local spawnTime = spawnEpoch + spawnEpochOffset
			
			if spawnTime > GetServerTime() then
				spawnTime = spawnTime - ((2^23) - 1)
			end
			
			textResult = textResult .. "Spawned at: ".. date("%d-%m-%Y %H:%M:%S", spawnTime) .. "\n"
			textResult = textResult .. "Spawn index: ".. spawnIndex .. "\n"
		else
			textResult = textResult .. "Spawn ID: ".. mobSpawnID1 .. "-" .. mobSpawnID2 .." ("..mobSpawnID3..", "..mobSpawnID4..")".. "\n"
		end

		textResult = textResult .. "GUID: ".. destGUID .. "\n"
		reportData[4][3][#reportData[4][3]+1] = "Mob ID: ".. mobID
		reportData[4][3][#reportData[4][3]+1] = "Spawn ID: ".. mobSpawnID1 .. "-" .. mobSpawnID2
		reportData[4][3][#reportData[4][3]+1] = "GUID: ".. destGUID

		if CurrentFight.maxHP[destGUID] then
			textResult = textResult .. "Max Health: ".. CurrentFight.maxHP[destGUID] .. "\n"
			reportData[4][3][#reportData[4][3]+1] = "Max Health: ".. CurrentFight.maxHP[destGUID]
		end

		mobsTab.infoBoxText:SetText(textResult)
	end

	function tab.targetsList:HoverListValue(isHover,index,hoveredObj)
		if not isHover then
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:Hide()
			BWInterfaceFrame.timeLineFrame.timeLine.lifeUnderLine:Hide()
			GameTooltip_Hide()
		else
			local mobGUID = self.GUIDs[index]
			local mobSeen = timestampToFightTime( CurrentFight.damage_seen[mobGUID] )
			local fight_dur = GetFightLength(true)
			local _time = mobSeen / fight_dur
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:SetPoint("TOPLEFT",BWInterfaceFrame.timeLineFrame.timeLine,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*_time,0)
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:Show()

			local dieTime = 1
			for i=1,#CurrentFight.dies do
				if CurrentFight.dies[i][1]==mobGUID then
					dieTime = timestampToFightTime(CurrentFight.dies[i][3]) / fight_dur
					break
				end
			end
			BWInterfaceFrame.timeLineFrame.timeLine.lifeUnderLine:SetPoint(_time,dieTime)

			GameTooltip:SetOwner(self,"ANCHOR_CURSOR")
			GameTooltip:AddLine(GUIDtoText("%s",mobGUID))

			if hoveredObj.text:IsTruncated() then
				GameTooltip:AddLine(GetGUID(mobGUID) .. date(" %M:%S", mobSeen) )
			end
			GameTooltip:Show()
		end
	end

	local function UpdateMobsPage()
		table.wipe(mobsTab.targetsList.L)
		table.wipe(mobsTab.targetsList.GUIDs)

		wipe(reportData[4][1])
		wipe(reportData[4][2])
		wipe(reportData[4][3])

		local mobsList = {}
		for mobGUID,mobData in pairs(CurrentFight.damage) do
			for destReaction,destReactData in pairs(mobData) do
				if (ExRT.F.GetUnitInfoByUnitFlag(destReaction,2) == 512) and not ExRT.F.table_find(mobsList,mobGUID,3) then
					mobsList[#mobsList+1] = {GetGUID(mobGUID),CurrentFight.damage_seen[mobGUID],mobGUID}
					for i=1,#CurrentFight.dies do
						if CurrentFight.dies[i][1]==mobGUID then
							local raidTarget = module.db.raidTargets[ CurrentFight.dies[i][4] or 0 ]
							if raidTarget then
								mobsList[#mobsList][1] = GetTargetIconText(raidTarget).." "..mobsList[#mobsList][1]
							end
							break
						end
					end
				end
			end
		end
		for mobGUID,mobData in pairs(CurrentFight.switch) do
			if (not CurrentFight.reaction[mobGUID] or ExRT.F.GetUnitInfoByUnitFlag(CurrentFight.reaction[mobGUID],2) == 512) and not ExRT.F.table_find(mobsList,mobGUID,3) then
				mobsList[#mobsList+1] = {GetGUID(mobGUID),mobData.seen or 0,mobGUID}
				for i=1,#CurrentFight.dies do
					if CurrentFight.dies[i][1]==mobGUID then
						local raidTarget = module.db.raidTargets[ CurrentFight.dies[i][4] or 0 ]
						if raidTarget then
							mobsList[#mobsList][1] = GetTargetIconText(raidTarget).." "..mobsList[#mobsList][1]
						end
						break
					end
				end
			end
		end
		table.sort(mobsList,function(a,b) return a[2] < b[2] end)
		for i=1,#mobsList do
			mobsTab.targetsList.L[i] =  date("%M:%S ", timestampToFightTime(mobsList[i][2]))..mobsList[i][1]
			mobsTab.targetsList.GUIDs[i] = mobsList[i][3]
		end
		mobsTab.targetsList:Update()

		Enemy_GUIDnow = nil
		mobsTab.toDamageButton:SetEnabled(false)
		mobsTab.toSegmentsButton:SetEnabled(false)
	end

	tab:SetScript("OnShow",function (self)
		BWInterfaceFrame.timeLineFrame:ClearAllPoints()
		BWInterfaceFrame.timeLineFrame:SetPoint("TOP",self,"TOP",0,-10)
		BWInterfaceFrame.timeLineFrame:Show()

		BWInterfaceFrame.report:Show()

		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			self.targetsList.selected = nil
			UpdateMobsPage()
			self.lastFightID = BWInterfaceFrame.nowFightID
		end
	end)
	tab:SetScript("OnHide",function (self)
		BWInterfaceFrame.timeLineFrame:Hide()
		BWInterfaceFrame.report:Hide()
	end)




	---- Spells
	tab = BWInterfaceFrame.tab.tabs[5]
	local tab5 = tab

	local SpellsTab_Variables = {
		Type = 1,	--1 - friendly 2 - hostile 3 - spells count, 4 - summons
		TypeP2 = 1,	--1 - friendly 2 - hostile
		Filter = {},
		FilterByTarget = {},
		TimeLineBlackList = {
			[147193] = true,	--Shadowy Apparition
			[341263] = true,	--Shadowy Apparition
			[272790] = true,	--Frenzy
			[27576] = true,		--Mutilate
			[124506] = true,	--Gift of the Ox
			[124503] = true,	--Gift of the Ox
			[336463] = true,	--Shadowcore Oil Blast
			[324748] = true,	--Celestial Guidance
			[139546] = true,	--Combo Point
			[328917] = true,	--Combat Meditation
			[328913] = true,	--Combat Meditation
			[228537] = true,	--Shattered Souls
			[324202] = true,	--Eternal Grace
			[324226] = true,	--Ascended Vigor
			[209788] = true,	--Soul Fragment
			[204255] = true,	--Soul Fragment
			[204062] = true,	--Soul Fragment
			[203795] = true,	--Soul Fragment
		},
	}
	tab.SpellsTab_Variables = SpellsTab_Variables

	tab.DecorationLine = ELib:DecorationLine(tab,true):Point("TOPLEFT",tab,"TOPLEFT",3,-8):Point("RIGHT",tab,-3,0):Size(0,20)

	tab.page = ELib:Tabs(tab,0,
		L.BossWatcherTimeLineTooltipTitle,
		L.BossWatcherTimelineText
	):Size(865,600):Point("TOP",0,-29):SetTo(1)

	tab.page:SetBackdropBorderColor(0,0,0,0)
	tab.page:SetBackdropColor(0,0,0,0)


	tab.playersList = ELib:ScrollList(tab.page.tabs[1]):Size(190,420):Point(14,-140)
	tab.playersCastsList = ELib:ScrollList(tab.page.tabs[1]):Size(637,440):Point(214,-95)
	tab.playersList.IndexToGUID = {}
	tab.playersCastsList.IndexToGUID = {}

	tab.summaryTooltip = ELib:Button(tab.page.tabs[1],STATISTICS):Point("TOP",tab.playersCastsList,"BOTTOM",0,-5):Size(637,20)
	tab.summaryTooltip:SetScript("OnEnter",function(self)
		if not self.tooltip then
			return
		end
		GameTooltip:SetOwner(self,"ANCHOR_LEFT")
		GameTooltip:SetText(self.tooltip[1])
		for i=2,#self.tooltip do
			if type(self.tooltip[i]) == "table" then
				GameTooltip:AddDoubleLine(self.tooltip[i][1],self.tooltip[i][2],1,1,1,1,1,1,1,1)
			else
				GameTooltip:AddLine(self.tooltip[i])
			end
		end
		GameTooltip:Show()
	end)
	tab.summaryTooltip:SetScript("OnLeave",ELib.Tooltip.Hide)


	local function SpellsTab_ReloadSpells()
		local selected = tab5.playersList.selected
		if selected then
			tab5.playersList:SetListValue(selected)
		end
	end

	local SpellsTab_UpdateFilterHeader = nil
	local function SpellsTab_UpdateFilter(text)
		SpellsTab_UpdateFilterHeader = nil
		wipe(SpellsTab_Variables.Filter)
		wipe(SpellsTab_Variables.FilterByTarget)
		if text:find("^target!?[=~]") or text:find("^!?[=~]") then
			text = text:gsub("^target","")
			local filterType = 1
			if text:find("^!=") then
				filterType = 3
			elseif text:find("^!~") then
				filterType = 4
			elseif text:find("^~") then
				filterType = 2
			end
			local targetsStr = text:match("^!?[=~](.+)")
			if targetsStr then
				local targets = {strsplit(";",targetsStr)}
				for i=1,#targets do
					if tonumber(targets[i]) then
						SpellsTab_Variables.FilterByTarget[ tonumber(targets[i]) ] = filterType
					else
						SpellsTab_Variables.FilterByTarget[ targets[i] ] = filterType
					end
				end
			end
			SpellsTab_ReloadSpells()
			return
		end
		local spells = {strsplit(";",text)}
		for i=1,#spells do
			if tonumber(spells[i]) then
				spells[i] = tonumber(spells[i])
			end
			SpellsTab_Variables.Filter[spells[i]] = true
		end
		SpellsTab_ReloadSpells()
	end
	tab.filterEditBox = ELib:Edit(tab.page.tabs[1]):Size(639,16):Point(213,-73):Tooltip(L.BossWatcherSpellsFilterTooltip..'|n'..L.BossWatcherBySpell..': "|cffffffff774;Multi-shot;105809|r" '..OR_CAPS:lower()..' "|cffffffffFlash Heal|r"|n'..L.BossWatcherByTarget..': "|cfffffffftarget=Ragnaros;The Lich King;Lei Shen|r" '..OR_CAPS:lower()..' "|cffffffff=Garrosh|r" '..OR_CAPS:lower()..' "|cffffffff~illi|r"'):OnChange(function (self)
		local text = self:GetText()
		if text == "" then
			ExRT.F.CancelTimer(SpellsTab_UpdateFilterHeader)
			wipe(SpellsTab_Variables.Filter)
			wipe(SpellsTab_Variables.FilterByTarget)
			SpellsTab_ReloadSpells()
			return
		end
		SpellsTab_UpdateFilterHeader = ExRT.F.ScheduleETimer(SpellsTab_UpdateFilterHeader,SpellsTab_UpdateFilter,0.8,text)
	end)

	function tab.playersList:HoverListValue(isHover,index)
		if not isHover then
			GameTooltip_Hide()
		else
			GameTooltip:SetOwner(self,"ANCHOR_CURSOR")
			GameTooltip:AddLine(GUIDtoText("%s",self.IndexToGUID[index]))
			GameTooltip:Show()
		end
	end
	function tab.playersCastsList:HoverListValue(isHover,index,hoveredObj)
		if not isHover then
			GameTooltip_Hide()
			ELib.Tooltip:HideAdd()
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:Hide()
			BWInterfaceFrame.timeLineFrame.timeLine:HideLabels()
		else
			local data = self.IndexToGUID[index]
			GameTooltip:SetOwner(hoveredObj or self,"ANCHOR_BOTTOMLEFT")
			GameTooltip:SetHyperlink(data[1])
			GameTooltip:AddLine("Spell ID: "..(data[3] or 0))
			GameTooltip:Show()

			if hoveredObj.text:IsTruncated() then
				ELib.Tooltip:Add(nil,{hoveredObj.text:GetText()},false,true)
			end

			if data[2] then
				if not data[5] then
					BWInterfaceFrame.timeLineFrame.timeLine.arrow:SetPoint("TOPLEFT",BWInterfaceFrame.timeLineFrame.timeLine,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*data[2],0)
					BWInterfaceFrame.timeLineFrame.timeLine.arrow:Show()
				else
					local count = 0
					for i=1,#data[5] do
						local pos = data[5][i]
						if pos < 0 and data[6] then
							pos = -pos
							count = count + 1
							BWInterfaceFrame.timeLineFrame.timeLine:AddLabel(count,pos,data[2] == pos and 1 or 2)
						elseif pos >= 0 then
							count = count + 1
							BWInterfaceFrame.timeLineFrame.timeLine:AddLabel(count,pos,data[2] == pos and 1 or nil)
						end
					end
				end
			end

			if self.redTime and data[4] then
				local diff = data[4] - self.redTime
				local isNegative = diff < 0 and -diff
				ELib.Tooltip:Add(nil,{format("%s%d:%06.3f (%.3f %s)",isNegative and "-" or "",(isNegative or diff) / 60,(isNegative or diff) % 60,diff,SECONDS)},false,true)
			end
		end
	end

	local function SpellsTab_FindInWord(haystack,needle)
		if not haystack or not needle then
			return
		end
		needle = needle:lower()
		haystack = haystack:lower()
		if haystack:find(needle) then
			return true
		end
		return false
	end

	function tab.playersList:SetListValue(index)
		local playersCastsList = tab5.playersCastsList

		table.wipe(playersCastsList.L)
		table.wipe(playersCastsList.IndexToGUID)

		local selfGUID = self.IndexToGUID[index]
		local fight_dur = GetFightLength(true)

		local SpellsTab_isFriendly = SpellsTab_Variables.Type == 1

		tab5.summaryTooltip.tooltip = nil
		tab5.summaryTooltip:Disable()

		if SpellsTab_Variables.Type == 4 then
			for i,data in ipairs(CurrentFight.summons) do
				if (not selfGUID or selfGUID == data[1]) and CurrentFight.segments[ data.s ].e then
					local spellName,_,spellTexture = GetSpellInfo(data[3])
					local time_ = timestampToFightTime(data[4])
					local sourceName= "|c"..ExRT.F.classColorByGUID(data[1])..GetGUID( data[1] )..GUIDtoText(" <%s>",data[1]).."|r "
					local destName= "|c"..ExRT.F.classColorByGUID(data[2])..GetGUID( data[2] )..GUIDtoText(" <%s>",data[2]).."|r "

					local sourceMarker = module.db.raidTargets[ data[5] or 0 ]
					local destMarker = module.db.raidTargets[ data[6] or 0 ]

					playersCastsList.L[#playersCastsList.L + 1] = format("[%02d:%06.3f] ",time_ / 60,time_ % 60)..(sourceMarker and GetTargetIconText(sourceMarker) or "")..sourceName.." "..ACTION_SPELL_SUMMON.." "..(destMarker and GetTargetIconText(destMarker) or "")..destName..L.BossWatcherByText..format(" %s%s",spellTexture and "|T"..spellTexture..":0|t " or "",spellName or "???")
					playersCastsList.IndexToGUID[#playersCastsList.IndexToGUID + 1] = {"spell:"..data[3],time_ / fight_dur,data[3],time_}
				end
			end
		elseif SpellsTab_Variables.Type ~= 3 then
			local spells = {}
			if selfGUID then
				for i,PlayerCastData in ipairs(CurrentFight.cast[selfGUID]) do
					if CurrentFight.segments[ PlayerCastData.s ].e then
						spells[#spells + 1] = {PlayerCastData[1],PlayerCastData[2],PlayerCastData[3],PlayerCastData[4],PlayerCastData[5],PlayerCastData[6],nil,PlayerCastData[8]}
					end
				end
			else
				local reaction = SpellsTab_isFriendly and 256 or 512
				for GUID,dataGUID in pairs(CurrentFight.cast) do
					for i,PlayerCastData in ipairs(dataGUID) do
						if ExRT.F.GetUnitInfoByUnitFlag(PlayerCastData[7],2) == reaction and CurrentFight.segments[ PlayerCastData.s ].e then
							spells[#spells + 1] = {PlayerCastData[1],PlayerCastData[2],PlayerCastData[3],PlayerCastData[4],PlayerCastData[5],PlayerCastData[6],GUID,PlayerCastData[8]}
						end
					end
				end
				sort(spells,function(a,b) return a[1]<b[1] end)
			end
			local spellToTime = {}

			local stats = {
				targets = {},
				sources = {},
			}

			local isSpellsFilterEnabled = ExRT.F.table_len(SpellsTab_Variables.Filter) > 0
			local isTargetsFilterEnabled = ExRT.F.table_len(SpellsTab_Variables.FilterByTarget) > 0
			for i,data in ipairs(spells) do
				local spellID = data[2]
				local spellName,_,spellTexture = GetSpellInfo(spellID)
				local time_ = timestampToFightTime(data[1])
				local isCast = ""
				if data[3] == 2 then
					isCast = L.BossWatcherBeginCasting.." "
				end
				local sourceName = ""
				if data[7] then
					sourceName = "|c"..ExRT.F.classColorByGUID(data[7])..GetGUID( data[7] )..GUIDtoText(" <%s>",data[7]).."|r "
				end

				local isMustBeAdded = true
				if isSpellsFilterEnabled then
					isMustBeAdded = false
					for filterSource,_ in pairs(SpellsTab_Variables.Filter) do
						if (type(filterSource) == "number" and filterSource == spellID) or
						   (type(filterSource) ~= "number" and spellName and string.find(strlower(spellName),strlower(filterSource))) then
							isMustBeAdded = true
							break
						end
					end
				elseif isTargetsFilterEnabled then
					isMustBeAdded = false
					for filterSource,filterType in pairs(SpellsTab_Variables.FilterByTarget) do
						if (filterType == 2 and SpellsTab_FindInWord( GetGUID( data[4] ),filterSource )) or 
							(filterType == 3 and not (GetGUID( data[4] ) == filterSource)) or 
							(filterType == 4 and not SpellsTab_FindInWord( GetGUID( data[4] ),filterSource )) or 
							(filterType == 1 and (GetGUID( data[4] ) == filterSource)) or
							(filterType == 1 and type(filterSource)=='number' and module.db.raidTargets[ data[5] or 0 ] == filterSource) then
							isMustBeAdded = true
							break
						end
					end
				end
				if isMustBeAdded then
					spellToTime[spellID] = spellToTime[spellID] or {}
					spellToTime[spellID][#spellToTime[spellID] + 1] = time_ / fight_dur * (data[3] == 2 and -1 or 1)

					local sourceMarker = module.db.raidTargets[ data[6] or 0 ]
					playersCastsList.L[#playersCastsList.L + 1] = format("[%02d:%06.3f] ",time_ / 60,time_ % 60)..(sourceMarker and GetTargetIconText(sourceMarker) or "")..sourceName..isCast..format("%s%s",spellTexture and "|T"..spellTexture..":0|t " or "",spellName or "???")..(data[8] and " ("..EMPOWERS..": "..data[8]..")" or "")
					playersCastsList.IndexToGUID[#playersCastsList.IndexToGUID + 1] = {"spell:"..spellID,time_ / fight_dur,spellID,time_,spellToTime[spellID],data[3] == 2}

					if data[4] and data[4] ~= "" then
						local destMarker = module.db.raidTargets[ data[5] or 0 ]
						playersCastsList.L[#playersCastsList.L] = playersCastsList.L[#playersCastsList.L] .. " > |c"..ExRT.F.classColorByGUID(data[4])..(destMarker and GetTargetIconText(destMarker) or "")..GetGUID( data[4] )..GUIDtoText(" <%s>",data[4]).."|r"

						if data[3] == 1 then
							stats.targets[ data[4] ] = (stats.targets[ data[4] ] or 0) + 1
						end
					elseif data[3] == 1 then
						stats.targets[ "-" ] = (stats.targets[ "-" ] or 0) + 1
					end
					if data[3] == 1 then
						stats.sources[spellID] = (stats.sources[spellID] or 0) + 1
					end
				end
			end

			local ss,ts = {},{}
			local cs,ct = 0,0
			for q,w in pairs(stats.sources) do ss[ #ss+1 ] = {q,w} cs=cs+w end
			for q,w in pairs(stats.targets) do if q~="-" then ts[ #ts+1 ] = {q,w} end ct=ct+w end
			sort(ss,DamageTab_Temp_SortingBy2Param)
			sort(ts,DamageTab_Temp_SortingBy2Param)
			local s = {TARGET..":"}
			for i=1,min(#ts,10) do
				s[#s+1]= { (ts[i][1] ~= "-" and GetGUID( ts[i][1] )..GUIDtoText(" <%s>",ts[i][1]) or NONE) , format("%d (%.2f%%)",ts[i][2],ts[i][2] / max(1,ct) * 100) }
			end
			if #ts > 10 then
				local o = 0
				for i=11,#ts do
					o = o + ts[i][2]
				end
				s[#s+1]= { OTHER , format("%d (%.2f%%)",o,o / max(1,ct) * 100) }
			end
			s[#s+1]= " "
			s[#s+1]= SOURCES .. ":"
			for i=1,min(#ss,10) do
				local spellName,_,spellTexture = GetSpellInfo(ss[i][1])
				s[#s+1]= { "|T" .. (spellTexture or "") .. ":0|t " ..(spellName or ss[i][1]) , format("%d (%.2f%%)",ss[i][2],ss[i][2] / max(1,cs) * 100) }
			end
			if #ss > 10 then
				local o = 0
				for i=11,#ss do
					o = o + ss[i][2]
				end
				s[#s+1]= { OTHER , format("%d (%.2f%%)",o,o / max(1,ct) * 100) }
			end
			tab5.summaryTooltip.tooltip = s
			tab5.summaryTooltip:Enable()
		else
			local spells,spellToTime = {},{}
			for GUID,dataGUID in pairs(CurrentFight.cast) do
				if not selfGUID or selfGUID == GUID then
					for i,PlayerCastData in ipairs(CurrentFight.cast[GUID]) do
						if PlayerCastData[3] ~= 2 and CurrentFight.segments[ PlayerCastData.s ].e then
							local spellID = PlayerCastData[2]
							local inTable = ExRT.F.table_find(spells,spellID,1)
							if not inTable then
								inTable = #spells + 1
								spells[inTable] = {spellID,0}
							end
							spells[inTable][2] = spells[inTable][2] + 1

							spellToTime[spellID] = spellToTime[spellID] or {}
							spellToTime[spellID][#spellToTime[spellID] + 1] = timestampToFightTime(PlayerCastData[1]) / fight_dur * (PlayerCastData[3] == 2 and -1 or 1)
						end
					end
				end
			end
			sort(spells,function(a,b)return a[2]>b[2] end)
			for i,data in ipairs(spells) do
				local spellName,_,spellTexture = GetSpellInfo(data[1])

				playersCastsList.L[#playersCastsList.L + 1] = data[2].." "..format("%s%s",spellTexture and "|T"..spellTexture..":0|t " or "",spellName or "???")
				playersCastsList.IndexToGUID[#playersCastsList.IndexToGUID + 1] = {"spell:"..data[1],0,data[1],nil,spellToTime[ data[1] ]}
			end
		end

		playersCastsList:Update()
	end
	function tab.playersCastsList:SetListValue(index,button)
		self.selected = nil
		if button == "RightButton" then
			if self.redTime or not self.IndexToGUID[index][4] then
				self.redTime = nil
				self.redIndex = nil
			else
				self.redTime = self.IndexToGUID[index][4]
				self.redIndex = index
			end
			self:Update()
			return
		end
		self.redTime = nil
		self.redIndex = nil

		local sID = self.IndexToGUID[index][3]
		if self.redSpell == sID then
			self.redSpell = nil
		else
			self.redSpell = sID
		end
		self:Update()
	end
	function tab.playersCastsList:UpdateAdditional(scrollPos)
		for j=1,#self.List do
			local index = self.List[j].index
			if self.redSpell and index and self.IndexToGUID[index] and self.IndexToGUID[index][3] == self.redSpell then
				self.List[j].text:SetTextColor(1,0.2,0.2,1)
			elseif self.redIndex and self.redIndex == index then
				self.List[j].text:SetTextColor(0.6,1,0.2,1)
			else
				self.List[j].text:SetTextColor(1,1,1,1)
			end
		end
	end

	local function UpdateSpellsPage()
		table.wipe(tab5.playersList.L)
		table.wipe(tab5.playersList.IndexToGUID)
		table.wipe(tab5.playersCastsList.L)
		table.wipe(tab5.playersCastsList.IndexToGUID)
		local playersListTable = {}
		if SpellsTab_Variables.Type ~= 4 then
			local SpellsTab_isFriendly = SpellsTab_Variables.Type == 1
			for sourceGUID,sourceData in pairs(CurrentFight.cast) do
				if not ExRT.F.table_find(playersListTable,sourceGUID,1) then
					for i=1,#sourceData do
						if 
							CurrentFight.segments[ sourceData[i].s ].e and 
							(SpellsTab_Variables.Type == 3 or (SpellsTab_isFriendly and ExRT.F.GetUnitInfoByUnitFlag(sourceData[i][7],1) == 1024) or (not SpellsTab_isFriendly and ExRT.F.GetUnitInfoByUnitFlag(sourceData[i][7],2) == 512))
						then
							playersListTable[#playersListTable + 1] = {sourceGUID,GetGUID( sourceGUID ),"|c"..ExRT.F.classColorByGUID(sourceGUID),sourceGUID:find("^Player%-")}
							break
						end
					end
				end
			end
		else
			for _,data in pairs(CurrentFight.summons) do
				local sourceGUID = data[1]
				if CurrentFight.segments[ data.s ].e and not ExRT.F.table_find(playersListTable,sourceGUID,1) then
					playersListTable[#playersListTable + 1] = {sourceGUID,GetGUID( sourceGUID ),"|c"..ExRT.F.classColorByGUID(sourceGUID)}
				end 
			end
		end
		if SpellsTab_Variables.Type == 3 then
			table.sort(playersListTable,function (a,b) if a[4] == b[4] then return a[2] < b[2] else return a[4] end end)
		else
			table.sort(playersListTable,function (a,b) return a[2] < b[2] end)
		end
		tab5.playersList.L[1] = L.BossWatcherAll
		for i,playersListTableData in ipairs(playersListTable) do
			tab5.playersList.L[i+1] = playersListTableData[3]..playersListTableData[2]
			tab5.playersList.IndexToGUID[i+1] = playersListTableData[1]
		end

		tab5.playersList.selected = 1

		tab5.playersCastsList.redTime = nil
		tab5.playersCastsList.redIndex = nil

		tab5.playersList:Update()
		tab5.playersList:SetListValue(1)
		--tab5.playersCastsList:Update()
	end

	tab.chkFriendly = ELib:Radio(tab.page.tabs[1],L.BossWatcherFriendly,true):Point(15,-75):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		tab5.chkEnemy:SetChecked(false)
		tab5.chkSpellsCount:SetChecked(false)
		tab5.chkSpellsSummons:SetChecked(false)
		SpellsTab_Variables.Type = 1
		UpdateSpellsPage()
	end)
	tab.chkEnemy = ELib:Radio(tab.page.tabs[1],L.BossWatcherHostile):Point(15,-90):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		tab5.chkFriendly:SetChecked(false)
		tab5.chkSpellsCount:SetChecked(false)
		tab5.chkSpellsSummons:SetChecked(false)
		SpellsTab_Variables.Type = 2
		UpdateSpellsPage()
	end)
	tab.chkSpellsCount = ELib:Radio(tab.page.tabs[1],L.BossWatcherSpellsCount):Point(15,-105):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		tab5.chkFriendly:SetChecked(false)
		tab5.chkEnemy:SetChecked(false)
		tab5.chkSpellsSummons:SetChecked(false)
		SpellsTab_Variables.Type = 3
		UpdateSpellsPage()
	end)
	tab.chkSpellsSummons = ELib:Radio(tab.page.tabs[1],SUMMONS):Point(15,-120):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		tab5.chkFriendly:SetChecked(false)
		tab5.chkEnemy:SetChecked(false)
		tab5.chkSpellsCount:SetChecked(false)
		SpellsTab_Variables.Type = 4
		UpdateSpellsPage()
	end)





	tab.chkFriendlyTab2 = ELib:Radio(tab.page.tabs[2],L.BossWatcherFriendly,true):Point(10,-55):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		tab5.chkEnemyTab2:SetChecked(false)
		SpellsTab_Variables.TypeP2 = 1
		tab5.timelineFrame:UpdateDB()
		tab5.timelineFrame:Update()
	end)
	tab.chkEnemyTab2 = ELib:Radio(tab.page.tabs[2],L.BossWatcherHostile):Point(10,-70):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		tab5.chkFriendlyTab2:SetChecked(false)
		SpellsTab_Variables.TypeP2 = 2
		tab5.timelineFrame:UpdateDB()
		tab5.timelineFrame:Update()
	end)

	do
		local scheduledUpdate
		tab.filterEditBox = ELib:Edit(tab.page.tabs[2]):Point("TOPLEFT",130,-46):Size(200,18):AddSearchIcon():Tooltip(FILTER.."\nplayer1,player2,55342,30451,s:innervate,s:hymn\nt:targetname\nft:targetname"):OnChange(function (self,isUser)
			if not isUser then
				return
			end
			local text = self:GetText()
			if text == "" then 
				text = nil 
			end
			SpellsTab_Variables.TLTargetFilter = nil
			if not text then
				SpellsTab_Variables.TLFilter = nil
				if scheduledUpdate then
					scheduledUpdate:Cancel()
					scheduledUpdate = nil
				end
				tab5.timelineFrame:UpdateDB()
				tab5.timelineFrame:Update()
				return
			end
			text = text:lower()
			SpellsTab_Variables.TLFilter = {strsplit(",",text)}
			for i=#SpellsTab_Variables.TLFilter,1,-1 do
				if strtrim(SpellsTab_Variables.TLFilter[i]) == "" then
					tremove(SpellsTab_Variables.TLFilter,i)
				elseif SpellsTab_Variables.TLFilter[i]:find("^[tT]:") then
					local t = strtrim(SpellsTab_Variables.TLFilter[i]:sub(3)):lower()
					if t ~= "" then
						SpellsTab_Variables.TLTargetFilter = SpellsTab_Variables.TLTargetFilter or {}
						SpellsTab_Variables.TLTargetFilter[#SpellsTab_Variables.TLTargetFilter+1] = t
					end
					tremove(SpellsTab_Variables.TLFilter,i)
				end
			end
			for i=1,#SpellsTab_Variables.TLFilter do
				SpellsTab_Variables.TLFilter[i] = tonumber(SpellsTab_Variables.TLFilter[i]) or SpellsTab_Variables.TLFilter[i]
			end
			if #SpellsTab_Variables.TLFilter == 0 then
				SpellsTab_Variables.TLFilter = nil
			end

			if not scheduledUpdate then
				scheduledUpdate = C_Timer.NewTimer(1,function()
					scheduledUpdate = nil
					tab5.timelineFrame:UpdateDB()
					tab5.timelineFrame:Update()
				end)
			end
		end)
	end

	tab.timelineFrame = ELib:ScrollFrame(tab.page.tabs[2]):Point("TOPLEFT",130,-90):Size(858-130,495-15-18):AddHorizontal(true)
	ELib:Border(tab.timelineFrame,0)
	ELib:DecorationLine(tab.page.tabs[2]):Point("BOTTOM",tab.timelineFrame,"TOP",0,0):Point("LEFT",tab.page.tabs[2]):Point("RIGHT",tab.page.tabs[2]):Size(0,1)

	tab.timelineFrame.LINE_HEIGHT = 24
	tab.timelineFrame.PIX_PER_SEC = 50

	tab.timelineFrameNames = ELib:ScrollFrame(tab.page.tabs[2]):Point("TOPLEFT",0,-90):Size(130,495-15-18)
	ELib:Border(tab.timelineFrameNames,0)
	tab.timelineFrameNames.ScrollBar:Hide()
	tab.timelineFrameNames.lines = {}
	tab.timelineFrame.ScrollNames = tab.timelineFrameNames
	tab.timelineFrameNames.mouseWheelRange = 0

	tab.timelineFrameTimes = ELib:ScrollFrame(tab.page.tabs[2]):Point("TOPLEFT",130,-70):Size(858-130,20)
	ELib:Border(tab.timelineFrameTimes,0)
	tab.timelineFrameTimes.ScrollBar:Hide()
	tab.timelineFrameTimes.texts = {}
	tab.timelineFrameTimes:Height(20)
	tab.timelineFrame.ScrollTimes = tab.timelineFrameTimes

	tab.timelineFrame.lines = {}
	for i=1,ceil(495/tab.timelineFrame.LINE_HEIGHT)+2 do
		local line = CreateFrame("Frame",nil,tab.timelineFrame.C)
		tab.timelineFrame.lines[i] = line
		line:SetPoint("TOPLEFT",0,-(i-1)*tab.timelineFrame.LINE_HEIGHT)
		line:SetPoint("RIGHT",0,0)
		line:SetHeight(tab.timelineFrame.LINE_HEIGHT)

		ELib:DecorationLine(line):Point("TOP",line,"BOTTOM",0,0):Point("LEFT",tab.timelineFrame):Point("RIGHT",tab.timelineFrame):Size(0,1)

		line.icons = {}

		line:Hide()


		local lineN = CreateFrame("Frame",nil,tab.timelineFrameNames.C)
		tab.timelineFrameNames.lines[i] = lineN
		lineN:SetPoint("TOPLEFT",0,-(i-1)*tab.timelineFrame.LINE_HEIGHT)
		lineN:SetPoint("RIGHT",0,0)
		lineN:SetHeight(tab.timelineFrame.LINE_HEIGHT)

		ELib:DecorationLine(lineN):Point("TOP",lineN,"BOTTOM",0,0):Point("LEFT",tab.timelineFrameNames):Point("RIGHT",tab.timelineFrameNames):Size(0,1)

		lineN.text = ELib:Text(lineN,"Name"):Point("LEFT",5,0):Point("RIGHT",-5,0):Color():Tooltip():MaxLines(2)

		lineN:Hide()

		line.LineName = lineN
	end

	tab.stepSlider = ELib:Slider(tab.page.tabs[2],""):Point("BOTTOMRIGHT",tab.timelineFrameTimes,"TOPRIGHT",-10,10):Size(100):Range(3,100):SetTo(50):SetObey(true):OnChange(function(self)
		local val = floor(self:GetValue() + 0.5)
		tab5.timelineFrame.PIX_PER_SEC = val
		self:Tooltip(val)
		self:tooltipReload()
		tab5.timelineFrame:UpdateDB()
		tab5.timelineFrame:Update()
	end)
	tab.stepSlider.Low:Hide()
	tab.stepSlider.High:Hide()

	local function SpellPage_TimeLine_Spell_OnEnter(self)
		local data = self.data
		local spellID = data.spellID
		local spellName,_,spellTexture = GetSpellInfo(spellID)
		GameTooltip:SetOwner(self,"ANCHOR_LEFT")
		GameTooltip:SetText("|T"..(spellTexture or 134400)..":20|t "..spellName)
		local t = data.time
		local castTime
		if data.time_end or data.failed then
			GameTooltip:AddLine(format("%d:%02d.%03d %s",t/60,t%60,t%1*1000,L.BossWatcherTimeLineCastStart))
			if data.time_end then
				castTime = data.time_end - t
				t = data.time_end
			end
			if data.interrupt then
				t = data.interrupt - data.time
				GameTooltip:AddLine(format("<%d.%03ds> %s",t,t%1*1000,L.BossWatcherInterruptText))
				local ispellName,_,ispellTexture = GetSpellInfo(data.interrupt_data[3])
				GameTooltip:AddLine(format("%s %s %s %s",
					"|c"..ExRT.F.classColorByGUID(data.interrupt_data[1])..GetGUID(data.interrupt_data[1]) .. GUIDtoText(" <%s>",data.interrupt_data[1]).."|r",
					L.BossWatcherInterruptText,L.BossWatcherByText,
					"|T"..(ispellTexture or 134400)..":16|t "..ispellName
				))
			end
		end
		if not data.failed then
			GameTooltip:AddLine(format("%d:%02d.%03d %s %s %s",t/60,t%60,t%1*1000,L.BossWatcherTimeLineCast,L.BossWatcherBuffsAndDebuffsTextOn,"|c"..ExRT.F.classColorByGUID(data.target)..GetGUID(data.target) .. GUIDtoText(" <%s>",data.target)))
			if castTime then
				GameTooltip:AddLine(format("<%d.%03ds>",castTime,castTime%1*1000))
			end
		end
		if data.prevTime then
			t = data.time - data.prevTime
			GameTooltip:AddLine(format("-%d.%03ds",t,t%1*1000))
		end
		GameTooltip:AddSpellByID(spellID)
		GameTooltip:AddLine("SpellID: "..spellID)

		GameTooltip:Show()
	end
	local function SpellPage_TimeLine_Spell_OnLeave(self)
		GameTooltip_Hide()
	end

	function tab.timelineFrame:GetIcon(line,tdata)
		local firstHidden
		for i=1,#line.icons do
			if line.icons[i].data == tdata then
				return line.icons[i], true
			elseif not firstHidden and not line.icons[i]:IsShown() then
				firstHidden = line.icons[i]
			end
		end
		if firstHidden then
			return firstHidden
		end
		local icon = CreateFrame("Frame",nil,line)
		line.icons[#line.icons+1] = icon
		icon:SetSize(22,22)
		icon.t = ELib:Texture(icon):Point("LEFT",0,0):Size(22,22)
		icon.l = ELib:Texture(icon,1,1,1,1,"BACKGROUND"):Point("LEFT",0,0):Size(22,22):Shown(false)
		icon:SetScript("OnEnter",SpellPage_TimeLine_Spell_OnEnter)
		icon:SetScript("OnLeave",SpellPage_TimeLine_Spell_OnLeave)

		return icon
	end
	function tab.timelineFrame:DBRecordSetTargetFilter(db)
		if SpellsTab_Variables.TLTargetFilter then
			local filterNotTarget
			for j=1,#SpellsTab_Variables.TLTargetFilter do
				local name = GetGUID(db.target)..GUIDtoText(" <%s>",db.target)
				if name:lower():find(SpellsTab_Variables.TLTargetFilter[j]) then
					filterNotTarget = true
					break
				end
			end
			if not filterNotTarget then
				db.filterNotTarget = true
			else
				db.filterNotTarget = false
			end
		end
	end
	function tab.timelineFrame:UpdateDB()
		local data = {}

		local SpellsTab_isFriendly = SpellsTab_Variables.TypeP2 == 1

		local interruptGUIDs = {}
		for _,data in pairs(CurrentFight.interrupts) do
			local d = interruptGUIDs[ data[2] ]
			if not d then
				d = {}
				interruptGUIDs[ data[2] ] = d
			end
			d[#d+1] = data
		end

		local reaction = SpellsTab_isFriendly and 256 or 512
		for sourceGUID,sourceData in pairs(CurrentFight.cast) do
			if ExRT.F.GetUnitInfoByUnitFlag(CurrentFight.reaction[sourceGUID],2) == reaction then
				local guidData = {
					guid = sourceGUID,
					name = GetGUID(sourceGUID) ..  GUIDtoText(" <%s>",sourceGUID),
					nameUnmod = GetGUID(sourceGUID):lower(),
					isPlayer = sourceGUID:find("^Player") and 1 or 0,
				}
				local castStarted,castStartedPrev
				local prevTime = 0
				for i=1,#sourceData do
					local cast = sourceData[i]
					local spellID = cast[2]

					local toAdd = false
					if SpellsTab_Variables.TLFilter then
						for j=1,#SpellsTab_Variables.TLFilter do
							local f = SpellsTab_Variables.TLFilter[j]
							if type(f) == "number" then
								if spellID == f then
									toAdd = true
								end
							elseif f:find("^[sS]:") then
								f = f:sub(3)
								if #f > 0 and GetSpellInfo(spellID):lower():find(f) then
									toAdd = true
								end
							elseif f:find("^[fF][tT]:") then
								local targetGUID = cast[4]
								if targetGUID then
									local tarName = GetGUID(targetGUID)..GUIDtoText(" <%s>",targetGUID)
									f = f:sub(4)
									if #f > 0 and tarName:lower():find(f) then
										toAdd = true
									end
								end
							else
								if #f > 0 and guidData.nameUnmod:find(f) then
									toAdd = true
								end
							end
						end
					else
						toAdd = true
					end
					if SpellsTab_Variables.TimeLineBlackList[spellID] then
						toAdd = false
					end

					if toAdd then
						local new

						if cast[3] == 1 and castStarted and castStarted.spellID == spellID then
							castStarted.time_end = timestampToFightTime(cast[1])
							castStarted.end_data = cast
							castStarted.target = cast[4]
							self:DBRecordSetTargetFilter(castStarted)
							prevTime = castStarted.time_end
						elseif cast[3] == 1 and castStartedPrev and castStartedPrev.spellID == spellID then
							castStartedPrev.time_end = timestampToFightTime(cast[1])
							castStartedPrev.end_data = cast
							castStartedPrev.target = cast[4]
							castStartedPrev.failed = nil
							self:DBRecordSetTargetFilter(castStartedPrev)
							prevTime = castStartedPrev.time_end
						else
							if castStarted then
								castStarted.failed = true
							end
							new = {
								time = timestampToFightTime(cast[1]),
								spellID = spellID,
								data = cast,
								prevTime = prevTime,
								target = cast[4],
							}
							self:DBRecordSetTargetFilter(new)
							guidData[#guidData+1] = new
							prevTime = new.time
						end
						if cast[3] == 2 then
							castStarted = new
							castStartedPrev = nil
						else
							castStartedPrev = castStarted
							castStarted = nil
						end
					end
				end
				if castStarted then
					castStarted.failed = true
				end

				local interrupts = interruptGUIDs[sourceGUID]
				if interrupts then
					local start = 1
					for i=1,#interrupts do
						local data = interrupts[i]
						local t = timestampToFightTime(data[5])
						local spellID = data[4]
						local prevdata
						for j=start,#guidData do
							local cdata = guidData[j]
							if cdata.time > t then
								start = j
								break
							end
							prevdata = cdata
						end
						if prevdata and prevdata.failed and (prevdata.spellID == spellID) then
							prevdata.interrupt = t
							prevdata.interrupt_data = data
						end
					end
				end
				if #guidData > 0 then
					data[#data+1] = guidData
				end
			end
		end
		self:Height(self.LINE_HEIGHT * #data + 20)
		self.ScrollNames:Height(self.LINE_HEIGHT * #data + 20)

		local fight_dur = GetFightLength(true)
		self:Width(max(900,self.PIX_PER_SEC * (fight_dur+2)))
		self.ScrollTimes.C:SetWidth(max(900,self.PIX_PER_SEC * (fight_dur+2)))

		local timeTextCount = ceil((858-130)/self.PIX_PER_SEC)+3
		local itCount = 1
		if timeTextCount < 25 then
			itCount = 1
		elseif timeTextCount < 50 then
			itCount = 2
			timeTextCount = ceil(timeTextCount/2)
		elseif timeTextCount < 75 then
			itCount = 3
			timeTextCount = ceil(timeTextCount/3)
		elseif timeTextCount < 100 then
			itCount = 5
			timeTextCount = ceil(timeTextCount/5)
		else
			itCount = 10
			timeTextCount = ceil(timeTextCount/10)
		end

		self.ScrollTimes.MAX = timeTextCount
		self.ScrollTimes.ITcount = itCount

		do
			local index = 0
			while index < timeTextCount do 
				index = index + 1
				local text = self.ScrollTimes.texts[index]
				if not text then
					text = ELib:Frame(self.ScrollTimes.C):Size(100,20)
					text.t = ELib:Text(text,"Time"):Color():Point('x'):Middle():Left()
					text.l = ELib:DecorationLine(text):Point("LEFT",text.t,"LEFT",0,0):Point("BOTTOM",self,"TOP"):Size(2,7)
				end
				text:Show()
				self.ScrollTimes.texts[index] = text
			end
			for i=index+1,#self.ScrollTimes.texts do
				self.ScrollTimes.texts[i]:Hide()
			end
		end

		sort(data,function(a,b)
			if a.isPlayer == b.isPlayer then
				return a.name < b.name
			else
				return a.isPlayer > b.isPlayer
			end
		end)

		self.data = data
	end

	local function SetSchoolColorToTexture(self,school)
		if school == -1 then
			self:Color(1,.3,.3,1)
			return
		elseif school == -2 then
			self:Color(.3,.3,1,1)
			return
		end
		local isNotGradient = ExRT.F.table_find(module.db.schoolsDefault,school) or school == 0 or module.db.schoolsColors[school or -1]
		local isConfirmedGradient = module.db.schoolsColorsGradient[ school or -1 ]
		if isNotGradient and module.db.schoolsColors[school] then
			self:Color(1,1,1,1)
			self:SetColorTexture(module.db.schoolsColors[school].r,module.db.schoolsColors[school].g,module.db.schoolsColors[school].b, 1)
		elseif isConfirmedGradient then
			local school1,school2 = isConfirmedGradient[1],isConfirmedGradient[2]
			self:SetColorTexture(1,1,1,1)
			self:SetGradient("HORIZONTAL",CreateColor(module.db.schoolsColors[school1].r,module.db.schoolsColors[school1].g,module.db.schoolsColors[school1].b,1), CreateColor(module.db.schoolsColors[school2].r,module.db.schoolsColors[school2].g,module.db.schoolsColors[school2].b,1))
		else
			local school1,school2 = nil
			for i=1,#module.db.schoolsDefault do
				local isSchool = bit.band(school,module.db.schoolsDefault[i]) > 0
				if isSchool and not school1 then
					school1 = module.db.schoolsDefault[i]
				elseif isSchool and not school2 then
					school2 = module.db.schoolsDefault[i]
				end
			end
			if school1 and school2 then
				self:SetColorTexture(1,1,1,1)
				self:SetGradient("HORIZONTAL",CreateColor(module.db.schoolsColors[school1].r,module.db.schoolsColors[school1].g,module.db.schoolsColors[school1].b,1), CreateColor(module.db.schoolsColors[school2].r,module.db.schoolsColors[school2].g,module.db.schoolsColors[school2].b,1))
			elseif school1 and not school2 then
				self:Color(1,1,1,1)
				self:SetColorTexture(module.db.schoolsColors[school1].r,module.db.schoolsColors[school1].g,module.db.schoolsColors[school1].b, 1)
			else
				self:Color(1,1,1,1)
				self:SetColorTexture(1,1,1,1)
			end
		end
	end


	function tab.timelineFrame:Update()
		local scroll = self.ScrollBar:GetValue()
		self:SetVerticalScroll(scroll % self.LINE_HEIGHT) 
		self.ScrollNames:SetVerticalScroll(scroll % self.LINE_HEIGHT) 
		local start = floor(scroll / self.LINE_HEIGHT) + 1

		local scrollH = self.ScrollBarHorizontal:GetValue()
		self:SetHorizontalScroll(scrollH % self.PIX_PER_SEC) 
		self.ScrollTimes:SetHorizontalScroll(scrollH % self.PIX_PER_SEC) 
		local startH = floor(scrollH / self.PIX_PER_SEC)

		local needRepos = (startH ~= self.prevStartH) or (start ~= self.prevStart) or (self.PIX_PER_SEC ~= self.prevPIX_PER_SEC)

		local visMaxTime = startH + (858-130) / self.PIX_PER_SEC + 1

		local DATA = self.data
		local lineCount = 1
		for i=start,#DATA do
			local data = DATA[i]
			local line = self.lines[lineCount]
			lineCount = lineCount + 1
			if not line then
				break
			end

			for j=1,#line.icons do
				line.icons[j].iter = nil
			end
			line.posnow = nil

			for j=1,#data do
				local tdata = data[j]
				if ((tdata.time >= startH) or (tdata.time_end and tdata.time_end >= startH) or (tdata.interrupt and tdata.interrupt >= startH)) and (tdata.time < visMaxTime) then
					local icon,isExist = self:GetIcon(line,tdata)
					local width = 22
					local pos = (tdata.time - startH) * self.PIX_PER_SEC
					if needRepos or not isExist then
						if line.posnow and pos < line.posnow and self.PIX_PER_SEC > 25 then
							pos = line.posnow
						end
						icon:SetPoint("LEFT",pos,0,0)
						if not isExist then
							local spellName,_,spellTexture = GetSpellInfo(tdata.spellID)
							icon.t:Texture(spellTexture or 134400)
							if tdata.failed then
								icon.t:Color(1,.3,.3,1)
							elseif tdata.filterNotTarget then
								icon.t:Color(.3,.3,1,1)
							else
								icon.t:Color(1,1,1,1)
							end
							if tdata.time_end then
								local school = module.db.spellsSchool[ tdata.spellID ] or 0
								SetSchoolColorToTexture(icon.l,school)
								if tdata.filterNotTarget then
									SetSchoolColorToTexture(icon.l,-2)
								end

								local w = (tdata.time_end - tdata.time) * self.PIX_PER_SEC
								icon.l:SetWidth(w)
								icon.l:Show()
								width = max(22,w)
								icon:SetWidth(width)
							elseif tdata.interrupt then
								SetSchoolColorToTexture(icon.l,-1)

								local w = (tdata.interrupt - tdata.time) * self.PIX_PER_SEC
								icon.l:SetWidth(w)
								icon.l:Show()
								width = max(22,w)
								icon:SetWidth(width)
							else
								icon.l:Hide()
								icon:SetWidth(22)
							end
							icon.data = tdata
						end
						icon:Show()
					end
					icon.iter = true
					line.posnow = pos + width - 6
				end
			end

			local color = "|c"..ExRT.F.classColorByGUID(data.guid)
			if data.isPlayer == 1 then
				line.LineName.text.TooltipOverwrite = color..data.name
				line.LineName.text:SetText(color..strsplit("-",data.name))
				line.LineName.text:FontSize(12)
			else
				line.LineName.text.TooltipOverwrite = nil
				line.LineName.text:SetText(color..data.name)
				line.LineName.text:FontSize(10)
			end

			for j=1,#line.icons do
				local icon = line.icons[j]
				if not icon.iter then
					icon.data = nil
					icon:Hide()
				end
			end

			line:Show()
			line.LineName:Show()
		end
		for i=lineCount,#self.lines do
			local line = self.lines[i]
			line:Hide()
			line.LineName:Hide()
		end

		if needRepos then
			local limit = self.ScrollTimes.MAX
			local itCount = self.ScrollTimes.ITcount
			local index = 0
			local t_pos = startH
			local t_fix = 0
			while (startH + t_fix) % itCount ~= 0 do
				t_fix = t_fix - 1
			end
			t_pos = t_pos + t_fix

			while index < limit do
				index = index + 1
				local text = self.ScrollTimes.texts[index]
				text.t:SetFormattedText("%d:%02d",t_pos / 60, t_pos % 60)
				text:Point("LEFT",self.ScrollTimes.C,"TOPLEFT",(t_pos - startH)*self.PIX_PER_SEC,-8)
				t_pos = t_pos + itCount
			end
		end

		self.prevStartH = startH
		self.prevStart = start
		self.prevPIX_PER_SEC = self.PIX_PER_SEC
	end
	tab.timelineFrame.ScrollBar.slider:SetScript("OnValueChanged", function(self)
		self:GetParent():GetParent():Update()
		self:UpdateButtons()
	end)
	tab.timelineFrame.ScrollBarHorizontal.slider:SetScript("OnValueChanged", function(self)
		self:GetParent():GetParent():Update()
		self:UpdateButtons()
	end)


	function SpellsPage_GetCastsNumber(guidsSourceTable,guidsDestTable,spellID)
		local allData = not spellID and {}
		local count = 0
		local spellName = GetSpellInfo(spellID)
		for GUID,dataGUID in pairs(CurrentFight.cast) do
			if not guidsSourceTable or guidsSourceTable[GUID] then
				for i,PlayerCastData in ipairs(dataGUID) do
					if allData and PlayerCastData[3] ~= 2 and CurrentFight.segments[ PlayerCastData.s ].e and (not guidsDestTable or not PlayerCastData[4] or guidsDestTable[ PlayerCastData[4] ]) then
						allData[ PlayerCastData[2] ] = (allData[ PlayerCastData[2] ] or 0) + 1
					elseif not allData and PlayerCastData[3] ~= 2 and (PlayerCastData[2] == spellID or (spellName and spellName == GetSpellInfo(PlayerCastData[2]))) and CurrentFight.segments[ PlayerCastData.s ].e then
						count = count + 1
					end
				end
			end
		end
		if allData then
			local byName = {}
			for spellID,count in pairs(allData) do
				byName[ GetSpellInfo(spellID) or "?" ] = count
			end
			for name,count in pairs(byName) do
				allData[name] = count
			end
		end
		return allData or count
	end

	tab:SetScript("OnShow",function (self)
		BWInterfaceFrame.timeLineFrame:ClearAllPoints()
		BWInterfaceFrame.timeLineFrame:SetPoint("TOP",self.page.tabs[1],"TOP",0,-10)
		BWInterfaceFrame.timeLineFrame:Show()

		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			UpdateSpellsPage()
			tab5.timelineFrame:UpdateDB()
			tab5.timelineFrame:Update()
			self.lastFightID = BWInterfaceFrame.nowFightID
		end
	end)
	tab:SetScript("OnHide",function (self)
		BWInterfaceFrame.timeLineFrame:Hide()
	end)




	---- Power; HP, Powers Graphs
	tab = BWInterfaceFrame.tab.tabs[6]
	local graphsTab = tab

	local PowerTab_isFriendly = true
	local GraphsTab_Variables = {
		DestTable = {},
		LastGUID = nil,
		LastDoEnemy = nil,
		LastDoSpell = nil,
		PowerTypeNow = 0,
		PowerLastName = nil,
		HealthTypeNow = 1,
		HealthLastName = nil,
		Cache = {},
	}


	tab.DecorationLine = ELib:DecorationLine(tab,true):Point("TOPLEFT",tab,"TOPLEFT",3,-9):Point("RIGHT",tab,-3,0):Size(0,20)

	tab.graphicsTab = ELib:Tabs(tab,0,
		POWER_GAINS,
		L.BossWatcherTabGraphics..": "..L.BossWatcherGraphicsHealth,
		L.BossWatcherTabGraphics..": "..L.BossWatcherGraphicsPower
	):Size(850,555):Point("TOP",0,-29):SetTo(1)
	tab.graphicsTab:SetBackdropBorderColor(0,0,0,0)
	tab.graphicsTab:SetBackdropColor(0,0,0,0)

	function tab.graphicsTab:buttonAdditionalFunc()
		local tab = graphsTab
		if self.selected == 1 then
			tab.graphicsTab.dropDown:Hide()
			tab.graph:Hide()
			tab.graphicsTab.powerDropDown:Hide()
			tab.graphicsTab.healthDropDown:Hide()
			tab.graphicsTab.bySpellDropDown:Hide()
			tab.graphicsTab.byTargetDropDown:Hide()
			tab.graphicsTab.stepSlider:Hide()
		else
			tab.graphicsTab.dropDown:Show()
			tab.graph:Show()
			tab.graphicsTab.stepSlider:Show()
		end
	end

	tab.graphicsTab.dropDown = ELib:DropDown(tab.graphicsTab,220,10):Size(220):Point(15,-10)
	tab.graph = ExRT.lib.CreateGraph(tab.graphicsTab,760,485,"TOP",0,-50,true)
	tab.graph.axisXisTime = true

	function tab.graphicsTab.dropDown:additionalToggle()
		local graphData = graphsTab.graph.data
		for i=1,#self.List do
			if self.List[i].checkable then
				local findPos = ExRT.F.table_find(graphData,self.List[i].arg1,'private_name')
				if findPos then
					self.List[i].checkState = not graphData[ findPos ].hide
				end
			end
		end
	end

	tab.graphicsTab.powerDropDown = ELib:DropDown(tab.graphicsTab,200,ExRT.F.table_len(module.db.energyLocale)):Size(220):Point(560,-10):SetText(L.BossWatcherSelectPower..module.db.energyLocale[0])
	tab.graphicsTab.healthDropDown = ELib:DropDown(tab.graphicsTab,200,2):Size(220):Point(560,-10):SetText(L.BossWatcherSelectPower..(HEALTH or "Health"))
	tab.graphicsTab.bySpellDropDown = ELib:DropDown(tab.graphicsTab,250,10):Size(145):Point(540,-10):SetText(L.BossWatcherTabPlayersSpells):Tooltip(L.BossWatcherGraphicsHoldShift)
	tab.graphicsTab.byTargetDropDown = ELib:DropDown(tab.graphicsTab,250,10):Size(145):Point(695,-10):SetText(L.BossWatcherGraphicsTargets)

	tab.graphicsTab.stepSlider = ELib:Slider(tab.graphicsTab,L.BossWatcherGraphicsStep):Size(250):Point(270,-15):Range(1,1):OnChange(function (self,value)
		value = ExRT.F.Round(value)
		self.tooltipText = value
		self:tooltipReload(self)
		if self.disableUpdateFix then
			return
		end
		graphsTab.graph.step = value
		graphsTab.graph:Reload()
	end)
	tab.graphicsTab.stepSlider:SetScript("OnMinMaxChanged",function (self)
		local _min,_max = self:GetMinMaxValues()
		self.Low:SetText(_min)
		self.High:SetText(_max)
	end)

	tab.graph:SetScript("OnLeave",function ()
		GameTooltip_Hide()
	end)

	tab.graphZoomDropDown = CreateFrame("Frame", BWInterfaceFrame_Name.."GraphZoomDropDown", nil, "UIDropDownMenuTemplate")
	function tab.graph:Zoom(start,ending)
		local zoomList = {
			{
				text = L.BossWatcherGraphZoom, 
				isTitle = true, 
				notCheckable = true, 
				notClickable = true 
			},
			{
				text = L.BossWatcherGraphZoomOnlyGraph,
				notCheckable = true,
				func = function()
					self.ZoomMinX = start
					self.ZoomMaxX = ending
					self:Reload()
				end,
			},
			{
				text = L.BossWatcherGraphZoomGlobal,
				notCheckable = true,
				func = function()
					self.ZoomMinX = start
					self.ZoomMaxX = ending
					self:Reload()
					UpdateSegments(start,ending,nil,true)
				end,
			},
			{
				text = L.BossWatcherSelectFightClose,
				notCheckable = true,
				func = CloseDropDownMenus_fix,
			}
		}
		if MenuUtil then
			MenuUtil.CreateContextMenu(graphsTab.graphZoomDropDown, function(ownerRegion, rootDescription)
				for i=1,#zoomList do
					local menu = zoomList[i]
					if menu.isTitle then
						rootDescription:CreateTitle(menu.text)
					else
						rootDescription:CreateButton(menu.text, menu.func)
					end
				end
			end)
		else
			EasyMenu(zoomList, graphsTab.graphZoomDropDown, "cursor", 10 , -15, "MENU")
		end
	end

	local function GraphGetFightMax()
		local i = 0
		for sec,data in pairs(CurrentFight.graphData) do
			i=max(sec,i)
		end
		return i
	end
	local function GraphHealthSelect(_,name)
		GraphsTab_Variables.HealthLastName = name

		local currTab = graphsTab

		local graphTypeName = GraphsTab_Variables.HealthTypeNow == 1 and "health" or "absorbs"

		local myGraphData = {}
		local maxFight = GraphGetFightMax()
		for sec,data in pairs(CurrentFight.graphData) do
			local health = data[name] and data[name][graphTypeName] or 0
			local maxHP = data[name] and data[name].hpmax or 0
			local maxHPtext = ""
			if maxHP > 0 then
				maxHPtext = format(" [%.1f%%]",(health or 0) / maxHP * 100)
			end
			local comment = (data[name] and data[name].name or "") .. maxHPtext
			if comment == "" then
				comment = nil
			end
			health = health or 0
			myGraphData[#myGraphData + 1] = {sec,health,format("%d:%02d",sec/60,sec%60),nil,comment}
		end
		table.sort(myGraphData,function(a,b)return a[1]<b[1] end)
		myGraphData.name = name
		if IsShiftKeyDown() and type(currTab.graph.data) == "table" and #currTab.graph.data > 0 then
			currTab.graph.data[#currTab.graph.data + 1] = myGraphData
		else
			currTab.graph.data = {myGraphData}
		end
		currTab.graph:Reload()

		currTab.graphicsTab.stepSlider:SetMinMaxValues(1,max(1,maxFight))
		currTab.graphicsTab.dropDown:SetText(name)
		ELib:DropDownClose()
	end

	function tab.graphicsTab.byTargetDropDown.additionalToggle(self)
		local tabNow = graphsTab.graphicsTab.selected
		for i=2,#self.List do
			self.List[i].checkState = GraphsTab_Variables.DestTable[self.List[i].arg1]
			if tabNow == 1 then
				self.List[i].isHidden = (self.List[i].isEnemy and GraphsTab_Variables.LastDoEnemy) or (not self.List[i].isEnemy and not GraphsTab_Variables.LastDoEnemy)
			end
		end
	end

	local function GraphTabLoad()
		ELib:DropDownClose()
		local currTab = graphsTab
		currTab.graph.data = {}
		currTab.graph:Reload()
		currTab.graphicsTab.dropDown:SetText(L.BossWatcherGraphicsSelect)
		table.wipe(currTab.graphicsTab.dropDown.List)
		currTab.graphicsTab.stepSlider:SetMinMaxValues(1,1)
		currTab.graphicsTab.stepSlider:SetValue(1)
		currTab.graphicsTab.dropDown.Lines = 10
		currTab.graphicsTab.dropDown.tooltip = L.BossWatcherGraphicsHoldShift

		currTab.graphicsTab.powerDropDown:Hide()
		currTab.graphicsTab.healthDropDown:Hide()
		currTab.graphicsTab.bySpellDropDown:Hide()
		currTab.graphicsTab.byTargetDropDown:Hide()

		GraphsTab_Variables.LastGUID = nil
		GraphsTab_Variables.LastDoEnemy = nil
		GraphsTab_Variables.LastDoSpell = nil
	end
	local GraphTab_SpecialUnits = {
		["_total"] = "*1",
		["boss1"] = "*2",
		["boss2"] = "*3",
		["boss3"] = "*4",
		["boss4"] = "*5",
		["boss5"] = "*6",
		["boss6"] = "*7",
		["target"] = "*8",
		["focus"] = "*9",
	}
	local function GraphTab_UnitDropDown_Check(self,checked)
		local graphData = graphsTab.graph.data
		local findPos = ExRT.F.table_find(graphData,self.arg1,'private_name')
		if findPos then
			graphData[ findPos ].hide = not checked
		end
		graphsTab.graph:Reload()
	end
	local function GraphTab_UnitDropDown_Click(self,arg1)
		ELib:DropDownClose()
		local graphData = graphsTab.graph.data
		for _,data in pairs(graphData) do
			data.hide = data.private_name ~= arg1
		end
		graphsTab.graph:Reload()
	end

	local function GraphTab_ReloadPage(_,newPowerID)
		local powerID = newPowerID or GraphsTab_Variables.PowerTypeNow
		GraphsTab_Variables.PowerTypeNow = powerID
		ELib:DropDownClose()
		graphsTab.graphicsTab.powerDropDown:SetText(L.BossWatcherSelectPower..module.db.energyLocale[powerID])
		wipe(graphsTab.graphicsTab.dropDown.List)

		local graphData = {}
		local maxFight = GraphGetFightMax()
		local units = GraphsTab_Variables.Cache[powerID]
		if units then
			for i=1,#units do
				local name = units[i]

				local info = {}
				graphsTab.graphicsTab.dropDown.List[i] = info
				local unitGUID = ExRT.F.table_find2(CurrentFight.raidguids,name)
				info.text = (unitGUID and "|c"..ExRT.F.classColorByGUID(unitGUID) or "")..name
				info.arg1 = name
				info.func = GraphTab_UnitDropDown_Click
				info.checkFunc = GraphTab_UnitDropDown_Check
				info.checkable = true
				--info.justifyH = "CENTER" 
				info._sort = GraphTab_SpecialUnits[ name ] or name

				local class,r,g,b = nil
				if unitGUID and unitGUID ~= "" then
					class = select(2,GetPlayerInfoByGUID(unitGUID))
				end
				if class then
					local classColorArray = type(CUSTOM_CLASS_COLORS)=="table" and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
					r,g,b = classColorArray.r,classColorArray.g,classColorArray.b
				end
				local unitGraphData = {
					name = info.text,
					private_name = name,
					hide = false,
					r = r,
					g = g,
					b = b,
				}

				if powerID == 0 then
					unitGraphData.hide = CurrentFight.other.roles[name] ~= "HEALER"
				end

				for sec,data in pairs(CurrentFight.graphData) do
					local dataPower = data[name]
					if dataPower and dataPower[powerID] then
						unitGraphData[#unitGraphData + 1] = {sec,dataPower[powerID],format("%d:%02d",sec/60,sec%60),nil,data[name].name}
					else
						unitGraphData[#unitGraphData + 1] = {sec,0,format("%d:%02d",sec/60,sec%60),nil,dataPower and dataPower.name}
					end
				end
				table.sort(unitGraphData,function(a,b)return a[1]<b[1] end)

				graphData[#graphData + 1] = unitGraphData
			end
		end
		table.sort(graphsTab.graphicsTab.dropDown.List,function(a,b)return a._sort < b._sort end) 

		graphsTab.graph.data = graphData
		graphsTab.graph:Reload()
	end
	local function GraphTab_UpdatePage()
		if not CurrentFight.graphData then
			return
		end

		local units,powers = {},{}
		for sec,data in pairs(CurrentFight.graphData) do
			for sourceName,dataPower in pairs(data) do
				for powerID,powerVal in pairs(dataPower) do
					powerID = tonumber(powerID)
					if powerID then
						powers[powerID] = true
						units[powerID] = units[powerID] or {}
						if not ExRT.F.table_find(units[powerID],sourceName) then
							units[powerID][#units[powerID]+1] = sourceName
						end
					end
				end
			end
		end

		wipe(graphsTab.graphicsTab.powerDropDown.List)
		for powerID,powerName in pairs(module.db.energyLocale) do
			if powers[powerID] then
				local info = {}
				graphsTab.graphicsTab.powerDropDown.List[ #graphsTab.graphicsTab.powerDropDown.List + 1 ] = info
				info.text = powerName
				info.arg1 = powerID
				info.func = GraphTab_ReloadPage
			end
		end
		table.sort(graphsTab.graphicsTab.powerDropDown.List,function(a,b)return a.arg1 < b.arg1 end)

		graphsTab.graphicsTab.powerDropDown.Lines = #graphsTab.graphicsTab.powerDropDown.List

		GraphsTab_Variables.Cache = units
		GraphsTab_Variables.PowerTypeNow = 0
		GraphTab_ReloadPage()
	end

	tab.graphicsTab.tabs[2]:SetScript("OnShow",function (self)
		if BWInterfaceFrame.nowFightID == self.lastFightID then
			return
		end
		self.lastFightID = BWInterfaceFrame.nowFightID
		graphsTab.graphicsTab.tabs[3].lastFightID = nil

		GraphTabLoad()
		graphsTab.graphicsTab.healthDropDown:Show()
		if not CurrentFight.graphData then
			return
		end
		local units = {}
		for i,data in pairs(CurrentFight.graphData) do
			for sourceName,_ in pairs(data) do
				if not ExRT.F.table_find(units,sourceName) then
					units[#units+1] = sourceName
				end
			end
		end
		for i=1,#units do
			local info = {}
			graphsTab.graphicsTab.dropDown.List[i] = info
			local unitGUID = ExRT.F.table_find2(CurrentFight.raidguids,units[i])
			info.text = (unitGUID and "|c"..ExRT.F.classColorByGUID(unitGUID) or "")..units[i]
			info.arg1 = units[i]
			info.func = GraphHealthSelect
			info.justifyH = "CENTER" 
			info._sort = GraphTab_SpecialUnits[ units[i] ] or units[i]
		end
		table.sort(graphsTab.graphicsTab.dropDown.List,function(a,b)return a._sort < b._sort end)
	end)
	tab.graphicsTab.tabs[3]:SetScript("OnShow",function (self)
		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			GraphTabLoad()
			graphsTab.graphicsTab.powerDropDown:Show()
			GraphTab_UpdatePage()
			self.lastFightID = BWInterfaceFrame.nowFightID
			graphsTab.graphicsTab.tabs[2].lastFightID = nil
		end
	end)

	local function GraphPowerSelectHealthType(_,arg)
		GraphsTab_Variables.HealthTypeNow = arg
		if GraphsTab_Variables.HealthLastName then
			GraphHealthSelect(nil,GraphsTab_Variables.HealthLastName)
		end
		local text
		if arg == 1 then
			text = HEALTH
		else
			text = ACTION_SPELL_MISSED_ABSORB
		end
		graphsTab.graphicsTab.healthDropDown:SetText(L.BossWatcherSelectPower..text)
		ELib:DropDownClose()
	end
	tab.graphicsTab.healthDropDown.List[1] = {text = HEALTH,arg1 = 1,func = GraphPowerSelectHealthType}
	tab.graphicsTab.healthDropDown.List[2] = {text = ACTION_SPELL_MISSED_ABSORB,arg1 = 2,func = GraphPowerSelectHealthType}


	tab.sourceList = ELib:ScrollList(tab.graphicsTab.tabs[1]):Size(190,365):Point(14,-45)
	tab.powerTypeList = ELib:ScrollList(tab.graphicsTab.tabs[1]):Size(190,136):Point("TOPLEFT",tab.sourceList,"BOTTOMLEFT",0,-8)
	tab.sourceList.IndexToGUID = {}
	tab.powerTypeList.IndexToGUID = {}

	local function EnergyLineOnEnter(self)
		if self.spellID then
			GameTooltip:SetOwner(self, "ANCHOR_LEFT")
			GameTooltip:SetHyperlink("spell:"..self.spellID)
			GameTooltip:Show()
		end
	end

	tab.spells = {}
	for i=1,20 do
		tab.spells[i] = CreateFrame("Frame",nil,tab.graphicsTab.tabs[1])
		tab.spells[i]:SetPoint("TOPLEFT",220,-10-28*(i-1))
		tab.spells[i]:SetSize(420,28)

		tab.spells[i].texture = tab.spells[i]:CreateTexture(nil,"BACKGROUND")
		tab.spells[i].texture:SetSize(24,24)
		tab.spells[i].texture:SetPoint("TOPLEFT",0,-2)

		tab.spells[i].spellName = ELib:Text(tab.spells[i],"",13):Size(225,28):Point(26,0):Color():Shadow()
		tab.spells[i].amount = ELib:Text(tab.spells[i],"",12):Size(90,28):Point(250,0):Color():Shadow()
		tab.spells[i].count = ELib:Text(tab.spells[i],"",12):Size(80,28):Point(340,0):Color():Shadow()

		tab.spells[i]:SetScript("OnEnter",EnergyLineOnEnter)
		tab.spells[i]:SetScript("OnLeave",GameTooltip_Hide)
	end

	local function EnergyClearLines()
		for i=1,#graphsTab.spells do
			graphsTab.spells[i]:Hide()
		end
	end

	function tab.sourceList:SetListValue(index)
		local tab6 = graphsTab
		table.wipe(tab6.powerTypeList.L)
		table.wipe(tab6.powerTypeList.IndexToGUID)

		local sourceGUID = tab6.sourceList.IndexToGUID[index]
		tab6.sourceGUID = sourceGUID
		local powerList = {}
		for powerType,powerData in pairs(CurrentFight.power[sourceGUID]) do
			powerList[#powerList + 1] = {powerType,module.db.energyLocale[ powerType ] or L.BossWatcherEnergyTypeUnknown..powerType}
		end
		table.sort(powerList,function (a,b) return a[1] < b[1] end)
		for i,powerData in ipairs(powerList) do
			tab6.powerTypeList.L[i] = powerData[2]
			tab6.powerTypeList.IndexToGUID[i] = powerData[1]
		end

		--EnergyClearLines()
		tab6.powerTypeList.selected = 1
		tab6.powerTypeList:Update()
		tab6.powerTypeList:SetListValue(1)
	end
	function tab.powerTypeList:SetListValue(index)
		local powerType = graphsTab.powerTypeList.IndexToGUID[index]
		local sourceGUID = graphsTab.sourceGUID

		local spellList = {
			{nil,L.BossWatcherReportTotal,"",0,0},
		}
		for spellID,spellData in pairs(CurrentFight.power[sourceGUID][powerType]) do
			local spellName,_,spellTexture = GetSpellInfo(spellID)
			spellList[#spellList + 1] = {spellID,spellName,spellTexture,spellData[1],spellData[2]}
			spellList[1][4] = spellList[1][4] + spellData[1]
			spellList[1][5] = spellList[1][5] + spellData[2]
		end
		table.sort(spellList,function (a,b) return a[4] > b[4] end)
		EnergyClearLines()
		if #spellList > 1 then
			for i,spellData in ipairs(spellList) do
				local line = graphsTab.spells[i]
				if line then
					line.texture:SetTexture(spellData[3])
					line.spellName:SetText(spellData[2])
					line.amount:SetText(spellData[4])
					line.count:SetText(spellData[5].." |4"..L.BossWatcherEnergyOnce1..":"..L.BossWatcherEnergyOnce2..":"..L.BossWatcherEnergyOnce1)
					line.spellID = spellData[1]
					line:Show()
				end
			end
		end
	end

	local function UpdatePowerPage()
		table.wipe(graphsTab.sourceList.L)
		table.wipe(graphsTab.sourceList.IndexToGUID)
		table.wipe(graphsTab.powerTypeList.L)
		table.wipe(graphsTab.powerTypeList.IndexToGUID)
		local sourceListTable = {}
		for sourceGUID,sourceData in pairs(CurrentFight.power) do
			if (PowerTab_isFriendly and ExRT.F.GetUnitInfoByUnitFlag(CurrentFight.reaction[sourceGUID],1) == 1024) or (not PowerTab_isFriendly and ExRT.F.GetUnitInfoByUnitFlag(CurrentFight.reaction[sourceGUID],2) == 512) then
				sourceListTable[#sourceListTable + 1] = {sourceGUID,GetGUID( sourceGUID ),"|c"..ExRT.F.classColorByGUID(sourceGUID)}
			end
		end
		table.sort(sourceListTable,function (a,b) return a[2] < b[2] end)
		for i,sourceData in ipairs(sourceListTable) do
			graphsTab.sourceList.L[i] = sourceData[3]..sourceData[2]
			graphsTab.sourceList.IndexToGUID[i] = sourceData[1]
		end

		graphsTab.sourceList.selected = nil
		graphsTab.powerTypeList.selected = nil

		graphsTab.sourceList:Update()
		graphsTab.powerTypeList:Update()
		EnergyClearLines()
	end

	tab.chkFriendly = ELib:Radio(tab.graphicsTab.tabs[1],L.BossWatcherFriendly,true):Point(15,-10):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		graphsTab.chkEnemy:SetChecked(false)
		PowerTab_isFriendly = true
		UpdatePowerPage()
	end)
	tab.chkEnemy = ELib:Radio(tab.graphicsTab.tabs[1],L.BossWatcherHostile):Point(15,-25):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		graphsTab.chkFriendly:SetChecked(false)
		PowerTab_isFriendly = nil
		UpdatePowerPage()
	end)

	do
		local firstLoad = nil
		tab:SetScript("OnShow",function (self)
			if BWInterfaceFrame.nowFightID ~= self.lastFightID then
				if not firstLoad then
					firstLoad = true
					graphsTab.graphicsTab:buttonAdditionalFunc()
				end
				GraphsTab_Variables.PowerLastName = nil
				GraphsTab_Variables.HealthLastName = nil
				self.lastFightID = BWInterfaceFrame.nowFightID
				UpdatePowerPage()
			end
		end)
	end


	---- Interrupt & dispels
	tab = BWInterfaceFrame.tab.tabs[7]
	local interruptTab = tab

	tab.DecorationLine = ELib:DecorationLine(tab,true):Point("TOPLEFT",tab,"TOPLEFT",3,-80):Point("RIGHT",tab,-3,0):Size(0,20)

	do
		local broke = ACTION_SPELL_AURA_BROKEN
		broke = (ExRT.F.utf8sub(broke,1,1):upper())..ExRT.F.utf8sub(broke,2,-1)
		tab.tabs = ELib:Tabs(tab,0,
			L.BossWatcherInterrupts,
			L.BossWatcherDispels,
			broke
		):Size(845,485):Point("TOP",0,-100)
	end
	tab.tabs.tabs[3].button.tooltip = L.BossWatcherBrokeTooltip
	tab.tabs:SetBackdropBorderColor(0,0,0,0)
	tab.tabs:SetBackdropColor(0,0,0,0)

	local Intterupt_Type = 1
	local UpdateInterruptPage = nil

	function tab.tabs:buttonAdditionalFunc()
		UpdateInterruptPage()
	end

	tab.bySource = ELib:Radio(tab.tabs,L.BossWatcherBySource,true):Point(10,-3):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		interruptTab.byTarget:SetChecked(false)
		interruptTab.bySpell:SetChecked(false)
		Intterupt_Type = 1
		UpdateInterruptPage()
	end)
	tab.byTarget = ELib:Radio(tab.tabs,L.BossWatcherByTarget):Point(10,-18):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		interruptTab.bySource:SetChecked(false)
		interruptTab.bySpell:SetChecked(false)
		Intterupt_Type = 2
		UpdateInterruptPage()
	end)
	tab.bySpell = ELib:Radio(tab.tabs,L.BossWatcherBySpell):Point(10,-33):AddButton():OnClick(function(self) 
		self:SetChecked(true)
		interruptTab.byTarget:SetChecked(false)
		interruptTab.bySource:SetChecked(false)
		Intterupt_Type = 3
		UpdateInterruptPage()
	end)

	tab.list = ELib:ScrollList(tab):Size(190,434):Point(14,-155)
	tab.list.GUIDs = {}

	tab.events = ELib:ScrollList(tab):Size(637,481):Point(214,-108)
	tab.events.DATA = {}

	function tab.list:SetListValue(index)
		local currTab = interruptTab
		local filter = currTab.list.GUIDs[index]
		local isInterrupt = currTab.tabs.selected == 1
		local isDispel = currTab.tabs.selected == 2
		local isBroke = currTab.tabs.selected == 3
		local workTable = CurrentFight.interrupts
		if isBroke then
			workTable = CurrentFight.aurabroken
		elseif not isInterrupt then
			workTable = CurrentFight.dispels
		end
		table.wipe(currTab.events.L)
		table.wipe(currTab.events.DATA)
		if index == 2 then
			local data = {}
			for i,line in ipairs(workTable) do
				local toAdd = nil
				if Intterupt_Type == 1 then
					toAdd = line[1]
				elseif Intterupt_Type == 2 then
					toAdd = line[2]
				elseif Intterupt_Type == 3 then
					toAdd = line[4]
				end
				if toAdd and CurrentFight.segments[ line.s ].e then
					local pos = ExRT.F.table_find(data,toAdd,1)
					if pos then
						data[pos][2] = data[pos][2] + 1
					else
						data[#data + 1] = {toAdd,1,line}
					end
				end
			end
			sort(data,function(a,b) return a[2]>b[2] end)
			for i=1,#data do
				local name = data[i][1]
				if Intterupt_Type == 3 then
					local spellName,_,spellTexture = GetSpellInfo(name)
					name = "|T"..spellTexture..":0|t ".. spellName
				else
					name = "|c".. ExRT.F.classColorByGUID(name) .. GetGUID(name) .. GUIDtoText(" (%s)",name).."|r"
				end
				currTab.events.L[#currTab.events.L + 1] = name .. ": " ..data[i][2]
				currTab.events.DATA[#currTab.events.L] = data[i][3]
			end
		else
			local SpellCanBeKicked = {}
			local SpellDispel = {}
			local resultData = {}
			for i,line in ipairs(workTable) do
				local isOkay = false
				if (Intterupt_Type == 1 and (not filter or line[1] == filter)) or
				   (Intterupt_Type == 2 and (not filter or line[2] == filter)) or
				   (Intterupt_Type == 3 and (not filter or line[4] == filter)) then
					isOkay = true
				end
				if isOkay then
					if isInterrupt and not line[2]:find("^Player%-") then
						SpellCanBeKicked[ line[4] ] = true
					elseif isDispel then
						SpellDispel[ line[3] ] = true
					end
					if CurrentFight.segments[ line.s ].e then
						local spellSourceName,_,spellSourceTexture = GetSpellInfo(line[3])
						local spellDestName,_,spellDestTexture = GetSpellInfo(line[4])
						local dispelOrInterrupt = L.BossWatcherDispelText
						local brokeType = nil
						if isInterrupt then
							dispelOrInterrupt = L.BossWatcherInterruptText
						elseif isBroke then
							dispelOrInterrupt = ACTION_SPELL_AURA_BROKEN
							brokeType = line[6] and " ("..line[6]:lower()..")"
							spellSourceName,spellSourceTexture,spellDestName,spellDestTexture = spellDestName,spellDestTexture,spellSourceName,spellSourceTexture
						end
						local sourceMarker = module.db.raidTargets[ isBroke and line[7] or line[6] or 0 ]
						local destMarker = module.db.raidTargets[ isBroke and line[8] or line[7] or 0 ]

						resultData[#resultData+1] = {
							"[".. date("%M:%S", timestampToFightTime(line[5])) .. format(".%03d",timestampToFightTime(line[5]) * 1000 % 1000).."] |c".. ExRT.F.classColorByGUID(line[1]) ..(sourceMarker and GetTargetIconText(sourceMarker) or "") .. GetGUID(line[1]) .. GUIDtoText(" (%s)",line[1]) .. "|r "..dispelOrInterrupt.." |c" ..  ExRT.F.classColorByGUID(line[2])..(destMarker and GetTargetIconText(destMarker) or "").. GetGUID(line[2]) .. "'s" .. GUIDtoText(" (%s)",line[2]) .. "|r |Hspell:" .. (line[4] or 0) .. "|h" .. format("%s%s",spellDestTexture and "|T"..spellDestTexture..":0|t " or "",spellDestName or "???") .. "|h"..(brokeType or "").." "..L.BossWatcherByText.." |Hspell:" .. (line[3] or 0) .. "|h" .. format("%s%s",spellSourceTexture and "|T"..spellSourceTexture..":0|t " or "",spellSourceName or "???") .. "|h",
							line,
							line[5],
							i,
						}
					end
				end
			end
			if isInterrupt and not filter then
				local subCount = 0
				for GUID,dataGUID in pairs(CurrentFight.cast) do
					for i,PlayerCastData in ipairs(dataGUID) do
						if CurrentFight.segments[ PlayerCastData.s ].e and SpellCanBeKicked[ PlayerCastData[2] ] and PlayerCastData[3] == 1 then
							local spellSourceName,_,spellSourceTexture = GetSpellInfo(PlayerCastData[2])
							local sourceMarker = module.db.raidTargets[ PlayerCastData[6] or 0 ]
							local destMarker = module.db.raidTargets[ PlayerCastData[5] or 0 ]
							subCount = subCount +1
							resultData[#resultData+1] = {
								"|cffff9999[".. date("%M:%S", timestampToFightTime(PlayerCastData[1])).. format(".%03d",timestampToFightTime(PlayerCastData[1]) * 1000 % 1000).."] |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:128:144:64:80|t |c".. ExRT.F.classColorByGUID(GUID) ..(sourceMarker and GetTargetIconText(sourceMarker) or "") .. GetGUID(GUID) .. GUIDtoText(" (%s)",GUID) .. "|r "..L.BossWatcherTimeLineCast.." |Hspell:" .. (PlayerCastData[3] or 0) .. "|h" .. format("%s%s",spellSourceTexture and "|T"..spellSourceTexture..":0|t " or "",spellSourceName or "???") .. "|h"..(PlayerCastData[4] and PlayerCastData[4] ~= "" and (" > |c".. ExRT.F.classColorByGUID(PlayerCastData[4]) ..(destMarker and GetTargetIconText(destMarker) or "") .. GetGUID(PlayerCastData[4]) .. GUIDtoText(" (%s)",PlayerCastData[4]) .. "|r") or ""),
								{nil,nil,nil,PlayerCastData[2],PlayerCastData[1]},
								PlayerCastData[1],
								subCount,
							}
						end
					end
				end
			end
			if isDispel and not filter then
				local subCount = 0
				for GUID,dataGUID in pairs(CurrentFight.cast) do
					for i,PlayerCastData in ipairs(dataGUID) do
						if CurrentFight.segments[ PlayerCastData.s ].e and SpellDispel[ PlayerCastData[2] ] and PlayerCastData[3] == 1 then
							local spellSourceName,_,spellSourceTexture = GetSpellInfo(PlayerCastData[2])
							local sourceMarker = module.db.raidTargets[ PlayerCastData[6] or 0 ]
							local destMarker = module.db.raidTargets[ PlayerCastData[5] or 0 ]
							local findEm = nil
							for j=1,#resultData do
								if GUID == resultData[j][2][1] and abs(resultData[j][3] - PlayerCastData[1]) < 0.5 then
									findEm = true
									break
								elseif (resultData[j][3] - PlayerCastData[1]) > 2 then
									break
								end
							end
							if not findEm then
								subCount = subCount + 1
								resultData[#resultData+1] = {
									"|cffff9999[".. date("%M:%S", timestampToFightTime(PlayerCastData[1])).. format(".%03d",timestampToFightTime(PlayerCastData[1]) * 1000 % 1000).."] |TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:128:144:64:80|t |c".. ExRT.F.classColorByGUID(GUID) ..(sourceMarker and GetTargetIconText(sourceMarker) or "") .. GetGUID(GUID) .. GUIDtoText(" (%s)",GUID) .. "|r "..L.BossWatcherTimeLineCast.." |Hspell:" .. (PlayerCastData[3] or 0) .. "|h" .. format("%s%s",spellSourceTexture and "|T"..spellSourceTexture..":0|t " or "",spellSourceName or "???") .. "|h" ..(PlayerCastData[4] and PlayerCastData[4] ~= "" and (" > |c".. ExRT.F.classColorByGUID(PlayerCastData[4]) ..(destMarker and GetTargetIconText(destMarker) or "") .. GetGUID(PlayerCastData[4]) .. GUIDtoText(" (%s)",PlayerCastData[4]) .. "|r") or ""),
									{nil,nil,nil,PlayerCastData[2],PlayerCastData[1]},
									PlayerCastData[1],
									subCount,
								}
							end
						end
					end
				end
			end
			sort(resultData,function(a,b)if a[3]==b[3] then return a[4]<b[4] else return a[3]<b[3] end end)
			for i=1,#resultData do
				currTab.events.L[#currTab.events.L + 1] = resultData[i][1]
				currTab.events.DATA[#currTab.events.L] = resultData[i][2]
			end
		end
		currTab.events:Update()
	end
	function tab.events:SetListValue(index)
		self.selected = nil
		self:Update()
	end
	function tab.events:HoverListValue(isHover,index,hoveredObj)
		if not isHover then
			GameTooltip_Hide()
			ELib.Tooltip:HideAdd()
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:Hide()
		else
			local this = hoveredObj
			local line = interruptTab.events.DATA[index]

			GameTooltip:SetOwner(this or self,"ANCHOR_BOTTOMLEFT")
			GameTooltip:SetHyperlink("spell:"..line[4])
			GameTooltip:Show()

			if line[3] then
				ELib.Tooltip:Add("spell:"..line[3])
			end

			if this.text:IsTruncated() then
				ELib.Tooltip:Add(nil,{this.text:GetText()},false,true)
			end

			local _time = timestampToFightTime(line[5]) / GetFightLength(true)

			BWInterfaceFrame.timeLineFrame.timeLine.arrow:SetPoint("TOPLEFT",BWInterfaceFrame.timeLineFrame.timeLine,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*_time,0)
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:Show()
		end
	end

	function UpdateInterruptPage()
		local currTab = interruptTab
		table.wipe(currTab.list.L)
		table.wipe(currTab.list.GUIDs)
		table.wipe(currTab.events.L)

		local workTable = CurrentFight.interrupts
		if currTab.tabs.selected == 2 then
			workTable = CurrentFight.dispels
		elseif currTab.tabs.selected == 3 then
			workTable = CurrentFight.aurabroken
		end
		local data = {}
		for i,line in ipairs(workTable) do
			if Intterupt_Type == 1 then
				if not ExRT.F.table_find(data,line[1]) and CurrentFight.segments[ line.s ].e then
					data[#data + 1] = line[1]
				end
			elseif Intterupt_Type == 2 then
				if not ExRT.F.table_find(data,line[2]) and CurrentFight.segments[ line.s ].e then
					data[#data + 1] = line[2]
				end
			else
				if not ExRT.F.table_find(data,line[4]) and CurrentFight.segments[ line.s ].e then
					data[#data + 1] = line[4]
				end
			end
		end
		local data2 = {}
		for i=1,#data do
			if Intterupt_Type ~= 3 then
				data2[i] = {data[i],GetGUID(data[i]),"|c"..ExRT.F.classColorByGUID(data[i])}
			else
				local spellName = GetSpellInfo(data[i])
				data2[i] = {data[i],spellName}
			end
		end
		sort(data2,function(a,b)return a[2]<b[2] end)
		for i=1,#data2 do
			currTab.list.L[i+2] = (data2[i][3] or "")..data2[i][2]
			currTab.list.GUIDs[i+2] = data2[i][1]
		end
		currTab.list.L[1] = L.BossWatcherAll
		currTab.list.L[2] = L.BossWatcherSpellsCount

		currTab.list.selected = 1

		currTab.list:Update()
		currTab.list:SetListValue(1)
		--currTab.events:Update()
	end

	tab:SetScript("OnShow",function (self)
		BWInterfaceFrame.timeLineFrame:ClearAllPoints()
		BWInterfaceFrame.timeLineFrame:SetPoint("TOP",self,"TOP",0,-10)
		BWInterfaceFrame.timeLineFrame:Show()
		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			UpdateInterruptPage()
			self.lastFightID = BWInterfaceFrame.nowFightID
		end
	end)
	tab:SetScript("OnHide",function (self)
		BWInterfaceFrame.timeLineFrame:Hide()
	end)




	---- Heal
	tab = BWInterfaceFrame.tab.tabs[2]

	local HsourceVar,HdestVar = {},{}
	local HealingTab_SetLine = nil
	local HealingTab_Variables = {
		Last_Func = nil,
		Last_doEnemy = nil,
		Last_doReduction = nil,
		ShowOverheal = false,
		Back_Func = nil,
		Back_destVar = nil,
		Back_sourceVar = nil,
		NULLSpellAmount = {
			amount = 0,
			over = 0,
			absorbed = 0,
			count = 0,
			crit = 0,
			critcount = 0,
			critmax = 0,
			critover = 0,
			hitmax = 0,
			absorbs = 0,
		},

		state_friendly = true,
		state_spells = false,
		state_mitigation = false,
		state_byTarget = false,
	}
	local HealingTab_UpdatePage

	local function HealingTab_UpdateDropDown(arr,dropDown)
		local count = ExRT.F.table_len(arr)
		if count == 0 then
			dropDown:SetText(L.BossWatcherAll)
		elseif count == 1 then
			local GUID = nil
			for g,_ in pairs(arr) do
				GUID = g
			end
			local name = GetGUID(GUID)
			local flags = CurrentFight.reaction[GUID]
			local isPlayer = ExRT.F.GetUnitInfoByUnitFlag(flags,1) == 1024
			local isNPC = ExRT.F.GetUnitInfoByUnitFlag(flags,2) == 512
			if isPlayer then
				name = "|c"..ExRT.F.classColorByGUID(GUID)..name
			elseif isNPC then
				name = name .. GUIDtoText(" [%s]",GUID)
			end
			dropDown:SetText(name)
		else
			dropDown:SetText(L.BossWatcherSeveral)
		end
	end

	local function HealingTab_UpdateDropDowns()
		HealingTab_UpdateDropDown(HsourceVar,BWInterfaceFrame.tab.tabs[2].sourceDropDown)
		HealingTab_UpdateDropDown(HdestVar,BWInterfaceFrame.tab.tabs[2].targetDropDown)
	end
	local function HealingTab_UpdateChecks()
		local tab = BWInterfaceFrame.tab.tabs[2]
		for _,c in pairs({tab.chkFriendly,tab.chkEnemy,tab.chkMitigation,tab.bySource,tab.byTarget,tab.bySpell}) do
			c:SetChecked(false)
		end
		if HealingTab_Variables.state_mitigation then
			tab.chkMitigation:SetChecked(true)
		elseif HealingTab_Variables.state_friendly then
			tab.chkFriendly:SetChecked(true)
		else
			tab.chkEnemy:SetChecked(true)
		end
		if HealingTab_Variables.state_spells then
			tab.bySpell:SetChecked(true)
		end
		if HealingTab_Variables.state_byTarget then
			tab.byTarget:SetChecked(true)
		elseif not HealingTab_Variables.state_spells then
			tab.bySource:SetChecked(true)
		end
	end

	local function HealingTab_ReloadGraph(data,fightLength,linesData,isSpell)
		local graphData = {}
		for key,spellData in pairs(data) do
			local newData
			if isSpell then
				local spellID = key
				local isPet = 1
				if (not ExRT.isClassic or ExRT.isCata) and spellID < -1 then
					isPet = -1
					spellID = -spellID
				end
				local spellName,_,spellIcon = GetSpellInfo(spellID)
				if spellID == -1 then
					spellName = L.BossWatcherReportTotal
				elseif spellName then
					spellName = "|T"..spellIcon..":0|t "..spellName
				else
					spellName = spellID
				end
				newData = {
					info_spellID = type(spellID)=='number' and spellID*isPet or spellID,
					name = spellName,
					total_healing = 0,
					hide = true,
				}
			else
				local sourceGUID = key
				local name,r,g,b = nil
				if sourceGUID == -1 then
					name = L.BossWatcherReportTotal
				else
					local class
					name = GetGUID(sourceGUID)
					if sourceGUID and sourceGUID ~= "" then
						class = select(2,GetPlayerInfoByGUID(sourceGUID))
					end
					name = "|c".. ExRT.F.classColor(class) .. name .. "|r"
					if class then
						local classColorArray = type(CUSTOM_CLASS_COLORS)=="table" and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
						r,g,b = classColorArray.r,classColorArray.g,classColorArray.b
					end
				end
				newData = {
					info_spellID = sourceGUID,
					name = name,
					total_healing = 0,
					hide = true,
					r = r,
					g = g,
					b = b,
				}
			end
			graphData[#graphData+1] = newData
			local totalHealing = 0
			for i=1,fightLength do
				newData[i] = {i,spellData[i] or 0}
				totalHealing = totalHealing + (spellData[i] or 0)
			end
			newData.total_healing = totalHealing
		end
		sort(graphData,function(a,b) return a.total_healing>b.total_healing end)
		local findPos = ExRT.F.table_find(graphData,-1,'info_spellID')
		if findPos then
			graphData[ findPos ].hide = nil
			graphData[ findPos ].specialLine = true
		end
		for i=1,3 do
			if linesData[i] then
				findPos = ExRT.F.table_find(graphData,linesData[i][isSpell and "spell" or "guid"],'info_spellID')
				if findPos then
					graphData[ findPos ].hide = nil
				end
			end
		end
		BWInterfaceFrame.GraphFrame.G.data = graphData
		BWInterfaceFrame.GraphFrame.G:Reload()
	end

	local function HealingTab_UpdateLines_GetUnit(heal,graph,source,dest,header,secondHeader)
		header = header or "guid"
		local sourceHeal

		for i=1,#heal do
			if heal[i][header] == source and (not secondHeader or heal[i].info == secondHeader) then
				sourceHeal = i
				break
			end
		end

		if not sourceHeal then
			sourceHeal = #heal + 1
			heal[sourceHeal] = {
				[header] = source,
				info = secondHeader,
				eff = 0,
				total = 0,
				count = 0,
				overheal = 0,
				absorbed = 0,
				absorbs = 0,
				crit = 0,
				critcount = 0,
				critmax = 0,
				critover = 0,
				hitmax = 0,
				targets = {},
				from = {},
			}
		end
		sourceHeal = heal[sourceHeal]

		local destPos

		local targets = sourceHeal.targets
		for i=1,#targets do
			if targets[i][1] == dest then
				destPos = i
				break
			end
		end

		if not destPos then
			destPos = #sourceHeal.targets + 1
			sourceHeal.targets[destPos] = {dest,0}
		end

		if not graph[ source ] then
			graph[ source ] = {}
		end

		return sourceHeal, sourceHeal.targets[destPos]
	end

	local function HealingTab_UpdateLinesPlayers()
		ExRT.F.dprint("Healing Update: Players",GetTime())
		HealingTab_UpdateDropDowns()
		HealingTab_UpdateChecks()

		local doEnemy = not HealingTab_Variables.state_friendly
		local doReduction = HealingTab_Variables.state_mitigation
		local isReverse = HealingTab_Variables.state_byTarget
		local onlyReduction = doReduction

		local heal = {}
		local total = 0
		local totalOver = 0
		local graph = {[-1]={}}
		if not onlyReduction then
			for sourceGUID,sourceData in pairs(CurrentFight.heal) do
				local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
				if owner then
					sourceGUID = owner
				end
				if ExRT.F.table_len(HsourceVar) == 0 or HsourceVar[sourceGUID] then
					for destGUID,destData in pairs(sourceData) do
						for destReact,destReactData in pairs(destData) do
							local isEnemy = not ExRT.F.UnitIsFriendlyByUnitFlag2(destReact)
							if ExRT.F.table_len(HdestVar) == 0 or HdestVar[destGUID] then
								if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
									local source = isReverse and destGUID or sourceGUID
									local dest = isReverse and sourceGUID or destGUID

									local sourceHeal, destPos = HealingTab_UpdateLines_GetUnit(heal,graph,source,dest,"guid")

									for spellID,spellSegments in pairs(destReactData) do
										for segment,spellAmount in pairs(spellSegments) do
											if CurrentFight.segments[segment].e then
												if spellID == 98021 then	--Spirit Link
													spellAmount = HealingTab_Variables.NULLSpellAmount
												end
												sourceHeal.eff = sourceHeal.eff + spellAmount.amount - spellAmount.over + spellAmount.absorbed
												sourceHeal.total = sourceHeal.total + spellAmount.amount + spellAmount.absorbed						--total
												sourceHeal.overheal = sourceHeal.overheal + spellAmount.over 							--overheal
												sourceHeal.absorbed = sourceHeal.absorbed + spellAmount.absorbed 						--absorbed
												sourceHeal.crit = sourceHeal.crit + spellAmount.crit - (HealingTab_Variables.ShowOverheal and 0 or spellAmount.critover)
												sourceHeal.absorbs = sourceHeal.absorbs + spellAmount.absorbs						--absorbs
												total = total + spellAmount.amount - spellAmount.over + spellAmount.absorbed
												totalOver = totalOver + spellAmount.over

												destPos[2] = destPos[2] + spellAmount.amount + spellAmount.absorbed + (HealingTab_Variables.ShowOverheal and 0 or -spellAmount.over)

												if not graph[ source ][segment] then
													graph[ source ][segment] = 0
												end
												if not graph[ -1 ][segment] then
													graph[ -1 ][segment] = 0
												end
												local healCount = spellAmount.amount - (HealingTab_Variables.ShowOverheal and 0 or spellAmount.over) + spellAmount.absorbed
												graph[ source ][segment] = graph[ source ][segment] + healCount
												graph[ -1 ][segment] = graph[ -1 ][segment] + healCount
											end
										end
									end
								end
							end
						end
					end
				end
			end
		end
		if doReduction and not doEnemy then
			for destGUID,destData in pairs(CurrentFight.reduction) do
				if ExRT.F.table_len(HdestVar) == 0 or HdestVar[destGUID] then
					for sourceGUID,sourceData in pairs(destData) do
						for spellID,spellData in pairs(sourceData) do
							for reductorGUID,reductorData in pairs(spellData) do
								local owner = ExRT.F.Pets:getOwnerGUID(reductorGUID,GetPetsDB())
								if owner then
									reductorGUID = owner
								end
								if ExRT.F.table_len(HsourceVar) == 0 or HsourceVar[reductorGUID] then
									local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[reductorGUID])
									if isFriendly then
										local source = isReverse and destGUID or reductorGUID
										local dest = isReverse and reductorGUID or destGUID

										local sourceHeal, destPos = HealingTab_UpdateLines_GetUnit(heal,graph,source,dest,"guid")

										for reductionSpellID,spellSegments in pairs(reductorData) do
											for segment,reductionSpellAmount in pairs(spellSegments) do
												if CurrentFight.segments[segment].e then
													sourceHeal.eff = sourceHeal.eff + reductionSpellAmount
													sourceHeal.total = sourceHeal.total + reductionSpellAmount
													if not onlyReduction then
														sourceHeal.absorbs = sourceHeal.absorbs + reductionSpellAmount
													end

													total = total + reductionSpellAmount

													destPos[2] = destPos[2] + reductionSpellAmount


													if not graph[ source ][segment] then
														graph[ source ][segment] = 0
													end
													if not graph[ -1 ][segment] then
														graph[ -1 ][segment] = 0
													end

													graph[ source ][segment] = graph[ source ][segment] + reductionSpellAmount
													graph[ -1 ][segment] = graph[ -1 ][segment] + reductionSpellAmount
												end
											end
										end
									end
								end
							end
						end
					end
				end
			end

			if HealingTab_Variables.ShowOverheal and onlyReduction then
				local missData = {}
				local avgDamage = {}
				for destGUID,destData in pairs(CurrentFight.damage) do
					for destReaction,destReactData in pairs(destData) do
						for sourceGUID,sourceData in pairs(destReactData) do
							local avgData = avgDamage[sourceGUID]
							if not avgData then
								avgData = {}
								avgDamage[sourceGUID] = avgData
							end
							for spellID,spellSegments in pairs(sourceData) do
								local avgSpell = avgData[spellID]
								if not avgSpell then
									avgSpell = {0,0}
									avgData[spellID] = avgSpell
								end
								for segment,spellAmount in pairs(spellSegments) do
									avgSpell[1] = avgSpell[1] + spellAmount.count
									avgSpell[2] = avgSpell[2] + spellAmount.amount + spellAmount.blocked + spellAmount.absorbed

									if spellAmount.parry > 0 or spellAmount.dodge > 0 or spellAmount.miss > 0 then
										local missDestData = missData[destGUID]
										if not missDestData then
											missDestData = {}
											missData[destGUID] = missDestData
										end
										local missSpell = missDestData[sourceGUID]
										if not missSpell then
											missSpell = {}
											missDestData[sourceGUID] = missSpell
										end
										local missSpellData = missSpell[spellID]
										if not missSpellData then
											missSpellData = {
												parry = 0,
												dodge = 0,
												miss = 0,
												parry_target = 0,
												dodge_target = 0,
												miss_target = 0,
												segments = {},
											}
											missSpell[spellID] = missSpellData
										end
										missSpellData.parry = missSpellData.parry+spellAmount.parry
										missSpellData.dodge = missSpellData.dodge+spellAmount.dodge
										missSpellData.miss = missSpellData.miss+spellAmount.miss

										if CurrentFight.segments[segment].e then
											missSpellData.parry_target = missSpellData.parry_target+spellAmount.parry
											missSpellData.dodge_target = missSpellData.dodge_target+spellAmount.dodge
											missSpellData.miss_target = missSpellData.miss_target+spellAmount.miss
											missSpellData.segments[#missSpellData.segments+1] = segment
										end
									end
								end
							end
						end
					end
				end
				local reductionMissToSpell = {
					dodge = 81,
					parry = 82243,
					miss = 154592,
				}
				for destGUID,destData in pairs(missData) do
					local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[destGUID] or 0)
					if isFriendly and (ExRT.F.table_len(HsourceVar) == 0 or HsourceVar[destGUID]) then
						for sourceGUID,sourceData in pairs(destData) do
							for spellID,spellAmount in pairs(sourceData) do
								local avgData = avgDamage[ sourceGUID ][ spellID ]
								local avg = avgData[3]
								if not avg then
									if avgData[1] > 0 then
										avg = avgData[2] / avgData[1]
									else
										avg = 0
									end
									avgData[3] = avg
								end
								if avg > 0 then
									for reductionName,reductionSpellID in pairs(reductionMissToSpell) do
										if spellAmount[reductionName] > 0 then
											local sourceHeal, destPos = HealingTab_UpdateLines_GetUnit(heal,graph,destGUID,destGUID,"guid")

											local fromSpellPos = ExRT.F.table_find(sourceHeal.from,spellID,1)
											if not fromSpellPos then
												fromSpellPos = #sourceHeal.from + 1
												sourceHeal.from[fromSpellPos] = {spellID,0}
											end
											fromSpellPos = sourceHeal.from[fromSpellPos]

											local amount = avg * spellAmount[reductionName.."_target"]

											sourceHeal.eff = sourceHeal.eff + amount
											sourceHeal.total = sourceHeal.total + amount
											sourceHeal.absorbs = sourceHeal.absorbs + amount
											total = total + amount
											destPos[2] = destPos[2] + amount
											fromSpellPos[2] = fromSpellPos[2] + amount

											for i=1,#spellAmount.segments do
												local segment = spellAmount.segments[i]
												if not graph[ destGUID ] then
													graph[ destGUID ] = {}
												end
												if not graph[ destGUID ][segment] then
													graph[ destGUID ][segment] = 0
												end
												if not graph[ -1 ][segment] then
													graph[ -1 ][segment] = 0
												end
												graph[ destGUID ][segment] = graph[ destGUID ][segment] + amount
												graph[ -1 ][segment] = graph[ -1 ][segment] + amount
											end
										end
									end
								end
							end
						end
					end
				end
			end

		end
		if not isReverse and not onlyReduction then
			for _,healData in pairs(heal) do
				for sourceGUID,sourceData in pairs(CurrentFight.healFrom) do
					if healData.guid == sourceGUID or ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB()) == healData.guid then
						for destGUID,destData in pairs(sourceData) do
							local isEnemy = not ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[destGUID])
							if ExRT.F.table_len(HdestVar) == 0 or HdestVar[destGUID] then
								if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
									for spellID,spellData in pairs(destData) do
										for fromSpellID,fromSpellSegments in pairs(spellData) do
											for segment,fromSpellAmount in pairs(fromSpellSegments) do
												if CurrentFight.segments[segment].e then

													local destPos = ExRT.F.table_find(healData.from,fromSpellID,1)
													if not destPos then
														destPos = #healData.from + 1
														healData.from[destPos] = {fromSpellID,0}
													end
													destPos = healData.from[destPos]

													destPos[2] = destPos[2] + fromSpellAmount
												end
											end
										end
									end
								end
							end
						end
					end
				end
			end
		end

		local totalIsFull = 1
		total = max(total,1)
		if total == 1 and #heal == 0 then
			total = 0
			totalIsFull = 0
		end
		local _max = nil
		reportOptions[2] = L.BossWatcherReportHPS
		wipe(reportData[2])
		reportData[2][1] = (DamageTab_GetGUIDsReport(HsourceVar) or L.BossWatcherAllSources).." > "..(DamageTab_GetGUIDsReport(HdestVar) or L.BossWatcherAllTargets)
		local activeFightLength = GetFightLength()

		if HealingTab_Variables.ShowOverheal then
			total = total + totalOver
			sort(heal,function(a,b) return a.total>b.total end)
			_max = heal[1] and heal[1].total or 0
		else
			sort(heal,function(a,b) return a.eff>b.eff end)
			_max = heal[1] and heal[1].eff or 0
		end
		reportData[2][2] = L.BossWatcherReportTotal.." - "..ExRT.F.shortNumber(total).."@1@ ("..floor(total / activeFightLength)..")@1#"
		HealingTab_SetLine({
			line = 1,
			name = L.BossWatcherReportTotal,
			num = total,
			total = total,
			max = total,
			alpha = HealingTab_Variables.ShowOverheal and totalOver,
			dps = total / activeFightLength,
			spellID = -1,
			check = BWInterfaceFrame.GraphFrame:IsShown(),
			checkState = true,
		})
		for i=1,#heal do
			local healLine = heal[i]
			local class = nil
			if healLine.guid and healLine.guid ~= "" then
				class = select(2,ExRT.F:SafeCall(GetPlayerInfoByGUID,healLine.guid))
			end
			local icon = ""
			if class and CLASS_ICON_TCOORDS[class] then
				icon = {"Interface\\GLUES\\CHARACTERCREATE\\UI-CHARACTERCREATE-CLASSES",unpack(CLASS_ICON_TCOORDS[class])}
			end
			local tooltipData = {GetGUID(healLine.guid),
				{L.BossWatcherHealTooltipOver,format("%s (%.1f%%)",ExRT.F.shortNumber(healLine.overheal),healLine.overheal/max(healLine.total,1)*100)},
				{L.BossWatcherHealTooltipAbsorbed,ExRT.F.shortNumber(healLine.absorbed)},
				{L.BossWatcherHealTooltipTotal,ExRT.F.shortNumber(healLine.total)},
				{" "," "},
				{L.BossWatcherHealTooltipFromCrit,format("%s (%.1f%%)",ExRT.F.shortNumber(healLine.crit),healLine.crit/max(1,healLine.eff+(HealingTab_Variables.ShowOverheal and healLine.overheal or 0))*100)},
				{ACTION_SPELL_MISSED_ABSORB,format("%s (%.1f%%)",ExRT.F.shortNumber(healLine.absorbs),healLine.absorbs/max(healLine.eff+(HealingTab_Variables.ShowOverheal and healLine.overheal or 0),1)*100)},
			}
			sort(healLine.targets,DamageTab_Temp_SortingBy2Param)
			if #healLine.targets > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherHealTooltipTargets," "}
			end
			for j=1,min(5,#healLine.targets) do
				tooltipData[#tooltipData + 1] = {SubUTF8String(GetGUID(healLine.targets[j][1]),20)..GUIDtoText(" [%s]",healLine.targets[j][1]),format("%s (%.1f%%)",ExRT.F.shortNumber(healLine.targets[j][2]),min(healLine.targets[j][2] / max(1,healLine.eff+(HealingTab_Variables.ShowOverheal and healLine.overheal or 0))*100,100))}
			end
			sort(healLine.from,DamageTab_Temp_SortingBy2Param)
			if #healLine.from > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherFromSpells," "}
			end
			for j=1,min(5,#healLine.from) do
				local spellName,_,spellTexture = GetSpellInfo(healLine.from[j][1])
				tooltipData[#tooltipData + 1] = {(spellTexture and "|T"..spellTexture..":0|t" or "")..(spellName or "spell:"..(healLine.from[j][1] or -1)),ExRT.F.shortNumber(healLine.from[j][2])}
			end

			local currHealing = healLine.eff+(HealingTab_Variables.ShowOverheal and healLine.overheal or 0)
			local hps = currHealing/activeFightLength
			HealingTab_SetLine({
				line = i+1,
				icon = icon,
				name = GetGUID(healLine.guid)..GUIDtoText(" [%s]",healLine.guid),
				num = currHealing,
				total = total,
				max = _max,
				alpha = (HealingTab_Variables.ShowOverheal and not onlyReduction) and healLine.overheal or healLine.absorbs,
				dps = hps,
				class = class,
				sourceGUID = healLine.guid,
				tooltip = tooltipData,
				check = BWInterfaceFrame.GraphFrame:IsShown(),
				checkState = i <= 3,
			})
			reportData[2][#reportData[2]+1] = i..". "..GetGUID(healLine.guid).." - "..ExRT.F.shortNumber(currHealing).."@1@ ("..floor(hps)..")@1#"
		end
		for i=#heal+2,#BWInterfaceFrame.tab.tabs[2].lines do
			BWInterfaceFrame.tab.tabs[2].lines[i]:Hide()
		end
		BWInterfaceFrame.tab.tabs[2].scroll:Height((#heal+1) * 20)


		HealingTab_Variables.graphCache = {graph,#CurrentFight.segments,heal,false}
		if BWInterfaceFrame.GraphFrame:IsShown() then
			HealingTab_ReloadGraph(graph,#CurrentFight.segments,heal,false)
		end
	end
	local function HealingTab_UpdateLinesSpell()
		ExRT.F.dprint("Healing Update: Spells",GetTime())
		HealingTab_UpdateDropDowns()
		HealingTab_UpdateChecks()

		local doEnemy = not HealingTab_Variables.state_friendly
		local doReduction = HealingTab_Variables.state_mitigation
		local onlyReduction = doReduction

		local heal = {}
		local total = 0
		local totalOver = 0
		local graph = {[-1]={}}
		if not onlyReduction then
			for sourceGUID,sourceData in pairs(CurrentFight.heal) do
				local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
				if owner then
					sourceGUID = owner
				end
				if ExRT.F.table_len(HsourceVar) == 0 or HsourceVar[sourceGUID] then
					for destGUID,destData in pairs(sourceData) do
						for destReact,destReactData in pairs(destData) do
							local isEnemy = not ExRT.F.UnitIsFriendlyByUnitFlag2(destReact)
							if ExRT.F.table_len(HdestVar) == 0 or HdestVar[destGUID] then
								if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
									for spellID,spellSegments in pairs(destReactData) do
										local sourceHeal, destPos = HealingTab_UpdateLines_GetUnit(heal,graph,spellID,destGUID,"spell",owner and "pet")

										for segment,spellAmount in pairs(spellSegments) do
											if CurrentFight.segments[segment].e then
												if spellID == 98021 and not HealingTab_Variables.ShowOverheal then	--Spirit Link
													spellAmount = HealingTab_Variables.NULLSpellAmount
												end

												sourceHeal.eff = sourceHeal.eff + spellAmount.amount - spellAmount.over + spellAmount.absorbed	--ef
												sourceHeal.total = sourceHeal.total + spellAmount.amount + spellAmount.absorbed						--total
												sourceHeal.overheal = sourceHeal.overheal + spellAmount.over 							--overheal
												sourceHeal.absorbed = sourceHeal.absorbed + spellAmount.absorbed 						--absorbed
												sourceHeal.count = sourceHeal.count + spellAmount.count 						--count
												sourceHeal.crit = sourceHeal.crit + spellAmount.crit 							--crit
												sourceHeal.critcount = sourceHeal.critcount + spellAmount.critcount						--crit-count
												sourceHeal.critmax = max(sourceHeal.critmax,spellAmount.critmax)						--crit-max
												sourceHeal.hitmax = max(sourceHeal.hitmax,spellAmount.hitmax)						--hit-max
												sourceHeal.critover = sourceHeal.critover + spellAmount.critover						--crit overheal
												sourceHeal.absorbs = sourceHeal.absorbs + spellAmount.absorbs						--absorbs
												total = total + spellAmount.amount - spellAmount.over + spellAmount.absorbed
												totalOver = totalOver + spellAmount.over

												destPos[2] = destPos[2] + spellAmount.amount + spellAmount.absorbed + (HealingTab_Variables.ShowOverheal and 0 or -spellAmount.over)

												if not graph[ spellID ][segment] then
													graph[ spellID ][segment] = 0
												end
												if not graph[ -1 ][segment] then
													graph[ -1 ][segment] = 0
												end
												local healCount = spellAmount.amount - (HealingTab_Variables.ShowOverheal and 0 or spellAmount.over) + spellAmount.absorbed

												graph[ spellID ][segment] = graph[ spellID ][segment] + healCount
												graph[ -1 ][segment] = graph[ -1 ][segment] + healCount
											end
										end
									end
								end
							end
						end
					end
				end
			end
		end
		if doReduction and not doEnemy then
			for destGUID,destData in pairs(CurrentFight.reduction) do
				if ExRT.F.table_len(HdestVar) == 0 or HdestVar[destGUID] then
					for sourceGUID,sourceData in pairs(destData) do
						for spellID,spellData in pairs(sourceData) do
							for reductorGUID,reductorData in pairs(spellData) do
								local owner = ExRT.F.Pets:getOwnerGUID(reductorGUID,GetPetsDB())
								if ExRT.F.table_len(HsourceVar) == 0 or HsourceVar[reductorGUID] then
									local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[reductorGUID])
									if isFriendly then
										for reductionSpellID,spellSegments in pairs(reductorData) do
											local sourceHeal, destPos = HealingTab_UpdateLines_GetUnit(heal,graph,reductionSpellID,destGUID,"spell",owner and "pet")

											for segment,reductionSpellAmount in pairs(spellSegments) do
												if CurrentFight.segments[segment].e then
													sourceHeal.eff = sourceHeal.eff + reductionSpellAmount
													sourceHeal.total = sourceHeal.total + reductionSpellAmount
													if not onlyReduction then
														sourceHeal.absorbs = sourceHeal.absorbs + reductionSpellAmount
													end
													total = total + reductionSpellAmount
													destPos[2] = destPos[2] + reductionSpellAmount

													if not graph[ reductionSpellID ][segment] then
														graph[ reductionSpellID ][segment] = 0
													end
													if not graph[ -1 ][segment] then
														graph[ -1 ][segment] = 0
													end
													graph[ reductionSpellID ][segment] = graph[ reductionSpellID ][segment] + reductionSpellAmount
													graph[ -1 ][segment] = graph[ -1 ][segment] + reductionSpellAmount
												end
											end
										end
									end
								end
							end
						end
					end
				end
			end

			if HealingTab_Variables.ShowOverheal and onlyReduction then
				local missData = {}
				local avgDamage = {}
				for destGUID,destData in pairs(CurrentFight.damage) do
					for destReaction,destReactData in pairs(destData) do
						for sourceGUID,sourceData in pairs(destReactData) do
							local avgData = avgDamage[sourceGUID]
							if not avgData then
								avgData = {}
								avgDamage[sourceGUID] = avgData
							end
							for spellID,spellSegments in pairs(sourceData) do
								local avgSpell = avgData[spellID]
								if not avgSpell then
									avgSpell = {0,0}
									avgData[spellID] = avgSpell
								end
								for segment,spellAmount in pairs(spellSegments) do
									avgSpell[1] = avgSpell[1] + spellAmount.count
									avgSpell[2] = avgSpell[2] + spellAmount.amount + spellAmount.blocked + spellAmount.absorbed

									if spellAmount.parry > 0 or spellAmount.dodge > 0 or spellAmount.miss > 0 then
										local missDestData = missData[destGUID]
										if not missDestData then
											missDestData = {}
											missData[destGUID] = missDestData
										end
										local missSpell = missDestData[sourceGUID]
										if not missSpell then
											missSpell = {}
											missDestData[sourceGUID] = missSpell
										end
										local missSpellData = missSpell[spellID]
										if not missSpellData then
											missSpellData = {
												parry = 0,
												dodge = 0,
												miss = 0,
												parry_target = 0,
												dodge_target = 0,
												miss_target = 0,
												segments = {},
											}
											missSpell[spellID] = missSpellData
										end
										missSpellData.parry = missSpellData.parry+spellAmount.parry
										missSpellData.dodge = missSpellData.dodge+spellAmount.dodge
										missSpellData.miss = missSpellData.miss+spellAmount.miss

										if CurrentFight.segments[segment].e then
											missSpellData.parry_target = missSpellData.parry_target+spellAmount.parry
											missSpellData.dodge_target = missSpellData.dodge_target+spellAmount.dodge
											missSpellData.miss_target = missSpellData.miss_target+spellAmount.miss
											missSpellData.segments[#missSpellData.segments+1] = segment
										end
									end
								end
							end
						end
					end
				end
				local reductionMissToSpell = {
					dodge = 81,
					parry = 82243,
					miss = 154592,
				}
				for destGUID,destData in pairs(missData) do
					local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[destGUID] or 0)
					if isFriendly and (ExRT.F.table_len(HsourceVar) == 0 or HsourceVar[destGUID]) then
						for sourceGUID,sourceData in pairs(destData) do
							for spellID,spellAmount in pairs(sourceData) do
								local avgData = avgDamage[ sourceGUID ][ spellID ]
								local avg = avgData[3]
								if not avg then
									if avgData[1] > 0 then
										avg = avgData[2] / avgData[1]
									else
										avg = 0
									end
									avgData[3] = avg
								end
								if avg > 0 then
									for reductionName,reductionSpellID in pairs(reductionMissToSpell) do
										if spellAmount[reductionName] > 0 then
											local sourceHeal, destPos = HealingTab_UpdateLines_GetUnit(heal,graph,reductionSpellID,destGUID,"spell")

											local fromSpellPos = ExRT.F.table_find(sourceHeal.from,spellID,1)
											if not fromSpellPos then
												fromSpellPos = #sourceHeal.from + 1
												sourceHeal.from[fromSpellPos] = {spellID,0}
											end
											fromSpellPos = sourceHeal.from[fromSpellPos]

											local amount = avg * spellAmount[reductionName.."_target"]

											sourceHeal.eff = sourceHeal.eff + amount
											sourceHeal.total = sourceHeal.total + amount
											sourceHeal.absorbs = sourceHeal.absorbs + amount
											total = total + amount
											destPos[2] = destPos[2] + amount
											fromSpellPos[2] = fromSpellPos[2] + amount

											for i=1,#spellAmount.segments do
												local segment = spellAmount.segments[i]
												if not graph[ reductionSpellID ] then
													graph[ reductionSpellID ] = {}
												end
												if not graph[ reductionSpellID ][segment] then
													graph[ reductionSpellID ][segment] = 0
												end
												if not graph[ -1 ][segment] then
													graph[ -1 ][segment] = 0
												end
												graph[ reductionSpellID ][segment] = graph[ reductionSpellID ][segment] + amount
												graph[ -1 ][segment] = graph[ -1 ][segment] + amount
											end
										end
									end
								end
							end
						end
					end
				end
			end

		end
		if not onlyReduction then
			for _,healData in pairs(heal) do
				for sourceGUID,sourceData in pairs(CurrentFight.healFrom) do
					for destGUID,destData in pairs(sourceData) do
						local isEnemy = not ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[destGUID])
						if ExRT.F.table_len(HdestVar) == 0 or HdestVar[destGUID] then
							if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
								for spellID,spellData in pairs(destData) do
									if healData.spell == spellID then
										for fromSpellID,fromSpellSegments in pairs(spellData) do
											for segment,fromSpellAmount in pairs(fromSpellSegments) do
												if CurrentFight.segments[segment].e then

													local destPos = ExRT.F.table_find(healData.from,fromSpellID,1)
													if not destPos then
														destPos = #healData.from + 1
														healData.from[destPos] = {fromSpellID,0}
													end
													destPos = healData.from[destPos]

													destPos[2] = destPos[2] + fromSpellAmount
												end
											end
										end
									end
								end
							end
						end
					end
				end
			end
		end

		local totalIsFull = 1
		total = max(total,1)
		if total == 1 and #heal == 0 then
			total = 0
			totalIsFull = 0
		end
		local _max = nil
		reportOptions[2] = L.BossWatcherReportHPS
		wipe(reportData[2])
		reportData[2][1] = (DamageTab_GetGUIDsReport(HsourceVar) or L.BossWatcherAllSources).." > "..(DamageTab_GetGUIDsReport(HdestVar) or L.BossWatcherAllTargets)
		local activeFightLength = GetFightLength()
		if HealingTab_Variables.ShowOverheal then
			total = total + totalOver
			sort(heal,function(a,b) return a.total>b.total end)
			_max = heal[1] and heal[1].total or 0
		else
			sort(heal,function(a,b) return a.eff>b.eff end)
			_max = heal[1] and heal[1].eff or 0
		end
		reportData[2][2] = L.BossWatcherReportTotal.." - "..ExRT.F.shortNumber(total).."@1@ ("..floor(total / activeFightLength)..")@1#"
		HealingTab_SetLine({
			line = 1,
			name = L.BossWatcherReportTotal,
			total = total,
			num = total,
			max = total,
			dps = total / activeFightLength,
			spellID = -1,
			alpha = HealingTab_Variables.ShowOverheal and totalOver,
			check = BWInterfaceFrame.GraphFrame:IsShown(),
			checkState = true,
		})
		_max = max(_max,1)
		local castsCount = SpellsPage_GetCastsNumber(ExRT.F.table_len(HsourceVar) > 0 and HsourceVar,ExRT.F.table_len(HdestVar) > 0 and HdestVar)
		for i=1,#heal do
			local healLine = heal[i]
			local isPetAbility = healLine.info == "pet"
			local spellID = healLine.spell
			local isHoT = (not ExRT.isClassic or ExRT.isCata) and spellID < 0
			if isHoT then
				spellID = -spellID
			end
			local spellName,_,spellIcon = GetSpellInfo(spellID)
			local defSpellName = spellName
			if isPetAbility then
				spellName = L.BossWatcherPetText..": "..spellName
			end
			if isHoT then
				spellName = spellName .. " ["..L.BossWatcherHoT.."]"
			end
			local school = module.db.spellsSchool[ spellID ] or 0
			local tooltipData = {
				{spellName,spellIcon},
				{L.BossWatcherHealTooltipCount,healLine.count},
				{L.BossWatcherHealTooltipHitMax,floor(healLine.hitmax)},
				{L.BossWatcherHealTooltipHitMid,ExRT.F.Round(max(healLine.total-healLine.crit-(healLine.overheal-healLine.critover),0)/max(healLine.count-healLine.critcount,1))},
				{L.BossWatcherHealTooltipCritCount,format("%d (%.1f%%)",healLine.critcount,healLine.critcount/max(1,healLine.count)*100)},
				{L.BossWatcherHealTooltipCritAmount,ExRT.F.shortNumber(healLine.crit-healLine.critover)},
				{L.BossWatcherHealTooltipCritMax,healLine.critmax},
				{L.BossWatcherHealTooltipCritMid,ExRT.F.Round((healLine.crit-healLine.critover)/max(healLine.critcount,1))},
				{L.BossWatcherHealTooltipOver,format("%s (%.1f%%)",ExRT.F.shortNumber(healLine.overheal),healLine.overheal/max(healLine.total,1)*100)},
				{L.BossWatcherHealTooltipAbsorbed,ExRT.F.shortNumber(healLine.absorbed)},
				{L.BossWatcherHealTooltipTotal,ExRT.F.shortNumber(healLine.total)},
				{L.BossWatcherSchool,GetSchoolName(school)},
			}
			local casts = castsCount[ spellID ] or castsCount[ defSpellName ]
			if casts then
				tinsert(tooltipData,2,{L.BossWatcherDamageTooltipCastsCount,casts})
				tinsert(tooltipData,3,{L.BossWatcherPerCast,ExRT.F.shortNumber(healLine.eff / casts)})
			end

			sort(healLine.targets,DamageTab_Temp_SortingBy2Param)
			if #healLine.targets > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherHealTooltipTargets," "}
			end
			for j=1,min(5,#healLine.targets) do
				tooltipData[#tooltipData + 1] = {SubUTF8String(GetGUID(healLine.targets[j][1]),20)..GUIDtoText(" [%s]",healLine.targets[j][1]),format("%s (%.1f%%)",ExRT.F.shortNumber(healLine.targets[j][2]),min(healLine.targets[j][2] / max(1,healLine.eff+(HealingTab_Variables.ShowOverheal and healLine.overheal or 0))*100,100))}
			end

			sort(healLine.from,DamageTab_Temp_SortingBy2Param)
			if #healLine.from > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherFromSpells," "}
			end
			for j=1,min(5,#healLine.from) do
				local spellName,_,spellTexture = GetSpellInfo(healLine.from[j][1])
				tooltipData[#tooltipData + 1] = {(spellTexture and "|T"..spellTexture..":0|t" or "")..(spellName or "spell:"..spellID),ExRT.F.shortNumber(healLine.from[j][2])}
			end

			local currHealing = healLine.eff+(HealingTab_Variables.ShowOverheal and healLine.overheal or 0)
			local hps = currHealing/activeFightLength
			HealingTab_SetLine({
				line = i+1,
				icon = spellIcon,
				name = spellName,
				total = total,
				num = currHealing,
				alpha = (HealingTab_Variables.ShowOverheal and not onlyReduction) and healLine.overheal or healLine.absorbs,
				max = _max,
				dps = hps,
				spellID = spellID,
				tooltip = tooltipData,
				school = school,
				isDoT = isHoT,
				check = BWInterfaceFrame.GraphFrame:IsShown(),
				checkState = i <= 3,
			})
			reportData[2][#reportData[2]+1] = i..". "..(isPetAbility and L.BossWatcherPetText..": " or "")..GetSpellLink(spellID).." - "..ExRT.F.shortNumber(currHealing).."@1@ ("..floor(hps)..")@1#"
		end
		for i=#heal+2,#BWInterfaceFrame.tab.tabs[2].lines do
			BWInterfaceFrame.tab.tabs[2].lines[i]:Hide()
		end
		BWInterfaceFrame.tab.tabs[2].scroll:Height((#heal+1) * 20)

		HealingTab_Variables.graphCache = {graph,#CurrentFight.segments,heal,true}
		if BWInterfaceFrame.GraphFrame:IsShown() then
			HealingTab_ReloadGraph(graph,#CurrentFight.segments,heal,true)
		end
	end


	local function HealingTab_UpdateLinesFromSpells()
		HealingTab_UpdateDropDowns()
		HealingTab_UpdateChecks()

		local doEnemy = nil

		local heal = {}
		local total = 0
		local graph = {[-1]={}}
		for sourceGUID,sourceData in pairs(CurrentFight.healFrom) do
			local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
			if owner then
				sourceGUID = owner
			end
			if ExRT.F.table_len(HsourceVar) == 0 or HsourceVar[sourceGUID] then
				for destGUID,destData in pairs(sourceData) do
					local isEnemy = not ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[destGUID])
					if ExRT.F.table_len(HdestVar) == 0 or HdestVar[destGUID] then
						if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
							for spellID,spellData in pairs(destData) do
								for fromSpellID,fromSpellSegments in pairs(spellData) do
									local inDamagePos = ExRT.F.table_find(heal,fromSpellID,1)
									if not inDamagePos then
										inDamagePos = #heal + 1
										heal[inDamagePos] = {fromSpellID,0,{},{},spell=fromSpellID}
									end
									local destPos = ExRT.F.table_find(heal[inDamagePos][3],destGUID,1)
									if not destPos then
										destPos = #heal[inDamagePos][3] + 1
										heal[inDamagePos][3][destPos] = {destGUID,0}
									end
									destPos = heal[inDamagePos][3][destPos]

									local sourcePos = ExRT.F.table_find(heal[inDamagePos][4],sourceGUID,1)
									if not sourcePos then
										sourcePos = #heal[inDamagePos][4] + 1
										heal[inDamagePos][4][sourcePos] = {sourceGUID,0}
									end
									sourcePos = heal[inDamagePos][4][sourcePos]

									if not graph[ fromSpellID ] then
										graph[ fromSpellID ] = {}
									end

									for segment,fromSpellAmount in pairs(fromSpellSegments) do
										if CurrentFight.segments[segment].e then
											heal[inDamagePos][2] = heal[inDamagePos][2] + fromSpellAmount
											total = total + fromSpellAmount
											destPos[2] = destPos[2] + fromSpellAmount
											sourcePos[2] = sourcePos[2] + fromSpellAmount

											if not graph[ fromSpellID ][segment] then
												graph[ fromSpellID ][segment] = 0
											end
											if not graph[ -1 ][segment] then
												graph[ -1 ][segment] = 0
											end

											graph[ fromSpellID ][segment] = graph[ fromSpellID ][segment] + fromSpellAmount
											graph[ -1 ][segment] = graph[ -1 ][segment] + fromSpellAmount
										end
									end
								end
							end
						end
					end
				end
			end
		end

		local totalIsFull = 1
		total = max(total,1)
		if total == 1 and #heal == 0 then
			total = 0
			totalIsFull = 0
		end
		local _max = nil
		reportOptions[2] = L.BossWatcherReportHPS
		wipe(reportData[2])
		reportData[2][1] = (DamageTab_GetGUIDsReport(HsourceVar) or L.BossWatcherAllSources).." > "..(DamageTab_GetGUIDsReport(HdestVar) or L.BossWatcherAllTargets)
		local activeFightLength = GetFightLength()
		do
			local hps = total / activeFightLength
			reportData[2][2] = L.BossWatcherReportTotal.." - "..ExRT.F.shortNumber(total).."@1@ ("..floor(hps)..")@1#"
			sort(heal,function(a,b) return a[2]>b[2] end)
			_max = heal[1] and heal[1][2] or 0
			HealingTab_SetLine({
				line = 1,
				name = L.BossWatcherReportTotal,
				num = total,
				total = total,
				max = total,
				dps = hps,
				spellID = -1,
				check = BWInterfaceFrame.GraphFrame:IsShown(),
				checkState = true,
			})
		end
		for i=1,#heal do
			local spellName,_,spellIcon = GetSpellInfo(heal[i][1])
			local school = module.db.spellsSchool[ heal[i][1] ] or 0
			local tooltipData = {
				{spellName,spellIcon},
				{L.BossWatcherHealTooltipTotal,ExRT.F.shortNumber(heal[i][2])},
				{L.BossWatcherSchool,GetSchoolName(school)},
			}
			sort(heal[i][3],DamageTab_Temp_SortingBy2Param)
			if #heal[i][3] > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherHealTooltipTargets," "}
			end
			for j=1,min(5,#heal[i][3]) do
				tooltipData[#tooltipData + 1] = {SubUTF8String(GetGUID(heal[i][3][j][1]),20)..GUIDtoText(" [%s]",heal[i][3][j][1]),format("%s (%.1f%%)",ExRT.F.shortNumber(heal[i][3][j][2]),min(heal[i][3][j][2] / max(1,heal[i][2])*100,100))}
			end
			sort(heal[i][4],DamageTab_Temp_SortingBy2Param)
			if #heal[i][4] > 0 then
				tooltipData[#tooltipData + 1] = {" "," "}
				tooltipData[#tooltipData + 1] = {L.BossWatcherHealTooltipSources," "}
			end
			for j=1,min(5,#heal[i][4]) do
				tooltipData[#tooltipData + 1] = {SubUTF8String(GetGUID(heal[i][4][j][1]),20)..GUIDtoText(" [%s]",heal[i][4][j][1]),format("%s (%.1f%%)",ExRT.F.shortNumber(heal[i][4][j][2]),min(heal[i][4][j][2] / max(1,heal[i][2])*100,100))}
			end
			do
				local hps = heal[i][2]/activeFightLength
				HealingTab_SetLine({
					line = i+1,
					icon = spellIcon,
					name = spellName,
					total = total,
					num = heal[i][2],
					max = _max,
					dps = hps,
					spellID = heal[i][1],
					tooltip = tooltipData,
					school = school,
					check = BWInterfaceFrame.GraphFrame:IsShown(),
					checkState = i <= 3,
				})
				reportData[2][#reportData[2]+1] = i..". "..GetSpellLink(heal[i][1]).." - "..ExRT.F.shortNumber(heal[i][2]).."@1@ ("..floor(hps)..")@1#"
			end
		end
		for i=#heal+2,#BWInterfaceFrame.tab.tabs[2].lines do
			BWInterfaceFrame.tab.tabs[2].lines[i]:Hide()
		end
		BWInterfaceFrame.tab.tabs[2].scroll:Height((#heal+1) * 20)

		HealingTab_Variables.graphCache = {graph,#CurrentFight.segments,heal,true}
		if BWInterfaceFrame.GraphFrame:IsShown() then
			HealingTab_ReloadGraph(graph,#CurrentFight.segments,heal,true)
		end
	end


	local function HealingTab_SelectDropDownSource(self,arg)
		ELib:DropDownClose()
		local Back_destVar = ExRT.F.table_copy2(HdestVar)
		local Back_sourceVar = ExRT.F.table_copy2(HsourceVar)
		wipe(HsourceVar)
		if arg then
			HsourceVar[arg] = true

			if IsShiftKeyDown() then
				local name = CurrentFight.guids[arg]
				if name then
					for GUID,GUIDname in pairs(CurrentFight.guids) do
						if GUIDname == name then
							HsourceVar[GUID] = true
						end
					end
				end
			end
		end
		HealingTab_UpdatePage()
	end
	local function HealingTab_SelectDropDownDest(self,arg)
		ELib:DropDownClose()
		local Back_destVar = ExRT.F.table_copy2(HdestVar)
		local Back_sourceVar = ExRT.F.table_copy2(HsourceVar)
		wipe(HdestVar)
		if arg then
			HdestVar[arg] = true

			if IsShiftKeyDown() then
				local name = CurrentFight.guids[arg]
				if name then
					for GUID,GUIDname in pairs(CurrentFight.guids) do
						if GUIDname == name then
							HdestVar[GUID] = true
						end
					end
				end
			end
		end
		HealingTab_UpdatePage()
	end

	local function HealingTab_SelectDropDown_OptionTanks(_,destTable,onlyTanks)
		ELib:DropDownClose()
		local Back_destVar = ExRT.F.table_copy2(HdestVar)
		local Back_sourceVar = ExRT.F.table_copy2(HsourceVar)
		wipe(HdestVar)
		for i=1,#destTable do
			local isTank
			if CurrentFight.other.rolesGUID[ destTable[i][1] ] == "TANK" then
				isTank = true
			end
			if (isTank and onlyTanks) or (not isTank and not onlyTanks) then
				HdestVar[ destTable[i][1] ] = true
			end
		end
		HealingTab_UpdatePage()
	end

	local function HealingTab_CheckDropDownSource(self,checked)
		if checked then
			HsourceVar[self.arg1] = true
		else
			HsourceVar[self.arg1] = nil
		end
		HealingTab_UpdatePage()
	end
	local function HealingTab_CheckDropDownDest(self,checked)
		if checked then
			HdestVar[self.arg1] = true
		else
			HdestVar[self.arg1] = nil
		end
		HealingTab_UpdatePage()
	end

	local function HealingTab_HPS(disableUpdateVars)
		local doEnemy = not HealingTab_Variables.state_friendly

		local sourceTable = {}
		local destTable = {}
		for sourceGUID,sourceData in pairs(CurrentFight.heal) do
			local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
			if owner then
				sourceGUID = owner
			end
			for destGUID,destData in pairs(sourceData) do
				for destReact,destReactData in pairs(destData) do
					local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(destReact)
					if (isFriendly and not doEnemy) or (not isFriendly and doEnemy) then
						for spellID,spellSegments in pairs(destReactData) do
							for segment,spellAmount in pairs(spellSegments) do
								if CurrentFight.segments[segment].e then
									if not ExRT.F.table_find(destTable,destGUID,1) then
										destTable[#destTable + 1] = {destGUID,GetGUID(destGUID)}
									end
									if not ExRT.F.table_find(sourceTable,sourceGUID,1) then
										sourceTable[#sourceTable + 1] = {sourceGUID,GetGUID(sourceGUID)}
									end
								end
							end
						end
					end
				end
			end
		end
		sort(sourceTable,function(a,b) return a[2]<b[2] end)
		sort(destTable,function(a,b) return a[2]<b[2] end)
		wipe(BWInterfaceFrame.tab.tabs[2].sourceDropDown.List)
		wipe(BWInterfaceFrame.tab.tabs[2].targetDropDown.List)
		BWInterfaceFrame.tab.tabs[2].sourceDropDown.List[1] = {text = L.BossWatcherAll,func = HealingTab_SelectDropDownSource,padding = 16}
		BWInterfaceFrame.tab.tabs[2].targetDropDown.List[1] = {text = L.BossWatcherAll,func = HealingTab_SelectDropDownDest,padding = 16}
		for i=1,#sourceTable do
			local isPlayer = ExRT.F.GetUnitTypeByGUID(sourceTable[i][1]) == 0
			local classColor = ""
			if isPlayer then
				classColor = "|c"..ExRT.F.classColorByGUID(sourceTable[i][1])
			end
			BWInterfaceFrame.tab.tabs[2].sourceDropDown.List[i+1] = {
				text = classColor..sourceTable[i][2]..GUIDtoText(" [%s]",sourceTable[i][1]),
				arg1 = sourceTable[i][1],
				func = HealingTab_SelectDropDownSource,
				checkFunc = HealingTab_CheckDropDownSource,
				checkable = true,
			}
		end
		for i=1,#destTable do
			local isPlayer = ExRT.F.GetUnitTypeByGUID(destTable[i][1]) == 0
			local classColor = ""
			if isPlayer then
				classColor = "|c"..ExRT.F.classColorByGUID(destTable[i][1])
			end
			BWInterfaceFrame.tab.tabs[2].targetDropDown.List[i+1] = {
				text = classColor..destTable[i][2]..GUIDtoText(" [%s]",destTable[i][1]),
				arg1 = destTable[i][1],
				func = HealingTab_SelectDropDownDest,
				checkFunc = HealingTab_CheckDropDownDest,
				checkable = true,
			}
		end
		tinsert(BWInterfaceFrame.tab.tabs[2].targetDropDown.List,2,{
			text = L.BossWatcherHealToTanks,
			padding = 16,
			func = HealingTab_SelectDropDown_OptionTanks,
			arg1 = destTable,
			arg2 = true,
		})
		tinsert(BWInterfaceFrame.tab.tabs[2].targetDropDown.List,2,{
			text = L.BossWatcherHealToNonTanks,
			padding = 16,
			func = HealingTab_SelectDropDown_OptionTanks,
			arg1 = destTable,
			arg2 = false,
		})
		if not disableUpdateVars then
			wipe(HsourceVar)
			wipe(HdestVar)
		end
	end

	local function HealingTab_RPS(disableUpdateVars)
		local sourceTable = {}
		local destTable = {}
		for destGUID,destData in pairs(CurrentFight.reduction) do
			for sourceGUID,sourceData in pairs(destData) do
				for spellID,spellData in pairs(sourceData) do
					for reductorGUID,reductorData in pairs(spellData) do
						local owner = ExRT.F.Pets:getOwnerGUID(reductorGUID,GetPetsDB())
						if owner then
							reductorGUID = owner
						end
						local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[reductorGUID])
						if isFriendly then
							for spellID,spellSegments in pairs(reductorData) do
								for segment,spellAmount in pairs(spellSegments) do
									if CurrentFight.segments[segment].e then
										if not ExRT.F.table_find(destTable,destGUID,1) then
											destTable[#destTable + 1] = {destGUID,GetGUID(destGUID)}
										end
										if not ExRT.F.table_find(sourceTable,reductorGUID,1) then
											sourceTable[#sourceTable + 1] = {reductorGUID,GetGUID(reductorGUID)}
										end
									end
								end
							end
						end
					end
				end
			end
		end
		sort(sourceTable,function(a,b) return a[2]<b[2] end)
		sort(destTable,function(a,b) return a[2]<b[2] end)
		wipe(BWInterfaceFrame.tab.tabs[2].sourceDropDown.List)
		wipe(BWInterfaceFrame.tab.tabs[2].targetDropDown.List)
		BWInterfaceFrame.tab.tabs[2].sourceDropDown.List[1] = {text = L.BossWatcherAll,func = HealingTab_SelectDropDownSource,padding = 16}
		BWInterfaceFrame.tab.tabs[2].targetDropDown.List[1] = {text = L.BossWatcherAll,func = HealingTab_SelectDropDownDest,padding = 16}
		for i=1,#sourceTable do
			local isPlayer = ExRT.F.GetUnitTypeByGUID(sourceTable[i][1]) == 0
			local classColor = ""
			if isPlayer then
				classColor = "|c"..ExRT.F.classColorByGUID(sourceTable[i][1])
			end
			BWInterfaceFrame.tab.tabs[2].sourceDropDown.List[i+1] = {
				text = classColor..sourceTable[i][2]..GUIDtoText(" [%s]",sourceTable[i][1]),
				arg1 = sourceTable[i][1],
				func = HealingTab_SelectDropDownSource,
				checkFunc = HealingTab_CheckDropDownSource,
				checkable = true,
			}
		end
		for i=1,#destTable do
			local isPlayer = ExRT.F.GetUnitTypeByGUID(destTable[i][1]) == 0
			local classColor = ""
			if isPlayer then
				classColor = "|c"..ExRT.F.classColorByGUID(destTable[i][1])
			end
			BWInterfaceFrame.tab.tabs[2].targetDropDown.List[i+1] = {
				text = classColor..destTable[i][2]..GUIDtoText(" [%s]",destTable[i][1]),
				arg1 = destTable[i][1],
				func = HealingTab_SelectDropDownDest,
				checkFunc = HealingTab_CheckDropDownDest,
				checkable = true,
			}
		end
		if not disableUpdateVars then
			wipe(HsourceVar)
			wipe(HdestVar)
		end
	end

	function HealingTab_UpdatePage(updateLists,midFunc,disableUpdateVars)
		if HealingTab_Variables.state_mitigation then
			BWInterfaceFrame.tab.tabs[2].showOverhealChk:Tooltip(""):SetText("|cffffffff"..STAT_DODGE.." / "..STAT_PARRY.." / "..ACTION_SPELL_MISSED_IMMUNE)

		else
			BWInterfaceFrame.tab.tabs[2].showOverhealChk:Tooltip(L.BossWatcherHealShowOver):SetText("|cffffffff"..L.BossWatcherOverhealing)
		end
		if updateLists then
			if not HealingTab_Variables.state_mitigation then
				HealingTab_HPS(disableUpdateVars)
			else
				HealingTab_RPS(disableUpdateVars)
			end
		end
		if midFunc then
			midFunc()
		end
		if IsAltKeyDown() then
			HealingTab_UpdateLinesFromSpells()
		elseif not HealingTab_Variables.state_spells then
			HealingTab_UpdateLinesPlayers()
		else
			HealingTab_UpdateLinesSpell()
		end
	end


	tab.chkFriendly = ELib:Radio(tab,L.BossWatcherFriendly,true):Point(15,-50):AddButton():OnClick(function(self) 
		HealingTab_Variables.state_friendly = true
		HealingTab_Variables.state_mitigation = false
		BWInterfaceFrame.tab.tabs[2].chkEnemy:SetChecked(false)
		BWInterfaceFrame.tab.tabs[2].chkMitigation:SetChecked(false)
		self:SetChecked(true)

		HealingTab_UpdatePage(true)
	end)
	tab.chkEnemy = ELib:Radio(tab,L.BossWatcherHostile):Point(15,-65):AddButton():OnClick(function(self) 
		HealingTab_Variables.state_friendly = false
		HealingTab_Variables.state_mitigation = false
		BWInterfaceFrame.tab.tabs[2].chkFriendly:SetChecked(false)
		BWInterfaceFrame.tab.tabs[2].chkMitigation:SetChecked(false)
		self:SetChecked(true)

		HealingTab_UpdatePage(true)
	end)
	tab.chkMitigation = ELib:Radio(tab,L.BossWatcherHealReduction):Point(15,-80):AddButton():OnClick(function(self) 
		HealingTab_Variables.state_friendly = true
		HealingTab_Variables.state_mitigation = true
		BWInterfaceFrame.tab.tabs[2].chkFriendly:SetChecked(false)
		BWInterfaceFrame.tab.tabs[2].chkEnemy:SetChecked(false)
		self:SetChecked(true)

		HealingTab_UpdatePage(true)
	end)

	tab.bySource = ELib:Radio(tab,L.BossWatcherBySource,true):Point(200,-50):AddButton():OnClick(function(self) 
		HealingTab_Variables.state_byTarget = false
		HealingTab_Variables.state_spells = false
		BWInterfaceFrame.tab.tabs[2].byTarget:SetChecked(false)
		BWInterfaceFrame.tab.tabs[2].bySpell:SetChecked(false)
		self:SetChecked(true)

		HealingTab_UpdatePage(true)
	end)
	tab.byTarget = ELib:Radio(tab,L.BossWatcherByTarget):Point(200,-65):AddButton():OnClick(function(self) 
		HealingTab_Variables.state_byTarget = true
		HealingTab_Variables.state_spells = false
		BWInterfaceFrame.tab.tabs[2].bySource:SetChecked(false)
		BWInterfaceFrame.tab.tabs[2].bySpell:SetChecked(false)
		self:SetChecked(true)

		HealingTab_UpdatePage(true)
	end)
	tab.bySpell = ELib:Radio(tab,L.BossWatcherBySpell):Point(200,-80):AddButton():OnClick(function(self) 
		HealingTab_Variables.state_byTarget = false
		HealingTab_Variables.state_spells = true
		BWInterfaceFrame.tab.tabs[2].bySource:SetChecked(false)
		BWInterfaceFrame.tab.tabs[2].byTarget:SetChecked(false)
		self:SetChecked(true)

		HealingTab_UpdatePage(true)
	end)

	tab.sourceDropDown = ELib:DropDown(tab,250,20):Size(195):Point(430,-50):SetText(L.BossWatcherAll)
	tab.sourceText = ELib:Text(tab,L.BossWatcherSource..":",12):Size(100,20):Point("TOPRIGHT",tab.sourceDropDown,"TOPLEFT",-6,0):Right():Color():Shadow()

	tab.targetDropDown = ELib:DropDown(tab,250,20):Size(195):Point(430,-75):SetText(L.BossWatcherAll)
	tab.targetText = ELib:Text(tab,L.BossWatcherTarget..":",12):Size(100,20):Point("TOPRIGHT",tab.targetDropDown,"TOPLEFT",-6,0):Right():Color():Shadow()

	function tab.sourceDropDown.additionalToggle(self)
		for i=2,#self.List do
			self.List[i].checkState = HsourceVar[self.List[i].arg1]
		end
	end
	function tab.targetDropDown.additionalToggle(self)
		for i=2,#self.List do
			self.List[i].checkState = HdestVar[self.List[i].arg1]
		end
	end

	tab.showOverhealChk = ELib:Check(tab,"|cffffffff"..L.BossWatcherOverhealing):Point(650,-50):Tooltip(L.BossWatcherHealShowOver):OnClick(function (self)
		if self:GetChecked() then
			HealingTab_Variables.ShowOverheal = true
		else
			HealingTab_Variables.ShowOverheal = false
		end
		HealingTab_UpdatePage()
	end)
	tab.showOverhealChk.text:SetPoint("RIGHT",BWInterfaceFrame,-5,0)
	tab.showOverhealChk.text:SetJustifyH("LEFT")

	tab.showGraphChk = ELib:Check(tab,"|cffffffff"..L.BossWatcherTabGraphics.." ",VMRT.BossWatcher.optionsHealingGraph):Point(650,-75):OnClick(function (self)
		local tab2 = BWInterfaceFrame.tab.tabs[2]
		if self:GetChecked() then
			tab2.scroll:Point("TOP",0,-305)
			BWInterfaceFrame.GraphFrame:Show()
		else
			tab2.scroll:Point("TOP",0,-100)
			BWInterfaceFrame.GraphFrame:Hide()
		end
		VMRT.BossWatcher.optionsHealingGraph = self:GetChecked()
		if HealingTab_Variables.graphCache then
			HealingTab_ReloadGraph(unpack(HealingTab_Variables.graphCache))
		end
	end)

	tab.scroll = ELib:ScrollFrame(tab):Point("TOP",0,VMRT.BossWatcher.optionsHealingGraph and -305 or -100):Point("BOTTOM",0,10):Height(600)
	tab.scroll:SetWidth(835)
	tab.scroll.C:SetWidth(835)
	tab.lines = {}

	local function HealingTab_RightClick_BackFunction()
		if not HealingTab_Variables.Back_state then
			HealingTab_UpdatePage(true)
			return
		end
		HealingTab_Variables.state_friendly = HealingTab_Variables.Back_state[1]
		HealingTab_Variables.state_spells = HealingTab_Variables.Back_state[2]
		HealingTab_Variables.state_mitigation = HealingTab_Variables.Back_state[3]
		HealingTab_Variables.state_byTarget = HealingTab_Variables.Back_state[4]

		HealingTab_UpdatePage(true,function()
			HsourceVar = HealingTab_Variables.Back_state[5]
			HdestVar = HealingTab_Variables.Back_state[6]
		end)
		HealingTab_Variables.Back_state = nil
	end

	tab.scroll:SetScript("OnMouseUp",function(self,button)
		if button == "RightButton" then
			HealingTab_RightClick_BackFunction()
		end
	end)

	local function HealingTab_Line_Check_OnClick(self)
		local spellID = self:GetParent().spellID or self:GetParent().sourceGUID
		if not spellID then
			return
		end
		if self:GetParent().isDoT and type(spellID) == 'number' then
			spellID = -spellID
		end
		local graphData = BWInterfaceFrame.GraphFrame.G.data
		local findPos = ExRT.F.table_find(graphData,spellID,'info_spellID')
		if findPos then
			graphData[ findPos ].hide = not self:GetChecked()
		end
		BWInterfaceFrame.GraphFrame.G:Reload()
	end
	local function HealingTab_Line_OnClick(self,button)
		if button == "RightButton" then
			HealingTab_RightClick_BackFunction()
			return
		end
		local x,y = ExRT.F.GetCursorPos(self)
		if (self.check and self.check:IsShown() or (self:GetParent().check and self:GetParent().check:IsShown())) and x <= 30 then
			return
		end
		local GUID = self.sourceGUID
		local tooltip = self.spellLink

		local parent = self:GetParent()
		if parent.isMain then
			GUID = parent.sourceGUID
			tooltip = parent.spellLink
		end
		if parent.isMain and IsShiftKeyDown() and tooltip and tooltip:find("spell:") then
			local spellID = tooltip:match("%d+")
			if spellID then
				ExRT.F.LinkSpell(spellID)
				return
			end
		end
		if GUID then
			if not HealingTab_Variables.state_spells then
				HealingTab_Variables.Back_state = {
					HealingTab_Variables.state_friendly,
					HealingTab_Variables.state_spells,
					HealingTab_Variables.state_mitigation,
					HealingTab_Variables.state_byTarget,
					ExRT.F.table_copy2(HsourceVar),
					ExRT.F.table_copy2(HdestVar),
				}
				HealingTab_Variables.state_spells = true
				HealingTab_UpdatePage(true,function()
					if HealingTab_Variables.state_byTarget then
						wipe(HdestVar)
						HdestVar[GUID] = true
					else
						wipe(HsourceVar)
						HsourceVar[GUID] = true
					end
				end,true)
			end
		end
	end
	local function HealingTab_LineOnEnter(self)
		if self.tooltip then
			GameTooltip:SetOwner(self,"ANCHOR_LEFT")
			local firstLine = self.tooltip[1]
			if type(firstLine) == "table" then
				firstLine = (firstLine[2] and "|T"..firstLine[2]..":18|t " or "")..firstLine[1]
			end
			GameTooltip:SetText(firstLine)
			for i=2,#self.tooltip do
				if type(self.tooltip[i]) == "table" then
					GameTooltip:AddDoubleLine(self.tooltip[i][1],self.tooltip[i][2],1,1,1,1,1,1,1,1)
				else
					GameTooltip:AddLine(self.tooltip[i])
				end
			end
			GameTooltip:Show()
		end
	end
	local function HealingTab_Line_OnEnter(self)
		local parent = self:GetParent()
		if parent.spellLink then
			GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
			GameTooltip:SetHyperlink(parent.spellLink)
			GameTooltip:Show()
		elseif parent.name:IsTruncated() then
			GameTooltip:SetOwner(self,"ANCHOR_LEFT")
			GameTooltip:SetText(parent.name:GetText())
			GameTooltip:Show()
		elseif parent.tooltip then
			HealingTab_LineOnEnter(parent)
		end
	end
	function HealingTab_SetLine(dataTable)
		local i,icon,name,overall_num,overall,total,dps,class,sourceGUID,doEnemy,spellLink,tooltip,school,overall_black,isDoT
		local showCheck,checkState,spellID

		i = dataTable.line
		icon = dataTable.icon or ""
		name = dataTable.name
		total = dataTable.num
		overall_num = dataTable.num / max(dataTable.total,1)
		overall = dataTable.num / max(dataTable.max,1)
		if dataTable.alpha then
			overall_black = dataTable.alpha / max(dataTable.num,1)
		end
		dps = dataTable.dps
		class = dataTable.class
		sourceGUID = dataTable.sourceGUID
		doEnemy = dataTable.doEnemy
		if dataTable.spellID and dataTable.spellID ~= -1 then
			spellLink = "spell:"..dataTable.spellID
		end
		tooltip = dataTable.tooltip
		school = dataTable.school
		isDoT = dataTable.isDoT
		showCheck = dataTable.check
		checkState = dataTable.checkState
		spellID = dataTable.spellID

		if not BWInterfaceFrame.tab.tabs[2].lines[i] then
			local line = CreateFrame("Button",nil,BWInterfaceFrame.tab.tabs[2].scroll.C)
			BWInterfaceFrame.tab.tabs[2].lines[i] = line
			line:SetSize(815,20)
			line:SetPoint("TOPLEFT",0,-(i-1)*20)

			line.leftSide = CreateFrame("Frame",nil,line)
			line.leftSide:SetSize(1,20)
			line.leftSide:SetPoint("LEFT",5,0)

			line.check = ELib:Check(line,""):Point("TOPLEFT",5,-2)
			line.check:SetSize(16,16)
			line.check:SetScript("OnClick",HealingTab_Line_Check_OnClick)

			line.overall_num = ELib:Text(line,"45.76%",12):Size(70,20):Point(250,0):Right():Color():Shadow()

			line.icon = ELib:Icon(line,nil,18):Point("TOPLEFT",line.leftSide,0,-1)
			line.name = ELib:Text(line,"name",12):Size(0,20):Point("TOPLEFT",line.leftSide,25,0):Point("TOPRIGHT",line.overall_num,"TOPLEFT",0,0):Color():Shadow()
			line.name:SetMaxLines(1)

			line.name_tooltip = CreateFrame('Button',nil,line)
			line.name_tooltip:SetAllPoints(line.name)
			line.overall = line:CreateTexture(nil, "BACKGROUND")
			--line.overall:SetColorTexture(0.7, 0.1, 0.1, 1)
			line.overall:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\bar24.tga")
			line.overall:SetSize(300,16)
			line.overall:SetPoint("TOPLEFT",325,-2)
			line.overall_black = line:CreateTexture(nil, "BACKGROUND")
			line.overall_black:SetTexture("Interface\\AddOns\\"..GlobalAddonName.."\\media\\bar24b.tga")
			line.overall_black:SetSize(300,16)
			line.overall_black:SetPoint("LEFT",line.overall,"RIGHT",0,0)

			line.total = ELib:Text(line,"125.46M",12):Size(95,20):Point(630,0):Color():Shadow()
			line.dps = ELib:Text(line,"34576.43",12):Size(100,20):Point(725,0):Color():Shadow()

			line.back = line:CreateTexture(nil, "BACKGROUND")
			line.back:SetAllPoints()
			if i%2==0 then
				line.back:SetColorTexture(0.3, 0.3, 0.3, 0.1)
			end
			line.name_tooltip:SetScript("OnClick",HealingTab_Line_OnClick)
			line.name_tooltip:SetScript("OnEnter",HealingTab_Line_OnEnter)
			line.name_tooltip:SetScript("OnLeave",GameTooltip_Hide)
			line:SetScript("OnClick",HealingTab_Line_OnClick)
			line:SetScript("OnEnter",HealingTab_LineOnEnter)
			line:SetScript("OnLeave",GameTooltip_Hide)
			line:RegisterForClicks("AnyUp")

			line.isMain = true
		end
		local line = BWInterfaceFrame.tab.tabs[2].lines[i]
		if type(icon) == "table" then
			line.icon.texture:SetTexture(icon[1] or "Interface\\Icons\\INV_MISC_QUESTIONMARK")
			line.icon.texture:SetTexCoord(unpack(icon,2,5))
		else
			line.icon.texture:SetTexture(icon or "Interface\\Icons\\INV_MISC_QUESTIONMARK")
			line.icon.texture:SetTexCoord(0,1,0,1)
		end
		line.name:SetText(name or "")
		line.overall_num:SetFormattedText("%.2f%%",overall_num and overall_num * 100 or 0)
		if overall_black and overall_black > 0 then
			local width = 300*(overall or 1)
			local normal_width = width * (1 - overall_black)
			line.overall:SetWidth(max(normal_width,1))
			line.overall_black:SetWidth(max(width-normal_width,1))
			line.overall_black:Show()
			if normal_width == 0 then
				line.overall:Hide()
				line.overall_black:SetPoint("TOPLEFT",325,-2)
			else
				line.overall:Show()
				line.overall_black:ClearAllPoints()
				line.overall_black:SetPoint("LEFT",line.overall,"RIGHT",0,0)
			end
		else
			line.overall:Show()
			line.overall_black:Hide()
			line.overall:SetWidth(max(300*(overall or 1),1))
		end
		line.total:SetText(total and ExRT.F.shortNumber(total) or "")
		do
			dps = dps or 0
			line.dps:SetFormattedText("%s.%s",FormatLargeNumber(floor(dps)),format("%.2f",dps % 1):gsub("^.-%.",""))
		end
		line.overall:SetGradient("HORIZONTAL",CreateColor(0,0,0,0), CreateColor(0,0,0,0))
		line.overall_black:SetGradient("HORIZONTAL",CreateColor(0,0,0,0), CreateColor(0,0,0,0))
		if class then
			local classColorArray = type(CUSTOM_CLASS_COLORS)=="table" and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
			if classColorArray then
				line.overall:SetVertexColor(classColorArray.r,classColorArray.g,classColorArray.b, 1)
				line.overall_black:SetVertexColor(classColorArray.r,classColorArray.g,classColorArray.b, 1)
			else
				line.overall:SetVertexColor(0.8,0.8,0.8, 1)
				line.overall_black:SetVertexColor(0.8,0.8,0.8, 1)
			end
		else
			line.overall:SetVertexColor(0.8,0.8,0.8, 1)
			line.overall_black:SetVertexColor(0.8,0.8,0.8, 1)
		end
		if school then
			SetSchoolColorsToLine(line.overall,school)
			SetSchoolColorsToLine(line.overall_black,school)
		end
		if showCheck then
			line.leftSide:SetPoint("LEFT",25,0)
			line.check:SetChecked(checkState)
			line.check:Show()
		else
			line.leftSide:SetPoint("LEFT",5,0)
			line.check:Hide()
		end
		line.sourceGUID = sourceGUID
		line.spellID = spellID
		line.doEnemy = doEnemy
		line.spellLink = spellLink
		line.tooltip = tooltip
		line.isDoT = isDoT
		line:Show()
	end

	local function HealingTab_AddSpecialInfo(text)
		local infoFrame = BWInterfaceFrame.tab.tabs[2].specialInfoFrame
		if not text then
			if infoFrame then
				infoFrame:Hide()
			end
			return
		end
		if not infoFrame then
			local sframe = CreateFrame("Frame",nil,BWInterfaceFrame.tab.tabs[2].scroll)
			BWInterfaceFrame.tab.tabs[2].specialInfoFrame = sframe
			sframe:SetSize(24,24)
			sframe:SetPoint("CENTER",BWInterfaceFrame.tab.tabs[2].scroll,"TOPLEFT",0,0)

			sframe.text = ELib:Text(sframe,"?",22):Size(24,24):Point("CENTER",0,0):Center():Color():Shadow()
			sframe.text:SetShadowColor(0,0,0,0)

			local circle = sframe:CreateTexture(nil, "OVERLAY")
			circle:SetPoint("CENTER",-1,2)
			circle:SetSize(26,26)
			circle:SetTexture("Interface\\Addons\\"..GlobalAddonName.."\\media\\radioModern")
			circle:SetTexCoord(0,0.25,0,1)

			sframe:SetScript("OnEnter",function(self)
				self.text:SetShadowColor(1,1,1,1)
				ELib.Tooltip.Show(self,nil,self.tooltip)
			end)
			sframe:SetScript("OnLeave",function(self)
				self.text:SetShadowColor(1,1,1,0)
				ELib.Tooltip:Hide()
			end)

			infoFrame = sframe
		end
		infoFrame.tooltip = text
		infoFrame:Show()
	end


	tab:SetScript("OnShow",function (self)
		BWInterfaceFrame.timeLineFrame:ClearAllPoints()
		BWInterfaceFrame.timeLineFrame:SetPoint("TOP",self,"TOP",0,-10)
		BWInterfaceFrame.timeLineFrame:Show()

		BWInterfaceFrame.GraphFrame:SetPoint("TOP",0,-105)
		if BWInterfaceFrame.tab.tabs[2].showGraphChk:GetChecked() then
			BWInterfaceFrame.GraphFrame:Show()
		end

		BWInterfaceFrame.report:Show()
		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			local currFightIDShort = GetFightID(CurrentFight,true)
			local disableUpdateVars = nil
			if currFightIDShort == self.lastFightShortID then
				disableUpdateVars = true
			end
			self.lastFightShortID = currFightIDShort

			HealingTab_Variables.graphCache = nil
			Graph_AutoUpdateStep()
			HealingTab_UpdatePage(true,nil,disableUpdateVars)
			self.lastFightID = BWInterfaceFrame.nowFightID

			HealingTab_AddSpecialInfo()
		elseif HealingTab_Variables.graphCache then
			HealingTab_ReloadGraph(unpack(HealingTab_Variables.graphCache))
		end
	end)
	tab:SetScript("OnHide",function (self)
		BWInterfaceFrame.timeLineFrame:Hide()
		BWInterfaceFrame.report:Hide()
		BWInterfaceFrame.GraphFrame:Hide()
	end)




	---- Death Tab
	tab = BWInterfaceFrame.tab.tabs[8]
	local deathTab = tab

	local DeathTab_Variables = {	--Use this because limit 200 local vars
		isEnemy = false,
		onlyPlayers = true,
		isBuffs = false,
		isDebuffs = false,
		isBlack = false,
		SetDeath_Last_Arg = nil,
		SetDeath_Last_Arg2 = nil,
		aurasBlackList = {
			[116956]=true,
			[167188]=true,
			[113742]=true,
			[6673]=true,
			[19740]=true,
			[109773]=true,
			[1126]=true,
			[21562]=true,
			[24907]=true,
			[166928]=true,
			[1459]=true,
			[93435]=true,
			[19506]=true,
			[167187]=true,
			[166916]=true,
			[166646]=true,
			[77747]=true,
			[67330]=true,
			[116781]=true,
			[24604]=true,
			[115921]=true,
			[51470]=true,
			[24932]=true,
			[117666]=true,
			[128432]=true,
			[155522]=true,
			[20217]=true,
			[469]=true,
			[57330]=true,
		}
	}

	local DeathTab_SetLine = nil

	function DeathTab_Variables:ConvertDataToOld(data)
		if not data.c then
			return data
		end
		local destTable = {data.h}
		local destTableLen = 1

		for i=data.c,1,-1 do
			local copyTable = data[i]
			if copyTable and copyTable.t then
				destTableLen = destTableLen + 1
				destTable[destTableLen] = {
					copyTable.t,
					copyTable.s,
					copyTable.ti,
					copyTable.sp,
					copyTable.a,
					copyTable.o,
					copyTable.sc,
					copyTable.b,
					copyTable.ab,
					copyTable.c,
					false,
					copyTable.h,
					copyTable.hm,
					copyTable.ia,
					copyTable.sm,
					copyTable.dm,
				}
			end
		end
		for i=deathMaxEvents,data.c+1,-1 do
			local copyTable = data[i]
			if copyTable and copyTable.t then
				destTableLen = destTableLen + 1
				destTable[destTableLen] = {
					copyTable.t,
					copyTable.s,
					copyTable.ti,
					copyTable.sp,
					copyTable.a,
					copyTable.o,
					copyTable.sc,
					copyTable.b,
					copyTable.ab,
					copyTable.c,
					false,
					copyTable.h,
					copyTable.hm,
					copyTable.ia,
					copyTable.sm,
					copyTable.dm,
				}
			end
		end

		return destTable
	end

	local function DeathTab_ClearPage()
		for i=1,#deathTab.lines do
			deathTab.lines[i]:Hide()
		end
		deathTab.scroll:SetNewHeight(0)
		deathTab.sourceDropDown:SetText(L.BossWatcherSelect)
	end

	local function DeathTab_SetDeath(_,arg,arg2)
		DeathTab_Variables.SetDeath_Last_Arg = arg
		DeathTab_Variables.SetDeath_Last_Arg2 = arg2
		ELib:DropDownClose()
		DeathTab_ClearPage()
		deathTab.sourceDropDown:SetText( arg2 )
		local _data = CurrentFight.deathLog[arg]
		_data = DeathTab_Variables:ConvertDataToOld(_data)
		local data = {}
		local minTime,maxTime = _data[1][3]-20,_data[1][3]
		local GUID = _data[1][2]
		local deathTime = nil
		wipe(reportData[8])
		reportData[8][1] = date("%H:%M:%S",_data[1][3])..date(" %Mm%Ss",timestampToFightTime(_data[1][3])).." "..GetGUID(_data[1][2])
		for i=1,#_data do
			if _data[i][3] then
				_data[i].P = i
				data[#data + 1] = _data[i]
				minTime = min(minTime,_data[i][3])
			end
		end
		if DeathTab_Variables.isBuffs or DeathTab_Variables.isDebuffs then
			local DataDefLen = #_data
			for i,auraData in ipairs(CurrentFight.auras) do
				if auraData[3] == GUID and auraData[1] >= minTime and auraData[1] <= maxTime and ((DeathTab_Variables.isBuffs and auraData[7]=='BUFF') or (DeathTab_Variables.isDebuffs and auraData[7]=='DEBUFF')) and (not DeathTab_Variables.isBlack or not DeathTab_Variables.aurasBlackList[ auraData[6] ]) then
					data[#data + 1] = {6,auraData[2],auraData[1],auraData[6],auraData[8],auraData[9],P=(DataDefLen + i)}
				end
			end
			sort(data,function(a,b) if a[3]==b[3] then return a.P<b.P else return a[3]>b[3] end end)
		end
		for i=1,#data do
			if data[i][1] then
				local _time = timestampToFightTime(data[i][3])
				local diffTime = deathTime and format("%.2f",_time - deathTime) or ""
				if diffTime == "0.00" then diffTime = "-0.00" end
				local timeText = date("%M:%S.",_time)..format("%03d",_time * 1000 % 1000)..(diffTime~="" and "  " or "")..diffTime
				if data[i][1] == 3 then
					local text = GetGUID(data[i][2])..GUIDtoText(" [%s]",data[i][2]) .. " ".. L.BossWatcherDeathDeath

					DeathTab_SetLine(i,timeText,text,0,0,0)

					reportData[8][#reportData[8] + 1] = "-0.0s "..L.BossWatcherDeathDeath

					deathTime = _time
				elseif data[i][1] == 4 then
					local spellName,_,spellTexture = GetSpellInfo(data[i][4])
					local sourceMarker = module.db.raidTargets[ data[i][15] or 0 ]
					local text = (sourceMarker and GetTargetIconText(sourceMarker) or "")..GetGUID(data[i][2])..GUIDtoText(" [%s]",data[i][2]).." "..L.BossWatcherInstaKill.." ".. L.BossWatcherByText .. " |T"..spellTexture..":0|t"..spellName

					DeathTab_SetLine(i,timeText,text,0,0,0,data[i][4])

					reportData[8][#reportData[8] + 1] = "-0.0s instakill "..GetSpellLink(data[i][4])

					deathTime = _time
				elseif data[i][1] == 5 then
					local spellName,_,spellTexture = GetSpellInfo(data[i][5])
					local text = format(GUILD_NEWS_FORMAT3,GetGUID(data[i][2])..GUIDtoText(" [%s]",data[i][2]),"|T"..spellTexture..":0|t"..spellName)

					DeathTab_SetLine(i,timeText,text,0,0,0,data[i][5])

					reportData[8][#reportData[8] + 1] = "-0.0s "..spellName

					deathTime = _time
				elseif data[i][1] == 1 then
					local spellName,_,spellTexture = GetSpellInfo(data[i][4])
					local name = GetGUID(data[i][2])..GUIDtoText(" [%s]",data[i][2])
					local overkill = data[i][6] and data[i][6] > 0 and " ("..L.BossWatcherDeathOverKill..":"..data[i][6]..")" or ""
					local blocked = data[i][8] and data[i][8] > 0 and " ("..L.BossWatcherDeathBlocked..":"..data[i][8]..")" or ""
					local absorbed = data[i][9] and data[i][9] > 0 and " ("..L.BossWatcherDeathAbsorbed..":"..data[i][9]..")" or ""
					local isCrit = data[i][10] and "*" or ""
					local school = " ("..GetSchoolName(data[i][7])..")"
					local amount = data[i][5] - (data[i][6] or 0)
					local HP = ""
					if data[i][12] and data[i][13]~=0 then
						HP = format("%d%% ",data[i][12]/data[i][13]*100)
						--HP = format("%d%% > %d%% ",min((data[i][12]+amount)/data[i][13],1)*100,data[i][12]/data[i][13]*100)
					end

					if ExRT.F.GetUnitTypeByGUID(data[i][2]) == 0 then
						name = "|c"..ExRT.F.classColorByGUID(data[i][2])..name.."|r"
					end

					local sourceMarker = module.db.raidTargets[ data[i][15] or 0 ]
					local destMarker = module.db.raidTargets[ data[i][16] or 0 ]

					local text = HP..(sourceMarker and GetTargetIconText(sourceMarker) or "")..name.." "..L.BossWatcherDeathDamage.." |T"..spellTexture..":0|t"..spellName.." "..L.BossWatcherDeathOn.." "..isCrit..amount..isCrit .. blocked .. absorbed .. overkill .. school

					DeathTab_SetLine(i,timeText,text,1,0,0,data[i][4])

					reportData[8][#reportData[8] + 1] = diffTime.."s."..HP.." -"..isCrit..amount..isCrit ..blocked .. absorbed .. overkill .." ["..GetGUID(data[i][2]).." - "..GetSpellLink(data[i][4]).."]"
				elseif data[i][1] == 2 then
					local spellName,_,spellTexture = GetSpellInfo(data[i][4])
					local name = GetGUID(data[i][2])..GUIDtoText(" [%s]",data[i][2])
					local overheal = data[i][6] and data[i][6] > 0 and " ("..L.BossWatcherDeathOverHeal..":"..data[i][6]..")" or ""
					local absorbed = data[i][9] and data[i][9] > 0 and " ("..L.BossWatcherDeathAbsorbed..":"..data[i][9]..")" or ""
					local isCrit = data[i][10] and "*" or ""
					local school = " ("..GetSchoolName(data[i][7])..")"
					local amount = data[i][5] - (data[i][6] or 0)
					local HP = ""
					if data[i][12] and data[i][13]~=0 then
						HP = format("%d%% ",data[i][12]/data[i][13]*100)
						--if not data[i][14] then HP = format("%d%% > ",(data[i][12]-amount)/data[i][13]*100) .. HP end
					end

					if ExRT.F.GetUnitTypeByGUID(data[i][2]) == 0 then
						name = "|c"..ExRT.F.classColorByGUID(data[i][2])..name.."|r"
					end

					local sourceMarker = module.db.raidTargets[ data[i][15] or 0 ]

					local text = HP .. (sourceMarker and GetTargetIconText(sourceMarker) or "")..name.." "..L.BossWatcherDeathHeal..(data[i][14] and (" ("..(ACTION_SPELL_MISSED_ABSORB and strlower(ACTION_SPELL_MISSED_ABSORB) or "absorbed")..")") or "").." |T"..spellTexture..":0|t"..spellName.." "..L.BossWatcherDeathOn.." "..isCrit..amount..isCrit .. absorbed .. overheal .. school

					DeathTab_SetLine(i,timeText,text,0,1,0,data[i][4])

					reportData[8][#reportData[8] + 1] = diffTime.."s."..HP.." +"..isCrit..amount..isCrit .. absorbed .. overheal .." ["..GetGUID(data[i][2]).." - "..GetSpellLink(data[i][4]).."]"
				elseif data[i][1] == 6 then
					local spellName,_,spellTexture = GetSpellInfo(data[i][4])
					local name = GetGUID(data[i][2])..GUIDtoText(" [%s]",data[i][2])
					local isApplied = (data[i][5]==1 or data[i][5]==3)

					if ExRT.F.GetUnitTypeByGUID(data[i][2]) == 0 then
						name = "|c"..ExRT.F.classColorByGUID(data[i][2])..name.."|r"
					end

					local sourceMarker = module.db.raidTargets[ data[i][15] or 0 ]

					local text = (sourceMarker and GetTargetIconText(sourceMarker) or "")..name.." "..(isApplied and L.BossWatcherDeathAuraAdd or L.BossWatcherDeathAuraRemove).." |T"..spellTexture..":0|t"..spellName
					if data[i][6] and data[i][6] > 1 then
						text = text .. "<"..data[i][6]..">"
					end

					DeathTab_SetLine(i,timeText,text,1,1,0,data[i][4])

					reportData[8][#reportData[8] + 1] = diffTime.."s. ["..GetGUID(data[i][2]).." "..(isApplied and "+" or "-")..GetSpellLink(data[i][4]).."]"
				end
				deathTab.lines[i]:Show()
			end
		end
		deathTab.scroll:SetNewHeight(#data * 18)
	end

	local function DeathTab_SetDeathList()
		local counter = 0
		for i,deathData in ipairs(CurrentFight.deathLog) do
			deathData = DeathTab_Variables:ConvertDataToOld(deathData)
			local header = deathData.header or deathData[1]
			local GUID = header[2]
			local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[GUID])
			local isPlayer = ExRT.F.GetUnitTypeByGUID(GUID) == 0
			if ((isFriendly and not DeathTab_Variables.isEnemy and (not DeathTab_Variables.onlyPlayers or isPlayer)) or (not isFriendly and DeathTab_Variables.isEnemy)) and (deathData[2] and deathData[2][1]) then
				counter = counter + 1
				local classColor = "|cffbbbbbb"
				if isPlayer then
					classColor = "|c"..ExRT.F.classColorByGUID(GUID)
				end
				local text = classColor..GetGUID(GUID)..GUIDtoText(" [%s]",GUID).."|r"
				local spellID = nil
				for j=1,#deathData do
					if deathData[j] ~= header and ((deathData[j][1] == 1 and deathData[j][6] > 0) or (deathData[j][1] == 4)) then
						local sourceColor = "|cffbbbbbb"
						if ExRT.F.GetUnitTypeByGUID(deathData[j][2]) == 0 then
							sourceColor = "|c"..ExRT.F.classColorByGUID(deathData[j][2])
						end
						local spellName,_,spellTexture = GetSpellInfo(deathData[j][4])
						text = text .." < " ..sourceColor .. GetGUID(deathData[j][2])..GUIDtoText(" [%s]",deathData[j][2]).."|r (|T"..spellTexture..":0|t"..spellName..")"
						spellID = deathData[j][4]
						break
					end
				end
				local cR,cG,cB = 0,0,0
				if header[1] == 5 then
					local spellName,_,spellTexture = GetSpellInfo(header[5])
					spellID = header[5]
					text = text .." (|T"..spellTexture..":0|t"..spellName..")"
					cR,cG,cB = .8,.8,0
				end

				local _time = timestampToFightTime( deathData[1][3] )
				local timeText = date("%M:%S.",_time)..format("%03d",_time * 1000 % 1000)

				local arrowPos = _time / GetFightLength(true)

				DeathTab_SetLine(counter,timeText,text,cR,cG,cB,spellID,i,arrowPos)
				deathTab.lines[counter]:Show()
			end
		end
		deathTab.scroll:SetNewHeight(counter * 18)
	end

	local function DeathTab_UpdateData()
		local list = deathTab.sourceDropDown.List
		wipe(list)
		for i,deathData in ipairs(CurrentFight.deathLog) do
			deathData = DeathTab_Variables:ConvertDataToOld(deathData)
			local header = deathData.header or deathData[1]
			local GUID = header[2]
			local isFriendly = ExRT.F.UnitIsFriendlyByUnitFlag2(CurrentFight.reaction[GUID])
			local isPlayer = ExRT.F.GetUnitTypeByGUID(GUID) == 0
			if ((isFriendly and not DeathTab_Variables.isEnemy and (not DeathTab_Variables.onlyPlayers or isPlayer)) or (not isFriendly and DeathTab_Variables.isEnemy)) and (deathData[2] and deathData[2][1]) then
				local classColor = ""
				if isPlayer then
					classColor = "|c"..ExRT.F.classColorByGUID(GUID)
				elseif isFriendly then
					classColor = "|cffbbbbbb"
				end
				local text = date("%M:%S"..(header[1] == 5 and "*" or "").." ",timestampToFightTime(header[3]))..classColor..GetGUID(GUID)..GUIDtoText(" [%s]",GUID)
				list[#list+1] = {
					text = text,
					arg1 = i,
					arg2 = text,
					func = DeathTab_SetDeath,
					hoverFunc = DamageTab_ShowArrow,
					leaveFunc = DamageTab_HideArrow,
					hoverArg = timestampToFightTime( header[3] ) / GetFightLength(true),
				}
			end
		end
	end

	local function DeathTab_UpdatePage()
		DeathTab_UpdateData()
		DeathTab_ClearPage()
		DeathTab_SetDeathList()
		DeathTab_Variables.SetDeath_Last_Arg = nil
	end

	tab.chkFriendlyOnlyPlayers = ELib:Radio(tab,L.BossWatcherFriendly.." ("..TUTORIAL_TITLE19..")",true):Point(15,-50):AddButton():OnClick(function(self) 
		DeathTab_Variables.isEnemy = false
		DeathTab_Variables.onlyPlayers = true
		self:SetChecked(true)
		deathTab.chkFriendly:SetChecked(false)
		deathTab.chkEnemy:SetChecked(false)
		DeathTab_UpdatePage()
	end)
	tab.chkFriendly = ELib:Radio(tab,L.BossWatcherFriendly):Point("LEFT",tab.chkFriendlyOnlyPlayers,"LEFT",200,0):AddButton():OnClick(function(self) 
		DeathTab_Variables.isEnemy = false
		DeathTab_Variables.onlyPlayers = false
		deathTab.chkFriendlyOnlyPlayers:SetChecked(false)
		self:SetChecked(true)
		deathTab.chkEnemy:SetChecked(false)
		DeathTab_UpdatePage()
	end)
	tab.chkEnemy = ELib:Radio(tab,L.BossWatcherHostile):Point("LEFT",tab.chkFriendly,"LEFT",200,0):AddButton():OnClick(function(self) 
		DeathTab_Variables.isEnemy = true
		DeathTab_Variables.onlyPlayers = false
		deathTab.chkFriendlyOnlyPlayers:SetChecked(false)
		deathTab.chkFriendly:SetChecked(false)
		self:SetChecked(true)
		DeathTab_UpdatePage()
	end)

	tab.sourceDropDown = ELib:DropDown(tab,250,20):Size(180):Point("TOPLEFT",tab.chkEnemy,"TOPLEFT",200,0):SetText(L.BossWatcherSelect):AddText(L.BossWatcherTarget..":")

	tab.showBuffsChk = ELib:Check(tab,L.BossWatcherDeathBuffsShow):Point(15,-75):OnClick(function (self)
		if self:GetChecked() then
			DeathTab_Variables.isBuffs = true
		else
			DeathTab_Variables.isBuffs = false
		end
		if DeathTab_Variables.SetDeath_Last_Arg then
			DeathTab_SetDeath(nil,DeathTab_Variables.SetDeath_Last_Arg,DeathTab_Variables.SetDeath_Last_Arg2)
		end
	end)

	tab.showDebuffsChk = ELib:Check(tab,L.BossWatcherDeathDebuffsShow):Point("LEFT",tab.showBuffsChk,"LEFT",200,0):OnClick(function (self)
		if self:GetChecked() then
			DeathTab_Variables.isDebuffs = true
		else
			DeathTab_Variables.isDebuffs = false
		end
		if DeathTab_Variables.SetDeath_Last_Arg then
			DeathTab_SetDeath(nil,DeathTab_Variables.SetDeath_Last_Arg,DeathTab_Variables.SetDeath_Last_Arg2)
		end
	end)

	tab.buffsblacklistChk = ELib:Check(tab,L.BossWatcherDeathBlacklist):Point("LEFT",tab.showDebuffsChk,"LEFT",200,0):OnClick(function (self)
		if self:GetChecked() then
			DeathTab_Variables.isBlack = true
		else
			DeathTab_Variables.isBlack = false
		end
		if DeathTab_Variables.SetDeath_Last_Arg then
			DeathTab_SetDeath(nil,DeathTab_Variables.SetDeath_Last_Arg,DeathTab_Variables.SetDeath_Last_Arg2)
		end
	end)

	local function DeathTab_LineOnEnter(self)
		if self.spellLink then
			GameTooltip:SetOwner(self, "ANCHOR_LEFT",120,0)
			GameTooltip:SetHyperlink(self.spellLink)
			GameTooltip:Show()
		end
		if self.text:IsTruncated() then
			ELib.Tooltip:Add(nil,{self.text:GetText()},false,true)
		end
		if self.arrowPos then
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:SetPoint("TOPLEFT",BWInterfaceFrame.timeLineFrame.timeLine,"TOPLEFT",BWInterfaceFrame.timeLineFrame.width*self.arrowPos,0)
			BWInterfaceFrame.timeLineFrame.timeLine.arrow:Show()
		end
	end
	local function DeathTab_LineOnLeave(self)
		GameTooltip_Hide()
		ELib.Tooltip:HideAdd()
		BWInterfaceFrame.timeLineFrame.timeLine.arrow:Hide()
	end
	local function DeathTab_LineOnClick(self,button)
		if not self.clickToLog then
			if button == "RightButton" then
				DeathTab_UpdatePage()
			end
			return
		end
		if button == "RightButton" then
			return
		end
		local name = self.text:GetText()
		DeathTab_SetDeath(nil,self.clickToLog,name:match("(.-)|r"),nil)
	end
	tab.scroll = ELib:ScrollFrame(tab):Size(835,508-25):Point("TOP",0,-105)
	tab.lines = {}
	function DeathTab_SetLine(i,textTime,textText,gradientR,gradientG,gradientB,spellID,clickToLog,arrowPos)
		local line = deathTab.lines[i]
		if not line then
			line = CreateFrame("Button",nil,deathTab.scroll.C)
			deathTab.lines[i] = line
			line:SetPoint("TOP",0,-(i-1)*18)
			line:SetSize(810,18)

			line.time = ELib:Text(line,"00:02."..format("%02d",i),12):Size(150,16):Point("LEFT",10,0):Color():Shadow()
			line.text = ELib:Text(line,"00:02."..format("%02d",i),12):Size(810-125-20,16):Point("LEFT",125,0):Color():Shadow()

			line.back = line:CreateTexture(nil, "BACKGROUND")
			line.back:SetAllPoints()
			line.back:SetColorTexture( 1, 1, 1, 1)
			line.back:SetGradient("HORIZONTAL",CreateColor(0,0,0,0), CreateColor(0,0,0,0))

			line:SetScript("OnEnter",DeathTab_LineOnEnter)
			line:SetScript("OnLeave",DeathTab_LineOnLeave)
			line:SetScript("OnClick",DeathTab_LineOnClick)

			line:RegisterForClicks("LeftButtonDown","RightButtonDown")
		end
		line.time:SetText(textTime)
		line.text:SetText(textText)
		line.back:SetGradient("HORIZONTAL",CreateColor(gradientR,gradientG,gradientB, 0.3), CreateColor(gradientR,gradientG,gradientB, 0))
		line.spellLink = spellID and "spell:"..spellID
		line.clickToLog = clickToLog
		line.arrowPos = arrowPos
		line:Show()
	end

	tab:SetScript("OnShow",function (self)
		BWInterfaceFrame.timeLineFrame:ClearAllPoints()
		BWInterfaceFrame.timeLineFrame:SetPoint("TOP",self,"TOP",0,-10)
		BWInterfaceFrame.timeLineFrame:Show()

		BWInterfaceFrame.report:Show()

		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			DeathTab_UpdatePage()
			self.lastFightID = BWInterfaceFrame.nowFightID
		end
	end)
	tab:SetScript("OnHide",function (self)
		BWInterfaceFrame.timeLineFrame:Hide()
		BWInterfaceFrame.report:Hide()
	end)





	---- Positions Tab
	tab = BWInterfaceFrame.tab.tabs[9]
	local posTab = tab

	local PositionsTab_UpdatePage = nil
	local PositionsTab_Variables = {	--Use this because limit 200 local vars
		DebuffsBlackList = {
			[160029] = true,	--Resurrecting; haven't CLEU event for removing
		},
		UnitsBlackList = {
			["boss1"]=true,
			["boss2"]=true,
			["boss3"]=true,
			["boss4"]=true,
			["boss5"]=true,
			["boss6"]=true,
			["target"]=true,
			["focus"]=true,
		},
		HPList = {},
	}
	BWInterfaceFrame.PositionsTab_Variables = PositionsTab_Variables

	PositionsTab_Variables.BossToMap = {}

	local function PositionsTab_UpdatePositions(segment)
		local time = ceil(segment / 2)
		local tab = posTab
		for i=1,40 do
			tab.raidFrames[i]:Update(segment)
		end
		for i=1,6 do
			tab.unitFrames[i]:Update(time)
		end

		local text = ""
		for destGUID,destData in pairs(PositionsTab_Variables.HPList) do
			local curHP = destData.res[time]

			if curHP and curHP ~= 0 and curHP ~= destData.maxhp and (not destData.maxhp or curHP < destData.maxhp) then
				local color1,color2
				if destData.lastSeen and time > destData.lastSeen then
					color1,color2 = "|cffaaaaaa", "|r"
				end
				text = text .. (color1 or "") .. (destData.mark[time] and GetTargetIconText(destData.mark[time]) or "") .. GetGUID(destGUID) .. GUIDtoText(" (%s)",destGUID) .. " "..(destData.maxhp and (destData.maxhp-curHP).."/"..destData.maxhp..format(" <%.1f%%>",(1-curHP/destData.maxhp)*100) or "-"..curHP) .. (color2 or "") .. "|n"
			end
		end
		tab.scroll.mobsText:SetText(text)
	end

	tab.timeSlider = ELib:Slider(tab,L.BossWatcherPositionsSlider):Size(800):Point("TOP",0,-20):Range(1,1):OnChange(function (self,value)
		value = ExRT.F.Round(value)

		local time = floor(value / 2)
		self.tooltipText = format("%d:%02d",time / 60,time % 60)
		self:tooltipReload(self)

		PositionsTab_UpdatePositions(value)
	end)
	tab.timeSlider.tooltipText = "0:00"
	tab.timeSlider:SetScript("OnMinMaxChanged",function (self)
		local _min,_max = self:GetMinMaxValues()
		self.Low:SetText("0:00")
		_max = max(1,_max / 2)
		self.High:SetText(format("%d:%02d",_max / 60,_max % 60))
	end)
	tab.timeSlider:SetObeyStepOnDrag(true)

	tab.scroll = ELib:ScrollFrame(tab):Size(835,540):Point("TOP",0,-50):Height(540)
	tab.scroll.ScrollBar:Hide()
	tab.scroll.C:SetWidth( tab.scroll:GetWidth() - 4 )

	tab.player = {}
	tab.scroll.player = tab.player

	local function PositionsTab_RaidFrame_UpdateHP(self,segment)
		if not self.Unit then
			self:Hide()
			return
		end
		local sec = ceil(segment / 2)
		local data = CurrentFight.graphData[sec]
		if not data then
			self:Hide()
			return
		end
		self:Show()

		local hpNow = data[self.Unit] and data[self.Unit].health or 0
		local hpMax = data[self.Unit] and data[self.Unit].hpmax or 0
		if hpMax == 0 or hpNow == 0 then
			self.hp:Hide()
		else
			self.hp:Show()
			self.hp:SetWidth(max(hpNow / hpMax * self.WIDTH,1))
		end

		local data = self.debuffsData and self.debuffsData[segment]
		if not data then
			for i=1,#self.debuffs do
				self.debuffs[i]:Hide()
			end
		else
			for i=1,#data do
				if i > #self.debuffs then
					break
				end
				local spellID = floor( data[i] )
				local texture = GetSpellTexture(data[i])
				self.debuffs[i]:Texture(texture)
				self.debuffs[i].spellID = spellID
				local timeLeft = (data[i] % 1) * 1000
				self.debuffs[i].timeLeft = floor(timeLeft)
				self.debuffs[i]:Show()
			end
			for i=#data+1,#self.debuffs do
				self.debuffs[i]:Hide()
			end
		end

		local data = CurrentFight.graphData[sec]
		local powerNow = data[self.Unit] and data[self.Unit].power or 0
		local powerMax = data[self.Unit] and data[self.Unit].pmax or 0
		if powerMax == 0 then
			self.power:Hide()
			self.power_text:SetText("")
		else
			self.power:SetShown(powerNow ~= 0)
			self.power:SetWidth(max(0,min(powerNow / powerMax * self.WIDTH,self.WIDTH)))
			if powerMax >= 1000 then
				self.power_text:SetFormattedText("%.1f%%",powerNow/powerMax*100)
			else
				self.power_text:SetFormattedText("%d/%d",powerNow,powerMax)
			end
		end
	end
	local function PositionsTab_UnitFrame_UpdateHP(self,sec)
		if not self.Unit then
			self:Hide()
			return
		end
		local data = CurrentFight.graphData[sec]
		if not data then
			self:Hide()
			return
		end

		self.text:SetText(data[self.Unit] and data[self.Unit].name or self.Unit)
		local hpNow = data[self.Unit] and data[self.Unit].health or 0
		local hpMax = data[self.Unit] and data[self.Unit].hpmax or 0
		if hpMax == 0 then
			self:Hide()
			return
		end
		self:Show()
		if hpMax == 0 or hpNow == 0 then
			self.hp:Hide()
			return
		end
		self.hp:Show()
		self.hp:SetWidth(max(hpNow / hpMax * self.WIDTH,1))

		self.hp_text:SetFormattedText("%.1f",hpNow / hpMax * 100)

		local powerNow = data[self.Unit] and data[self.Unit].power or 0
		local powerMax = data[self.Unit] and data[self.Unit].pmax or 0
		if powerMax == 0 then
			self.power:Hide()
			self.power_text:SetText("")
		else
			self.power:SetShown(powerNow ~= 0)
			self.power:SetWidth(max(0,min(powerNow / powerMax * self.WIDTH,self.WIDTH)))
			if powerMax >= 1000 then
				self.power_text:SetFormattedText("%.1f%%",powerNow/powerMax*100)
			else
				self.power_text:SetFormattedText("%d/%d",powerNow,powerMax)
			end
		end
	end

	local function PositionsTab_RaidFrame_DebuffOnEnter(self)
		posTab.scroll.disableTooltip = true
		if self.spellID then
			ELib.Tooltip.Link(self,"spell:"..self.spellID)
			if self.stacks then
				GameTooltip:AddLine(L.BossWatcherBuffsAndDebuffsTooltipCountText..": "..self.stacks)
				GameTooltip:Show()
			end
			if self.timeLeft then
				GameTooltip:AddLine(format(PET_TIME_LEFT_SECONDS,self.timeLeft + 1))
				GameTooltip:Show()
			end
		end
	end
	local function PositionsTab_RaidFrame_DebuffOnLeave(self)
		posTab.scroll.disableTooltip = nil
		ELib.Tooltip:Hide()
	end

	tab.raidFrames = {}
	for i=1,8 do
		for j=1,5 do
			local frame = CreateFrame("Button",nil,tab.scroll)
			tab.raidFrames[(i-1)*5+j] = frame
			local WIDTH,HEIGHT = 100,35
			frame.WIDTH = WIDTH
			frame:SetSize(WIDTH,HEIGHT)
			frame:SetPoint("BOTTOMLEFT",tab.scroll,5+(i-1)*(WIDTH+3),5+(j-1)*(HEIGHT+3))
			frame.text = ELib:Text(frame,UnitName('player'),12):Size(WIDTH-10,14):Point("BOTTOMLEFT",5,6):Left():Color()
			frame.text:SetDrawLayer("ARTWORK", 0)

			ELib:Border(frame,1,0,0,0,1,1)

			frame.back = frame:CreateTexture(nil, "BACKGROUND",nil,-5)
			frame.back:SetSize(WIDTH,HEIGHT)
			frame.back:SetPoint("LEFT",0,0)
			frame.back:SetColorTexture(.05,.05,.05,1)

			frame.hp = frame:CreateTexture(nil, "BACKGROUND",nil,0)
			frame.hp:SetSize(WIDTH,HEIGHT)
			frame.hp:SetPoint("LEFT",0,0)
			frame.hp:SetColorTexture(.3,.3,.3,1)

			frame.power = frame:CreateTexture(nil, "BACKGROUND",nil,3)
			frame.power:SetSize(WIDTH,3)
			frame.power:SetPoint("BOTTOMLEFT",0,0)
			frame.power:SetColorTexture(.3,.3,1,1)

			frame.power_text = ELib:Text(frame,"99%",8):Point("BOTTOMRIGHT",-2,1):Right():Color()
			frame.power_text:SetDrawLayer("ARTWORK", 0)

			frame.Update = PositionsTab_RaidFrame_UpdateHP

			frame.debuffs = {}
			for i=1,6 do
				frame.debuffs[i] = ELib:Frame(frame):Point("TOP",frame,"TOPLEFT",7 + (i-1)*(14+1),1):Size(14,14):Texture(GetSpellTexture(25771),nil):TexturePoint('x')
				frame.debuffs[i]:SetScript("OnEnter",PositionsTab_RaidFrame_DebuffOnEnter)
				frame.debuffs[i]:SetScript("OnLeave",PositionsTab_RaidFrame_DebuffOnLeave)
			end
			frame:Hide()
		end
	end

	tab.unitFrames = {}
	for i=1,6 do
		local frame = CreateFrame("Button",nil,tab.scroll)
		tab.unitFrames[i] = frame
		local WIDTH,HEIGHT = 195,30
		frame:SetSize(WIDTH,HEIGHT)
		frame.WIDTH = WIDTH
		frame:SetPoint("TOPLEFT",tab.scroll,5,-50-(i-1)*(HEIGHT+3))
		frame.text = ELib:Text(frame,UnitName('player'),11):Size(WIDTH-40,20):Point("LEFT",2,0):Color()
		frame.text:SetDrawLayer("ARTWORK", 0)

		frame.hp_text = ELib:Text(frame,"99.9%",10):Size(36,20):Point("TOPRIGHT",-2,-3):Right():Color()
		frame.hp_text:SetDrawLayer("ARTWORK", 0)

		ELib:Border(frame,1,0,0,0,1,1)

		frame.back = frame:CreateTexture(nil, "BACKGROUND",nil,-5)
		frame.back:SetSize(WIDTH,HEIGHT)
		frame.back:SetPoint("LEFT",0,0)
		frame.back:SetColorTexture(.05,.05,.05,1)

		frame.hp = frame:CreateTexture(nil, "BACKGROUND",nil,0)
		frame.hp:SetSize(WIDTH,HEIGHT)
		frame.hp:SetPoint("LEFT",0,0)
		frame.hp:SetColorTexture(.3,.3,.3,1)

		frame.power = frame:CreateTexture(nil, "BACKGROUND",nil,3)
		frame.power:SetSize(WIDTH,4)
		frame.power:SetPoint("BOTTOMLEFT",0,0)
		frame.power:SetColorTexture(.3,.3,1,1)

		frame.power_text = ELib:Text(frame,"99/120",8):Point("BOTTOMRIGHT",-2,1):Right():Color()
		frame.power_text:SetDrawLayer("ARTWORK", 0)

		frame.Update = PositionsTab_UnitFrame_UpdateHP

		frame:Hide()
	end

	tab.scroll.mobsText = ELib:Text(tab.scroll,"",10):Size(400,0):Point("TOPRIGHT",-5,-3):Left():Color()


	function PositionsTab_UpdatePage()
		local tab = posTab
		local positionsData = CurrentFight.positionsData
		local minX,maxX,minY,maxY = 0,1,0,1
		local knownMap = nil

		local encounterID = CurrentFight.encounterID
		for i=1,#tab.player do
			tab.player[i]:Hide()
		end
		local dotCount = 0
		local raidFrames = {}
		local graphData = CurrentFight.graphData
		if graphData and graphData[1] then
			for name,data in pairs(graphData[1]) do
				if not PositionsTab_Variables.UnitsBlackList[name] then
					local unitGUID = ExRT.F.table_find2(CurrentFight.raidguids,name)
					local cR,cG,cB = .8,.8,.8
					if unitGUID then
						local class = select(2,GetPlayerInfoByGUID(unitGUID))
						if class then
							cR,cG,cB = ExRT.F.classColorNum(class)
						end
					end

					raidFrames[#raidFrames + 1] = {name,cR,cG,cB}
				end
			end
		end
		sort(raidFrames,function(a,b) return a[1]<b[1] end)
		--tinsert(raidFrames,1,{"target",.7,.7,.7})
		if graphData and graphData[1] then
			for i=1,#raidFrames do
				tab.raidFrames[i].Unit = raidFrames[i][1]
				tab.raidFrames[i].text:SetTextColor(raidFrames[i][2],raidFrames[i][3],raidFrames[i][4],1)
				tab.raidFrames[i].text:SetText(raidFrames[i][1])
				tab.raidFrames[i]:Update(1)

				--- debuffs list
				local debuffsData = {}
				tab.raidFrames[i].debuffsData = debuffsData
				local guid = nil
				for guidNow,nameNow in pairs(CurrentFight.raidguids) do
					if nameNow == raidFrames[i][1] then
						guid = guidNow
						break
					end
				end
				if guid then
					local current = {}
					local aurasData = CurrentFight.auras
					for k=1,#aurasData do
						local aurasLine = aurasData[k]
						if aurasLine[3] == guid and aurasLine[7] == 'DEBUFF' then
							local time_ = floor( timestampToFightTime( aurasLine[1] ) * 2 ) + 1
							local spellID = aurasLine[6]
							if not PositionsTab_Variables.DebuffsBlackList[ spellID ] then
								if aurasLine[8] ~= 2 then
									current[ spellID ] = current[ spellID ] or time_
								elseif aurasLine[8] == 2 then
									local start = current[ spellID ] or 1
									for l = start, time_ do
										debuffsData[l] = debuffsData[l] or {}
										tinsert(debuffsData[l],spellID+((time_ - l)%1000)/1000)
									end
									current[ spellID ] = nil
								end
							end
						end
					end
					local positionsData_len = #positionsData
					for spellID,start in pairs(current) do
						for j=start, positionsData_len do
							debuffsData[j] = debuffsData[j] or {}
							tinsert(debuffsData[j],spellID+((positionsData_len - j)%1000)/1000)
						end
					end

					tab.raidFrames[i]:Update(1)
				end
			end
			for i=#raidFrames+1,40 do
				tab.raidFrames[i].Unit = nil
				tab.raidFrames[i]:Update()
			end
			for i=1,6 do
				tab.unitFrames[i].Unit = "boss"..i
				tab.unitFrames[i]:Update(1)
			end
		else
			for i=1,40 do
				tab.raidFrames[i].Unit = nil
				tab.raidFrames[i]:Update()
			end
			for i=1,6 do
				tab.unitFrames[i].Unit = nil
				tab.unitFrames[i]:Update()
			end
		end

		tab.timeSlider:SetMinMaxValues(1,max(.5,#graphData)*2)

		tab.scroll.C:SetScale(1)
		tab.scroll.scrollH = 0
		tab.scroll.scrollV = 0
		tab.scroll:SetHorizontalScroll(0)
		tab.scroll:SetVerticalScroll(0)
		for i=1,#tab.player do
			tab.player[i].SubDot:SetScale(1)
		end

		local HPList = PositionsTab_Variables.HPList
		wipe(PositionsTab_Variables.HPList)

		for destGUID,destData in pairs(CurrentFight.damage) do
			for destReaction,destReactData in pairs(destData) do
				local isEnemy = false
				if GetUnitInfoByUnitFlagFix(destReaction,2) == 512 then
					isEnemy = true
				end
				if isEnemy then
					for sourceGUID,sourceData in pairs(destReactData) do
						local source = sourceGUID
						local dest = destGUID

						local mobData = HPList[dest]
						if not mobData then
							mobData = {
								maxhp = CurrentFight.maxHP[dest],
								damage = {},
								res = {},
								mark = {},
							}
							HPList[dest] = mobData
						end

						for spellID,spellSegments in pairs(sourceData) do
							for segment,spellAmount in pairs(spellSegments) do
								mobData.damage[segment] = (mobData.damage[segment] or 0) + spellAmount.amount - spellAmount.overkill
							end
						end
					end
				end
			end
		end
		for sourceGUID,sourceData in pairs(CurrentFight.heal) do
			for destGUID,destData in pairs(sourceData) do
				for destReact,destReactData in pairs(destData) do
					local isEnemy = not ExRT.F.UnitIsFriendlyByUnitFlag2(destReact)
					if isEnemy then
						local source = sourceGUID
						local dest = destGUID

						local mobData = HPList[dest]
						if not mobData then
							mobData = {
								maxhp = CurrentFight.maxHP[dest],
								damage = {},
								res = {},
								mark = {},
							}
							HPList[dest] = mobData
						end

						for spellID,spellSegments in pairs(destReactData) do
							for segment,spellAmount in pairs(spellSegments) do
								mobData.damage[segment] = (mobData.damage[segment] or 0) - (spellAmount.amount - spellAmount.over - spellAmount.absorbs)
							end
						end
					end
				end
			end
		end

		for GUID,dataGUID in pairs(CurrentFight.cast) do
			for i,PlayerCastData in ipairs(dataGUID) do
				local mark, destData
				if HPList[dataGUID] then
					mark = PlayerCastData[6]
					destData = HPList[dataGUID]
				elseif HPList[ PlayerCastData[4] ] then
					mark = PlayerCastData[5]
					destData = HPList[ PlayerCastData[4] ]
				end
				if mark then
					local t = ceil(CurrentFight.segments[ PlayerCastData.s ].t - CurrentFight.encounterStart)
					destData.mark[t] = module.db.raidTargets[ mark ] or 0
				end
			end
		end
		for destGUID,destData in pairs(HPList) do
			local dmgList = {}
			for seg,dmg in pairs(destData.damage) do
				dmgList[#dmgList+1] = {seg,dmg}
			end
			sort(dmgList,function(a,b)return a[1]<b[1] end)
			local now = 0
			for i,d in pairs(dmgList) do
				if not destData.seen then
					destData.seen = d[1]
				end
				now = now + d[2]
				destData.res[ d[1] ] = now
				destData.lastSeen = d[1]
			end
			local last = ceil(CurrentFight.segments[#CurrentFight.segments].t - CurrentFight.encounterStart)
			local prev = nil
			for i=0,last do
				if i < destData.seen then
					destData.res[i] = 0
				elseif i <= (destData.lastSeen + 10) then
					if destData.res[i] then
						prev = destData.res[i]
					else
						destData.res[i] = prev
					end
				end
			end

			local prev,first = nil
			for i=0,last do
				if destData.mark[i] then
					prev = destData.mark[i]
					if not first then
						for j=0,i-1 do
							destData.mark[j] = prev
						end
						first = true
					end
				else
					destData.mark[i] = prev
				end
			end
			for i=0,last do
				if destData.mark[i] == 0 then
					destData.mark[i] = nil
				end
			end
		end

		tab.timeSlider:SetValue(1)
		PositionsTab_UpdatePositions(1)
	end

	tab:SetScript("OnShow",function (self)
		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			PositionsTab_UpdatePage()
			self.lastFightID = BWInterfaceFrame.nowFightID
		end
	end)


	--- Others tab
	tab = BWInterfaceFrame.tab.tabs[10]
	local otherTab = tab

	tab.DecorationLine = ELib:DecorationLine(tab,true):Point("TOPLEFT",tab,"TOPLEFT",3,-8):Point("RIGHT",tab,-3,0):Size(0,20)

	tab.tab = ELib:Tabs(tab,0,
		TRACKING,
		L.BossWatcherDamageTaken
	):Size(865,600):Point("TOP",0,-29):SetTo(1)

	tab.tab:SetBackdropBorderColor(0,0,0,0)
	tab.tab:SetBackdropColor(0,0,0,0)


	---- Tracking
	tab = BWInterfaceFrame.tab.tabs[10].tab.tabs[1]
	local trackingTab = tab

	local TrackingTab_Variables = {
		EncounterOrder = {
			1778,1785,1787,1798,1786,1783,1788,1794,1777,1800,1784,1795,1799,
			1853,1841,1873,1854,1876,1877,1864,
			1958,1962,2008,
			1849,1865,1867,1871,1862,1886,1842,1863,1872,1866,
		},
	}

	tab.DecorationLine = ELib:DecorationLine(tab,true):Point("TOPLEFT",tab,"TOPLEFT",3,-9):Point("RIGHT",tab,-3,0):Size(0,20)

	tab.headerTab = ELib:Tabs(tab,0,
		L.BossWatcherTabPlayersSpells,
		L.BossWatcherTabSettings
	):Size(850,555):Point("TOP",0,-29):SetTo(1)
	tab.headerTab:SetBackdropBorderColor(0,0,0,0)
	tab.headerTab:SetBackdropColor(0,0,0,0)

	tab.spellsList = ELib:ScrollList(tab.headerTab.tabs[1]):Size(190,510):Point(10,-15)
	tab.targetsList = ELib:ScrollTableList(tab.headerTab.tabs[1],80,0):Size(625,510):Point("TOPLEFT",tab.spellsList,"TOPRIGHT",10,0)

	tab.spellsList.D = {}

	function tab.spellsList:UpdateAdditional()
		for i=1,#self.List do
			self.List[i]:SetEnabled(true)
		end
	end

	function tab.spellsList:SetListValue(index)
		wipe(trackingTab.targetsList.L)

		local L = trackingTab.targetsList.L

		local prevTime,prevTimeRow = nil

		local spellID = self.D[index]
		for i,trackingData in ipairs(CurrentFight.tracking) do
			if trackingData[6] == spellID then
				local time = timestampToFightTime(trackingData[1])
				local sourceGUID,destGUID = trackingData[2],trackingData[4]
				local sourceRaidTarget,destRaidTarget = nil

				if spellID == 185008 then	--Archimonde: Unleashed Torment
					for _,auraData in ipairs(CurrentFight.auras) do
						if auraData[2] == sourceGUID and auraData[6] == 184964 then
							sourceGUID = auraData[3]
							break
						end 
					end
				elseif spellID == 190399 then	--Archimonde: Mark of the Legion
					for _,auraData in ipairs(CurrentFight.auras) do
						if auraData[6] == 187050 and auraData[8] == 2 and abs(trackingData[1]-auraData[1])<0.4 then
							sourceGUID = auraData[3]
							break
						end 
					end
				elseif spellID == 182011 then	--Mannoroth: Empowered Mannoroth's Gaze
					local newSourceGUID = nil
					for _,auraData in ipairs(CurrentFight.auras) do
						if auraData[6] == 182006 and auraData[8] == 2 and auraData[1]>trackingData[1] then
							break
						elseif auraData[6] == 182006 and auraData[8] == 2 and auraData[1]<=trackingData[1] then
							newSourceGUID = auraData[3]
						end
					end
					sourceGUID = newSourceGUID or sourceGUID
				elseif spellID == 181617 then	--Mannoroth: Mannoroth's Gaze
					local newSourceGUID = nil
					for _,auraData in ipairs(CurrentFight.auras) do
						if auraData[6] == 181597 and auraData[8] == 2 and auraData[1]>trackingData[1] then
							break
						elseif auraData[6] == 181597 and auraData[8] == 2 and auraData[1]<=trackingData[1] then
							newSourceGUID = auraData[3]
						end
					end
					sourceGUID = newSourceGUID or sourceGUID
				elseif spellID == 180161 then	--Tyrant Velhari: Edict of Condemnation
					local newSourceGUID = nil
					for _,auraData in ipairs(CurrentFight.auras) do
						if auraData[6] == 185241 and auraData[8] == 1 and auraData[1]<=trackingData[1] then
							newSourceGUID = auraData[3]
						elseif auraData[6] == 185241 and auraData[8] == 1 and auraData[1]>trackingData[1] then
							break
						end
					end
					sourceGUID = newSourceGUID or sourceGUID
				elseif spellID == 198099 then	--Ursoc: Barreling Momentum
					local newSourceGUID = nil
					for _,auraData in ipairs(CurrentFight.auras) do
						if auraData[6] == 198006 and auraData[8] == 1 and auraData[1]<=trackingData[1] then
							newSourceGUID = auraData[3]
						elseif auraData[1]>trackingData[1] then
							break
						end
					end
					sourceGUID = newSourceGUID or sourceGUID
				elseif spellID == 228162 then	--Odyn: Shield of Light
					local newSourceGUID = nil
					if CurrentFight.cast[sourceGUID] then
						for _,castData in ipairs(CurrentFight.cast[sourceGUID]) do
							if castData[2] == 228162 and castData[3] == 1 and castData[1]<=trackingData[1] then
								newSourceGUID = castData[4]
							elseif castData[1]>trackingData[1] then
								break
							end
						end
					end
					sourceGUID = newSourceGUID or sourceGUID

				end

				sourceRaidTarget = module.db.raidTargets[ trackingData[3] or 0 ]
				destRaidTarget = module.db.raidTargets[ trackingData[5] or 0 ]

				local diff = prevTime and (time-prevTime) or 999
				if diff <= 0.05 then
					prevTimeRow = prevTimeRow or prevTime
				else
					if prevTimeRow then
						for j=#L,1,-1 do
							if L[j][3] and L[j][3] < prevTimeRow then
								tinsert(L,j+1,{" "," "})
								break
							elseif L[j][1] == " " then
								break
							end
						end
						L[#L+1] = {" "," "}
					end
					prevTimeRow = nil
				end
				prevTime = time

				--{timestamp,sourceGUID,sourceFlags2,destGUID,destFlags2,spellID,amount,overkill,school,blocked,absorbed,critical,multistrike,missType}
				local amountString
				if not trackingData[14] then
					local overkill = trackingData[8] and trackingData[8] > 0 and " ("..ExRT.L.BossWatcherDeathOverKill..": "..ExRT.F.shortNumber(trackingData[8])..") " or ""
					local blocked = trackingData[10] and trackingData[10] > 0 and " ("..ExRT.L.BossWatcherDeathBlocked..": "..ExRT.F.shortNumber(trackingData[10])..") " or ""
					local absorbed = trackingData[11] and trackingData[11] > 0 and " ("..ExRT.L.BossWatcherDeathAbsorbed..": "..ExRT.F.shortNumber(trackingData[11])..") " or ""

					amountString = (trackingData[12] and "*" or "")..ExRT.F.shortNumber(trackingData[7] - trackingData[8])..(trackingData[12] and "*" or "").." "..overkill..blocked..absorbed
					amountString = strtrim(amountString)
				else
					amountString = "~"..trackingData[13].."~"
				end

				L[#L+1] = {date("%M:%S.", time)..format("%03d",time%1*1000),(sourceRaidTarget and GetTargetIconText(sourceRaidTarget) or "").."|c".. ExRT.F.classColorByGUID(sourceGUID)..GetGUID(sourceGUID)..GUIDtoText(" [%s]",sourceGUID).."|r > "..(destRaidTarget and GetTargetIconText(destRaidTarget) or "").."|c".. ExRT.F.classColorByGUID(destGUID)..GetGUID(destGUID)..GUIDtoText(" [%s]",destGUID).."|r: "..amountString,time}
			end
		end
		local prevTimeText = nil
		for i=1,#L do
			if L[i][1] == prevTimeText then
				prevTimeText = L[i][1]
				L[i][1] = ""
			else
				prevTimeText = L[i][1]
			end
		end

		trackingTab.targetsList:Update()
	end

	function tab.targetsList:HoverListValue(isHover,index,hoveredObj)
		if not isHover then
			GameTooltip_Hide()
		else
			if hoveredObj.text2:IsTruncated() then
				GameTooltip:SetOwner(self,"ANCHOR_CURSOR")
				GameTooltip:AddLine(hoveredObj.text2:GetText() )
				GameTooltip:Show()
			end
		end
	end

	local function UpdateTrackingPage()
		wipe(trackingTab.targetsList.L)
		wipe(trackingTab.spellsList.L)
		wipe(trackingTab.spellsList.D)
		local L,D = trackingTab.spellsList.L,trackingTab.spellsList.D

		for i,trackingData in ipairs(CurrentFight.tracking) do
			if not ExRT.F.table_find(D,trackingData[6]) then
				D[#D+1] = trackingData[6]
			end
		end

		for i=1,#D do
			local spellName,_,spellTexture = GetSpellInfo(D[i])
			L[i] = "|T"..spellTexture..":0|t "..spellName
		end 

		trackingTab.spellsList:Update()
		trackingTab.targetsList:Update()
	end

	tab.optionsSpellsList = ELib:ScrollTableList(tab.headerTab.tabs[2],80,20,0,20):Size(650,400):Point(10,-15)

	local function UpdateTrackingOptionsPage()
		wipe(trackingTab.optionsSpellsList.L)
		local L = trackingTab.optionsSpellsList.L
		for spellID,encounterID in pairs(var_trackingDamageSpells) do
			local spellName,_,spellTexture = GetSpellInfo(spellID)
			spellName = spellName or '???'
			spellTexture = spellTexture or "Interface\\Icons\\INV_MISC_QUESTIONMARK"
			local encounterName = nil
			if type(encounterID)=='number' then
				encounterName = ExRT.L.bossName[encounterID]
			end
			L[#L+1] = {spellID,"|T"..spellTexture..":0|t",(encounterName and encounterName..": " or "")..spellName,module.db.def_trackingDamageSpells[spellID] and "" or "|TInterface\\AddOns\\"..GlobalAddonName.."\\media\\DiesalGUIcons16x256x128:16:16:0:0:256:128:128:144:64:80|t",type(encounterID)=='number' and ExRT.F.table_find(TrackingTab_Variables.EncounterOrder,encounterID) or -1}
		end
		sort(L,function(a,b) if a[5]==b[5] then return a[1]<b[1] else return a[5]>b[5] end end)
		trackingTab.optionsSpellsList:Update()
	end
	function tab.optionsSpellsList:AdditionalLineClick()
		local x,y = ExRT.F.GetCursorPos(self)
		local pos = self:GetWidth()-x
		if pos <= 25 and pos > 7 then
			local parent = self.mainFrame
			local i = parent.selected
			if parent.L[i][4] ~= "" then
				local spellID = parent.L[i][1]
				VMRT.BossWatcher.trackingDamageSpells[ spellID ] = nil
				UpdateTrackingDamageSpellsTable()
				UpdateTrackingOptionsPage()
			end
		end
	end
	UpdateTrackingOptionsPage()

	tab.optionsEditAddSpell = ELib:Edit(tab.headerTab.tabs[2],6,true):Size(200,20):Point("TOPLEFT",tab.optionsSpellsList,"BOTTOMLEFT",0,-5)
	tab.optionsButtonAddSpell = ELib:Button(tab.headerTab.tabs[2],L.cd2TextAdd):Size(150,20):Point("LEFT",tab.optionsEditAddSpell,"RIGHT",5,0):OnClick(function()
		local tab = trackingTab
		local spellID = tonumber(tab.optionsEditAddSpell:GetText())
		if not spellID then
			return
		end
		tab.optionsEditAddSpell:SetText("")

		VMRT.BossWatcher.trackingDamageSpells[ spellID ] = true

		UpdateTrackingDamageSpellsTable()
		UpdateTrackingOptionsPage()
	end)


	tab:SetScript("OnShow",function (self)
		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			self.lastFightID = BWInterfaceFrame.nowFightID
			UpdateTrackingPage()
		end
	end)


	---- Tracking
	tab = BWInterfaceFrame.tab.tabs[10].tab.tabs[2]
	local damageTakenTab = tab

	local DamageTakenTab_Variables = {
		graph_step = 5,
		check_byrole = true,
		check_absorbs = false,
		check_enemy = false,
	}

	tab.graph = ELib:GraphCol(tab):Point("TOP",0,-35):Size(780,400)
	tab.graph.TooltipText = function(self,tip)
		local t = tip.dataX
		local val = tip.dataY

		if val >= 1000000 then
			val = format("%.2fm",val/1000000)
		elseif val >= 1000 then
			val = format("%dk",val/1000)
		else
			val = format("%d",val)
		end

		return (tip.dataT and tip.dataT.."\n" or "") .. format("%d:%02d",t / 60,t % 60) .. "\n" ..val
	end
	tab.graph.TextX = function(self,x,data)
		x = data.x
		return format("%d:%02d",x / 60,x % 60)
	end
	tab.graph.media.colors = {
		{1,.3,0,1},
		{0.5,.8,0,1},
		{1,.3,0,.55}
	}

	tab.graph.stepSlider = ELib:Slider(tab.graph,"",true):Point("RIGHT",tab.graph,"LEFT",-10,0):Size(100):Range(1,60):SetTo(DamageTakenTab_Variables.graph_step):OnChange(function(self)
		local step = floor(self:GetValue() + 0.5)
		if DamageTakenTab_Variables.graph_step == step then
			return
		end
		DamageTakenTab_Variables.graph_step = step

		self:Tooltip(L.BossWatcherGraphicsStep.."\n"..step)
		self:tooltipReload()

		damageTakenTab:Update()
	end):Tooltip(L.BossWatcherGraphicsStep.."\n"..DamageTakenTab_Variables.graph_step)

	tab.chkByRole = ELib:Radio(tab,"Non-tanks/Tanks",DamageTakenTab_Variables.check_byrole):Point("TOPLEFT",tab.graph,"BOTTOMLEFT",0,-15):AddButton():OnClick(function(self) 
		damageTakenTab.chkAbsorbs:SetChecked(false)
		damageTakenTab.chkEnemies:SetChecked(false)
		self:SetChecked(true)

		DamageTakenTab_Variables.check_byrole = true
		DamageTakenTab_Variables.check_absorbs = false
		DamageTakenTab_Variables.check_enemy = false

		damageTakenTab:Update()
	end)
	tab.chkAbsorbs = ELib:Radio(tab,"Non-absorbed/Absorbed",DamageTakenTab_Variables.check_absorbs):Point("TOPLEFT",tab.chkByRole,"BOTTOMLEFT",0,-5):AddButton():OnClick(function(self) 
		damageTakenTab.chkByRole:SetChecked(false)
		damageTakenTab.chkEnemies:SetChecked(false)
		self:SetChecked(true)

		DamageTakenTab_Variables.check_byrole = false
		DamageTakenTab_Variables.check_absorbs = true
		DamageTakenTab_Variables.check_enemy = false

		damageTakenTab:Update()
	end)
	tab.chkEnemies = ELib:Radio(tab,"Enemies",DamageTakenTab_Variables.check_absorbs):Point("TOPLEFT",tab.chkAbsorbs,"BOTTOMLEFT",0,-5):AddButton():OnClick(function(self) 
		damageTakenTab.chkByRole:SetChecked(false)
		damageTakenTab.chkAbsorbs:SetChecked(false)
		self:SetChecked(true)

		DamageTakenTab_Variables.check_byrole = false
		DamageTakenTab_Variables.check_absorbs = false
		DamageTakenTab_Variables.check_enemy = true

		damageTakenTab:Update()
	end)

	function tab:Update()
		local result = {}
		local max_t = 0
		local doEnemy = DamageTakenTab_Variables.check_enemy
		local isReverse = false
		for destGUID,destData in pairs(CurrentFight.damage) do
			if ExRT.F.table_len(destVar) == 0 or destVar[destGUID] then
				for destReaction,destReactData in pairs(destData) do
					local isEnemy = false
					if GetUnitInfoByUnitFlagFix(destReaction,2) == 512 then
						isEnemy = true
					end
					if (isEnemy and doEnemy) or (not isEnemy and not doEnemy) then
						for sourceGUID,sourceData in pairs(destReactData) do
							local owner = ExRT.F.Pets:getOwnerGUID(sourceGUID,GetPetsDB())
							if owner then
								sourceGUID = owner
							end
							if ExRT.F.table_len(sourceVar) == 0 or sourceVar[sourceGUID] then
								local source = isReverse and destGUID or sourceGUID
								local dest = isReverse and sourceGUID or destGUID

								for spellID,spellSegments in pairs(sourceData) do
									for segment,spellAmount in pairs(spellSegments) do
										local t = floor(CurrentFight.segments[segment].t - CurrentFight.encounterStart)

										if not result[t] then
											result[t] = {0,0}
										end

										if DamageTakenTab_Variables.check_byrole then
											local c = CurrentFight.other.rolesGUID[dest] == "TANK" and 2 or 1
											--result[t][c] = result[t][c] + spellAmount.amount + spellAmount.absorbed - spellAmount.overkill
											result[t][c] = result[t][c] + spellAmount.amount - spellAmount.overkill
										elseif DamageTakenTab_Variables.check_absorbs then
											result[t][1] = result[t][1] + spellAmount.amount - spellAmount.overkill
											result[t][2] = result[t][2] + spellAmount.absorbed
										elseif DamageTakenTab_Variables.check_enemy then
											result[t][1] = result[t][1] + spellAmount.amount + spellAmount.absorbed - spellAmount.overkill
										end

										if t > max_t then max_t = t end
									end
								end
							end
						end
					end
				end
			end
		end

		--result={} max_t=600 for i=0,600 do result[i] = {math.random(100000),math.random(50000)} end

		local data = {}
		local step = DamageTakenTab_Variables.graph_step
		local now = 1

		local total = 0
		for i=0,max_t do
			if i % step == 0 and i > 0 then 
				now = now + 1 
			end

			data[now] = (data[now] or {{0,0},x=i})
			data[now][1][1] = data[now][1][1] + (result[i] and result[i][1] or 0)
			data[now][1][2] = data[now][1][2] + (result[i] and result[i][2] or 0)
		end
		if DamageTakenTab_Variables.check_byrole then
			data.c1_1 = tab.graph.media.colors[1]
			data.c1_2 = tab.graph.media.colors[2]
			data.t1_1 = "Non-tanks"
			data.t1_2 = "Tanks"
		elseif DamageTakenTab_Variables.check_absorbs then
			data.c1_1 = tab.graph.media.colors[1]
			data.c1_2 = tab.graph.media.colors[3]
			data.t1_1 = "Non-absorbed"
			data.t1_2 = "Absorbed"
		elseif DamageTakenTab_Variables.check_enemy then
			data.c1_1 = tab.graph.media.colors[1]
			for i=1,#data do
				for j=2,#data[i][1] do
					data[i][1][j] = nil
				end
			end
		end

		self.graph.data = data
		self.graph:Update()
	end

	tab:SetScript("OnShow",function (self)
		if BWInterfaceFrame.nowFightID ~= self.lastFightID then
			self.lastFightID = BWInterfaceFrame.nowFightID
			damageTakenTab:Update()
		end
	end)



	BWInterfaceFrame:GetScript("OnShow")(BWInterfaceFrame)
end