Recount = LibStub("AceAddon-3.0"):NewAddon("Recount", "AceConsole-3.0","AceEvent-3.0", "AceComm-3.0", "AceTimer-3.0")
local Recount = _G.Recount
local AceConfigDialog = LibStub("AceConfigDialog-3.0")

local SM = LibStub:GetLibrary("LibSharedMedia-3.0")
local AceLocale = LibStub("AceLocale-3.0")
local L = AceLocale:GetLocale( "Recount" )
 
local _
 
local DataVersion	= "1.3"
local FilterSize	= 20
local RampUp		= 5
local RampDown		= 10
      
Recount.Version = tonumber(string.sub("$Revision: 1172 $", 12, -3))

local UnitLevel = UnitLevel
local UnitClass = UnitClass
local UnitIsTrivial = UnitIsTrivial
local UnitIsPlayer = UnitIsPlayer
local UnitExists = UnitExists
local UnitName = UnitName
local UnitGUID = UnitGUID
local GetTime = GetTime
local UnitIsFriend = UnitIsFriend
local GetNumRaidMembers = GetNumRaidMembers
local GetNumPartyMembers = GetNumPartyMembers

local type = type
local pairs = pairs
local ipairs = ipairs
local tonumber = tonumber
local string_format = string.format
local string_match = string.match
local string_lower = string.lower
local tinsert = table.insert
local tremove = table.remove
local math_floor = math.floor
local math_fmod = math.fmod
local time = time
local date = date
local abs = abs

local dbCombatants  
  
-- Elsia: This is straight from GUIDRegistryLib-0.1 by ArrowMaster.
local bit_bor	= bit.bor
local bit_band  = bit.band
   
local COMBATLOG_OBJECT_AFFILIATION_MINE		= COMBATLOG_OBJECT_AFFILIATION_MINE		or 0x00000001
local COMBATLOG_OBJECT_AFFILIATION_PARTY	= COMBATLOG_OBJECT_AFFILIATION_PARTY	or 0x00000002
local COMBATLOG_OBJECT_AFFILIATION_RAID		= COMBATLOG_OBJECT_AFFILIATION_RAID		or 0x00000004
local COMBATLOG_OBJECT_AFFILIATION_OUTSIDER	= COMBATLOG_OBJECT_AFFILIATION_OUTSIDER	or 0x00000008
local COMBATLOG_OBJECT_AFFILIATION_MASK		= COMBATLOG_OBJECT_AFFILIATION_MASK		or 0x0000000F
-- Reaction
local COMBATLOG_OBJECT_REACTION_FRIENDLY	= COMBATLOG_OBJECT_REACTION_FRIENDLY	or 0x00000010
local COMBATLOG_OBJECT_REACTION_NEUTRAL		= COMBATLOG_OBJECT_REACTION_NEUTRAL		or 0x00000020
local COMBATLOG_OBJECT_REACTION_HOSTILE		= COMBATLOG_OBJECT_REACTION_HOSTILE		or 0x00000040
local COMBATLOG_OBJECT_REACTION_MASK		= COMBATLOG_OBJECT_REACTION_MASK		or 0x000000F0
-- Ownership
local COMBATLOG_OBJECT_CONTROL_PLAYER		= COMBATLOG_OBJECT_CONTROL_PLAYER		or 0x00000100
local COMBATLOG_OBJECT_CONTROL_NPC			= COMBATLOG_OBJECT_CONTROL_NPC			or 0x00000200
local COMBATLOG_OBJECT_CONTROL_MASK			= COMBATLOG_OBJECT_CONTROL_MASK			or 0x00000300
-- Unit type
local COMBATLOG_OBJECT_TYPE_PLAYER			= COMBATLOG_OBJECT_TYPE_PLAYER			or 0x00000400
local COMBATLOG_OBJECT_TYPE_NPC				= COMBATLOG_OBJECT_TYPE_NPC				or 0x00000800
local COMBATLOG_OBJECT_TYPE_PET				= COMBATLOG_OBJECT_TYPE_PET				or 0x00001000
local COMBATLOG_OBJECT_TYPE_GUARDIAN		= COMBATLOG_OBJECT_TYPE_GUARDIAN		or 0x00002000
local COMBATLOG_OBJECT_TYPE_OBJECT			= COMBATLOG_OBJECT_TYPE_OBJECT			or 0x00004000
local COMBATLOG_OBJECT_TYPE_MASK			= COMBATLOG_OBJECT_TYPE_MASK			or 0x0000FC00

-- Special cases (non-exclusive)
local COMBATLOG_OBJECT_TARGET				= COMBATLOG_OBJECT_TARGET				or 0x00010000
local COMBATLOG_OBJECT_FOCUS				= COMBATLOG_OBJECT_FOCUS				or 0x00020000
local COMBATLOG_OBJECT_MAINTANK				= COMBATLOG_OBJECT_MAINTANK				or 0x00040000
local COMBATLOG_OBJECT_MAINASSIST			= COMBATLOG_OBJECT_MAINASSIST			or 0x00080000
local COMBATLOG_OBJECT_RAIDTARGET1			= COMBATLOG_OBJECT_RAIDTARGET1			or 0x00100000
local COMBATLOG_OBJECT_RAIDTARGET2			= COMBATLOG_OBJECT_RAIDTARGET2			or 0x00200000
local COMBATLOG_OBJECT_RAIDTARGET3			= COMBATLOG_OBJECT_RAIDTARGET3			or 0x00400000
local COMBATLOG_OBJECT_RAIDTARGET4			= COMBATLOG_OBJECT_RAIDTARGET4			or 0x00800000
local COMBATLOG_OBJECT_RAIDTARGET5			= COMBATLOG_OBJECT_RAIDTARGET5			or 0x01000000
local COMBATLOG_OBJECT_RAIDTARGET6			= COMBATLOG_OBJECT_RAIDTARGET6			or 0x02000000
local COMBATLOG_OBJECT_RAIDTARGET7			= COMBATLOG_OBJECT_RAIDTARGET7			or 0x04000000
local COMBATLOG_OBJECT_RAIDTARGET8			= COMBATLOG_OBJECT_RAIDTARGET8			or 0x08000000
local COMBATLOG_OBJECT_NONE					= COMBATLOG_OBJECT_NONE					or 0x80000000
local COMBATLOG_OBJECT_SPECIAL_MASK			= COMBATLOG_OBJECT_SPECIAL_MASK			or 0xFFFF0000

local LIB_FILTER_RAIDTARGET	= bit_bor(
	COMBATLOG_OBJECT_RAIDTARGET1, COMBATLOG_OBJECT_RAIDTARGET2, COMBATLOG_OBJECT_RAIDTARGET3, COMBATLOG_OBJECT_RAIDTARGET4,
	COMBATLOG_OBJECT_RAIDTARGET5, COMBATLOG_OBJECT_RAIDTARGET6, COMBATLOG_OBJECT_RAIDTARGET7, COMBATLOG_OBJECT_RAIDTARGET8
)
local LIB_FILTER_ME = bit_bor(
	COMBATLOG_OBJECT_AFFILIATION_MINE, COMBATLOG_OBJECT_REACTION_FRIENDLY, COMBATLOG_OBJECT_CONTROL_PLAYER, COMBATLOG_OBJECT_TYPE_PLAYER
)
local LIB_FILTER_MY_PET = bit_bor(
						COMBATLOG_OBJECT_AFFILIATION_MINE,
						COMBATLOG_OBJECT_REACTION_FRIENDLY,
						COMBATLOG_OBJECT_CONTROL_PLAYER,
						COMBATLOG_OBJECT_TYPE_PET
						)
local LIB_FILTER_PARTY = bit_bor(COMBATLOG_OBJECT_TYPE_PLAYER, COMBATLOG_OBJECT_AFFILIATION_PARTY)
local LIB_FILTER_RAID  = bit_bor(COMBATLOG_OBJECT_TYPE_PLAYER, COMBATLOG_OBJECT_AFFILIATION_RAID)
local LIB_FILTER_GROUP = bit_bor(LIB_FILTER_PARTY, LIB_FILTER_RAID)

--[[local DefaultConfig={
	char={
		combatants={
			['*'] = {
				Init=false,
				Owner=false,
				AbilityType={},
				TimeLast={},
				TimeData={
					Damage={{},{}},
					DamageTaken={{},{}},
					Healing={{},{}},
					Overhealing={{},{}},
					HealingTaken={{},{}},
					Threat={{},{}}
				},

				TimeWindows={
					Damage={['*']=0},
					DamageTaken={['*']=0},
					Healing={['*']=0},
					HealingTaken={['*']=0},
					Overhealing={['*']=0},
					Threat={['*']=0},
				},
				Fights={
					['*']={
						Damage=0,
						FDamage=0,
						DamageTaken=0,
						Healing=0,
						HealingTaken=0,
						Overhealing=0,
						DeathCount=0,
						DOT_Time=0,
						HOT_Time=0,
						Interrupts=0,
						Dispels=0,
						Dispelled=0,
						ActiveTime=0,
						TimeHeal=0,
						TimeDamage=0,
						CCBreak=0,
						Threat=0,
						ThreatNonZero=0,
						ManaGain=0,
						EnergyGain=0,
						RageGain=0,
						Ressed=0,

						--Ability Data
						Attacks={},
						FAttacks={},
						Heals={},
						OverHeals={},
						DOTs={},
						HOTs={},
						InterruptData={},
						CCBroken={},

						--Interaction Data
						DamagedWho={}, --Who did I damage?
						FDamagedWho={}, --Who did I damage?
						WhoDamaged={}, --Who damaged me?
						HealedWho={}, --Who did I heal?
						WhoHealed={}, --Who healed me?
						DispelledWho={}, --Who did I dispel?
						WhoDispelled={}, --Who dispelled me?
						PartialResist={},	--What spells partially resisted
						PartialBlock={}, -- What attacks partially blocked
						PartialAbsorb={}, -- What damage partially absorbed
						TimeSpent={},	--Where did I spend my time
						TimeDamaging={},	--Where did I spend my time attacking
						TimeHealing={},	--Where did I spend my time healing
						ManaGained={},	--Where did I gain mana
						EnergyGained={}, --Where did I gain energy
						RageGained={}, --Where did I gain rage
						ManaGainedFrom={},	--Where did I gain mana
						EnergyGainedFrom={}, --Where did I gain energy
						RageGainedFrom={}, --Where did I gain rage
						RessedWho={},

						--Elemental Tracking
						ElementDone={},
						ElementDoneResist={},
						ElementDoneBlock={},
						ElementDoneAbsorb={},
						ElementTaken={},
						ElementTakenResist={},
						ElementTakenBlock={},
						ElementTakenAbsorb={},

						ElementHitsDone={},
						ElementHitsTaken={},
					}
				},





				TimeNeedZero={},

				LastEvents={},
				LastEventHealth={},
				LastEventHealthNum={},
				LastEventTimes={},
				LastEventType={},
				LastEventIncoming={},
				LastEventNum={},

				NextEventNum=1,

				LastThreat=0,
				LastAbility=0,
				LastActive=0,

				LastFightIn=0,
				UnitLockout=0,

				HealBuffHas=nil,
				HealBuffName=nil,

				DeathLogs={},

				FightsSaved=0,

				Sync={
					MsgNum=0,
					LastSent=0,
					LastChanged=0,

					Damage=0,
					DamageTaken=0,
					FDamage=0,
					Healing=0,
					HealingTaken=0,
					Overhealing=0,

					ActiveTime=0,
					
					OverhealCorrection=0,
					HealingCorrection=0,
				},
			}
		},
		GUID=nil,
		PetGUID=nil,
		FoughtWho={},
		FightNum=0,
		CombatTimes={},
		version=0,
	}
}
]]

local Default_Profile={
	profile={
		Colors={
			["Window"]={
				["Title"] = { r = 1, g = 0, b = 0, a = 1},
				["Background"]= { r = 24/255, g = 24/255, b = 24/255, a = 1},
				["Title Text"] = {r = 1, g = 1, b = 1, a = 1},
			},
			["Bar"]={
				["Bar Text"] = {r = 1, g = 1, b = 1},
				["Total Bar"] = { r = 0.75, g = 0.75, b = 0.75},
			},
			["Other Windows"]={
				["Title"] = { r = 1, g = 0, b = 0, a = 1},
				["Background"]= { r = 24/255, g = 24/255, b = 24/255, a = 1},
				["Title Text"] = {r = 1, g = 1, b = 1, a = 1},
			},
			["Detail Window"]={
			},
			["Class"]={
				["HUNTER"] = { r = 0.67, g = 0.83, b = 0.45, a=1 },
				["WARLOCK"] = { r = 0.58, g = 0.51, b = 0.79, a=1 },
				["PRIEST"] = { r = 1.0, g = 1.0, b = 1.0, a=1 },
				["PALADIN"] = { r = 0.96, g = 0.55, b = 0.73, a=1 },
				["MAGE"] = { r = 0.41, g = 0.8, b = 0.94, a=1 },
				["ROGUE"] = { r = 1.0, g = 0.96, b = 0.41, a=1 },
				["DRUID"] = { r = 1.0, g = 0.49, b = 0.04, a=1 },
				["SHAMAN"] = { r = 0.14, g = 0.35, b = 1.0, a=1 },
				["WARRIOR"] = { r = 0.78, g = 0.61, b = 0.43, a=1 },
				["DEATHKNIGHT"] = { r = 0.77, g = 0.12, b = 0.23, a=1 },
				["PET"] = { r = 0.09, g = 0.61, b = 0.55, a=1 },
--				["GUARDIAN"] = { r = 0.61, g = 0.09, b = 0.09 },
				["MOB"] = { r = 0.58, g = 0.24, b = 0.63, a=1 },
				["UNKNOWN"] = { r = 0.1, g = 0.1, b = 0.1, a=1 },
				["HOSTILE"] = { r = 0.7, g = 0.1, b = 0.1, a=1 },
				["UNGROUPED"] = { r = 0.63, g = 0.58, b = 0.24, a=1 },
			},
			["Realtime"]={
			},
			["Names"]={
			}
		},
		MaxFights=5,
		--Window={
			--ShowCurAndLast=false,
		--},
		ReportLines=10,
		MessagesTracked=50,
		GlobalStatusBar=false,
		AutoDelete=true,
		AutoDeleteCombatants=true, -- Elsia: set this to true to reduce data accumulation
		AutoDeleteTime=180,
		AutoDeleteNewInstance=true, -- Elsia: set this to true
		ConfirmDeleteInstance=true, -- Elsia: Get annoying popup box?
		LastInstanceName="", -- Elsia: Last instance is empty by default
		DeleteNewInstanceOnly=true,
		DeleteJoinRaid = true,
		ConfirmDeleteRaid = true,
		DeleteJoinGroup = true,
		ConfirmDeleteGroup = true,
		BarTexture="BantoBar",
		MergePets=true,
		MergeAbsorbs=true,
		RecordCombatOnly=true,
		SegmentBosses=false,
		MainWindowVis=true,
		MainWindowMode=1,
		Locked=false,
		EnableSync=true, -- Elsia: Default enable sync is set to true again now, thanks to lazy syncing.
		GlobalDataCollect=true, -- Elsia: Global toggle for data collection
		HideCollect=false, -- Elsia: Hide Recount window when not collecting data
		Font="Arial Narrow",
		Scaling=1,
		MainWindow={
			Buttons={
				ReportButton=true,
				FileButton=true,
				ConfigButton=true,
				ResetButton=true,
				LeftButton=true,
				RightButton=true,
				CloseButton=true,
			},
			RowHeight=14,
			RowSpacing=1,
			AutoHide=false,
			ShowScrollbar=true, -- Elsia: Allow toggle of scrollbar
			HideTotalBar=true,
			BarText=
			{
				RankNum =true,
				PerSec = true,
				Percent = true,
				NumFormat = 1,
			},
			Position={
				x = 0,
				y = 0,
				w = 140,
				h = 200,
			},
		},
		Filters={
			Show={
				Self=true,
				Grouped=true,
				Ungrouped=true, -- Elsia: Default show leaving party members
				Hostile=false,
				Pet=false,
				Trivial=false,
				Nontrivial=false,
				Boss=false,
				Unknown=false,
			},
			Data={
				Self=true,
				Grouped=true,
				Ungrouped=false, -- Elsia: Removed to reduce default data accumulation
				Hostile=false,
				Pet=true,
				Trivial=false,
				Nontrivial=false,
				Boss=true,
				Unknown=true,
			},
			TimeData={
				Self=false,
				Grouped=false, -- Elsia: Removed Default timed on for groups
				Ungrouped=false,
				Hostile=false,
				Pet=false,
				Trivial=false,
				Nontrivial=false,
				Boss=false, -- Elsia:Removed Default timed on for bosses
				Unknown=false,
			},
			TrackDeaths={
				Self=true,
				Grouped=true,
				Ungrouped=false,
				Hostile=false,
				Pet=true,
				Trivial=false,
				Nontrivial=false,
				Boss=true,
				Unknown=false,
			},
		},
		ZoneFilters={
			none=true, -- Elsia: These fields are named after what IsInInstance() returns for types.
			pvp=true,
			arena=true,
			party=true,
			raid=true,
		},
		GroupFilters={
			[1]=true, -- Solo
			[2]=true, -- Party
			[3]=true, -- Raid	
		},
		FilterDeathType={
			DAMAGE=true,
			HEAL=true,
			MISC=true,
		},
		FilterDeathIncoming={
			[true]=true,
			[false]=false
		},
		RealtimeWindows={},
		ClampToScreen = false,
	},
} 

SM:Register("statusbar", "Aluminium",			[[Interface\Addons\Recount\Textures\statusbar\Aluminium]])
SM:Register("statusbar", "Armory",				[[Interface\Addons\Recount\Textures\statusbar\Armory]])
SM:Register("statusbar", "BantoBar",			[[Interface\Addons\Recount\Textures\statusbar\BantoBar]])
SM:Register("statusbar", "Flat",				[[Interface\Addons\Recount\Textures\statusbar\Flat]])
SM:Register("statusbar", "Minimalist",			[[Interface\Addons\Recount\Textures\statusbar\Minimalist]])
SM:Register("statusbar", "Otravi",				[[Interface\Addons\Recount\Textures\statusbar\Otravi]])
SM:Register("statusbar", "Empty",               [[Interface\Addons\Recount\Textures\statusbar\Empty]])

BINDING_HEADER_RECOUNT = "Recount"
BINDING_NAME_RECOUNT_PREVIOUSPAGE = L["Show previous main page"]
BINDING_NAME_RECOUNT_NEXTPAGE = L["Show next main page"]
BINDING_NAME_RECOUNT_DAMAGE = L["Display"].." "..L["Damage Done"]
BINDING_NAME_RECOUNT_DPS = L["Display"].." "..L["DPS"]
BINDING_NAME_RECOUNT_FRIENDLYFIRE = L["Display"].." "..L["Friendly Fire"]
BINDING_NAME_RECOUNT_DAMAGETAKEN = L["Display"].." "..L["Damage Taken"]
BINDING_NAME_RECOUNT_HEALING = L["Display"].." "..L["Healing Done"]
BINDING_NAME_RECOUNT_HEALINGTAKEN = L["Display"].." "..L["Healing Taken"]
BINDING_NAME_RECOUNT_OVERHEALING = L["Display"].." "..L["Overhealing Done"]
BINDING_NAME_RECOUNT_DEATHS = L["Display"].." "..L["Deaths"]
BINDING_NAME_RECOUNT_DOTS = L["Display"].." "..L["DOT Uptime"]
BINDING_NAME_RECOUNT_HOTS = L["Display"].." "..L["HOT Uptime"]
BINDING_NAME_RECOUNT_ACTIVITY = L["Display"].." "..L["Activity"]
BINDING_NAME_RECOUNT_DISPELS = L["Display"].." "..L["Dispels"]
BINDING_NAME_RECOUNT_DISPELLED = L["Display"].." "..L["Dispelled"]
BINDING_NAME_RECOUNT_INTERRUPTS = L["Display"].." "..L["Interrupts"]
BINDING_NAME_RECOUNT_RESURRECT = L["Display"].." "..L["Ressers"]
BINDING_NAME_RECOUNT_CCBREAKER = L["Display"].." "..L["CC Breakers"]
BINDING_NAME_RECOUNT_MANA = L["Display"].." "..L["Mana Gained"]
BINDING_NAME_RECOUNT_ENERGY = L["Display"].." "..L["Energy Gained"]
BINDING_NAME_RECOUNT_RAGE = L["Display"].." "..L["Rage Gained"]
BINDING_NAME_RECOUNT_RUNICPOWER = L["Display"].." "..L["Runic Power Gained"]

BINDING_NAME_RECOUNT_REPORT_MAIN = L["Report the Main Window Data"]
BINDING_NAME_RECOUNT_REPORT_DETAILS = L["Report the Detail Window Data"]
BINDING_NAME_RECOUNT_RESET_DATA = L["Resets the data"]
BINDING_NAME_RECOUNT_SHOW_MAIN = L["Shows the main window"]
BINDING_NAME_RECOUNT_HIDE_MAIN = L["Hides the main window"]
BINDING_NAME_RECOUNT_TOGGLE_MAIN = L["Toggles the main window"]
BINDING_NAME_RECOUNT_TOGGLE_PAUSE = L["Toggle pause of global data collection"]

local optFrame

local function deepcopy(object)
	local lookup_table = {}
	local function _copy(object)
		if type(object) ~= "table" then
			return object
		elseif lookup_table[object] then
			return lookup_table[object]
		end
		local new_table = {}
		lookup_table[object] = new_table
		for index, value in pairs(object) do
			new_table[_copy(index)] = _copy(value)
		end
		return setmetatable(new_table, getmetatable(object))
	end
	return _copy(object)
end

Recount.consoleOptions = {
	name = L["Recount"],
	type = 'group',
	args = {
		confdesc = {
			order = 1,
			type = "description",
			name = L["Config Access"].."\n",
			cmdHidden = true
		},
		windesc = {
			order = 10,
			type = "description",
			name = L["Window Options"].."\n",
			cmdHidden = true
		},
		syncdesc = {
			order = 20,
			type = "description",
			name = L["Sync Options"].."\n",
			cmdHidden = true
		},
		datadesc = {
			order = 30,
			type = "description",
			name = L["Data Options"].."\n",
			cmdHidden = true
		},
		[L["gui"]] = {
			order = 2,
			name = L["GUI"],
			desc = L["Open Ace3 Config GUI"],
			type = 'execute',
			func = function()
				InterfaceOptionsFrame:Hide()
				AceConfigDialog:SetDefaultSize("Recount", 500, 550)
				AceConfigDialog:Open("Recount") end
		},
		[L["sync"]] = {
			order = 21,
			name  = L["Sync"],
			desc = L["Toggles sending synchronization messages"],
			type = 'toggle',
			get = function(info) return Recount.db.profile.EnableSync end,
			set = function(info,v)
				if v then -- Elsia: Make sure it's on before enabling, an event might intervene
					Recount:ConfigComm(); 
					Recount:Print("Lazy Sync enabled")
				end
					
				Recount.db.profile.EnableSync=v
				
				if not v then -- Elsia: Make sure it's off before disabling, an event might intervene
					Recount:FreeComm();
					Recount:Print("Lazy Sync disabled")
				end
			end,
		},
		[L["reset"]] = {
			order = 31,
			name = L["Reset"],
			desc = L["Resets the data"],
			type = 'execute',
			func = function() Recount:ResetData() end
		},
		[L["verChk"]] = {
			order = 22,
			name = L["VerChk"],
			desc = L["Displays the versions of players in the raid"],
			type = 'execute',
			func = function() Recount:ReportVersions() end
		},
		[L["show"]] = {
			order = 12,
			name = L["Show"],
			desc = L["Shows the main window"],
			type = 'execute',
			func = function() Recount.MainWindow:Show();Recount:RefreshMainWindow() end,
			dialogHidden = true
		},
		[L["pause"]] = {
			order = 23,
			name = L["Pause"],
			desc = L["Toggle pause of global data collection"],
			type = 'execute',
			func = function() if not Recount.db.profile.GlobalDataCollect then
			     Recount:SetGlobalDataCollect(true);
			     Recount:Print(L["Data collection turned on"]);
			else
			     Recount:SetGlobalDataCollect(false);
			     Recount:Print(L["Data collection turned off"]);
			end end,
		},		
		hide = {
			order = 13,
			name = L["Hide"],
			desc = L["Hides the main window"],
			type = 'execute',
			func = function() Recount.MainWindow:Hide() end,
			dialogHidden = true
		},
		toggle = {
			order = 11,
			name = L["Toggle"],
			desc = L["Toggles the main window"],
			type = 'execute',
			func = function() if Recount.MainWindow:IsShown() then Recount.MainWindow:Hide() else Recount.MainWindow:Show();Recount:RefreshMainWindow() end end
		},
		config = {
			order = 3,
			name = L["Config"],
			desc = L["Shows the config window"],
			type = 'execute',
			func = function() Recount:ShowConfig() end
		},
		resetpos = {
			order = 14,
			name = L["ResetPos"],
			desc = L["Resets the positions of the detail, graph, and main windows"],
			type = 'execute',
			func = function() Recount:ResetPositions() end
		},
		lock = {
			order = 15,
			name  = L["Lock"],
			desc = L["Toggles windows being locked"],
			type = 'toggle',
			get = function(info) return Recount.db.profile.Locked end,
			set = function(info,v)
				Recount.db.profile.Locked=v
				Recount:LockWindows(v)
			end,
		},
		maxfights =  {
			  order = 31,
			  name = L["Recorded Fights"],
			  desc = L["Set the maximum number of recorded fight segments"],
			  type = 'range',
			  min = 1,
			  max = 25,
			  step = 1,
			  get = function(info) return Recount.db.profile.MaxFights end,
			  set = function(info, v)
			          if v < Recount.db.profile.MaxFights then
				     Recount.Fights:DeleteOverflowFights(v)
				  end
			          Recount.db.profile.MaxFights=v
			  end, 
		},	
		FrameStrata = {
			type = "select",
			order = 17,
			name = L["Frame Strata"],
			desc = L["Controls the frame strata of the Recount windows. Default: MEDIUM"],
			values = { -- A hack to sort them in the menu
				["1-BACKGROUND"] = "BACKGROUND",
				["2-LOW"] = "LOW",
				["3-MEDIUM"] = "MEDIUM",
				["4-HIGH"] = "HIGH",
				["5-DIALOG"] = "DIALOG",
				["6-FULLSCREEN"] = "FULLSCREEN",
				["7-FULLSCREEN_DIALOG"] = "FULLSCREEN_DIALOG",
				["8-TOOLTIP"] = "TOOLTIP",
			},
			get = function(info) return Recount.db.profile.FrameStrata or "3-MEDIUM" end,
			set = function(info, value)
				Recount.db.profile.FrameStrata = value
				Recount:SetStrataAndClamp()
			end,
		},
		ClampToScreen = {
			type = "toggle",
			name = L["Clamp To Screen"],
			desc = L["Controls whether the Recount windows can be dragged offscreen"],
			order = 16,
			get = function(info) return Recount.db.profile.ClampToScreen end,
			set = function(info, value)
				Recount.db.profile.ClampToScreen = value
				Recount:SetStrataAndClamp()
			end,
		},
		
	}
}

Recount.consoleOptions2 = deepcopy(Recount.consoleOptions)	

Recount.consoleOptions2.args.report = {
			order = 32,
			name = L["Report"],
			type = 'group',
			desc = L["Allows the data of a window to be reported"],
			args = {
				detail = {
					type = "select",
					name = L["Detail"],
					order = 2,
					desc = L["Report the Detail Window Data"],
					values = {
						["Say"] = "Say",
						["Party"] = "Party",
						["Raid"] = "Raid",
						["Guild"] = "Guild",
						["Officer"] = "Officer",
						["Gui"] = "GUI",
					},
					get = function(info) return "Select" end,
					set = function(info, value)
						if string_lower(value) == "gui" then
							Recount:ShowReport("Detail",Recount.ReportDetail)
						else
							Recount.db.profile.ReportLines = Recount.db.profile.ReportLines or 10
							Recount:ReportDetail(Recount.db.profile.ReportLines,string_lower(value),"")
						end
					end,
				},
				main = {
					type = "select",
					name = L["Main"],
					order = 1,
					desc = L["Report the Main Window Data"],
					values = {
						["Say"] = "Say",
						["Party"] = "Party",
						["Raid"] = "Raid",
						["Guild"] = "Guild",
						["Officer"] = "Officer",
						["Gui"] = "GUI",
					},
					get = function(info) return "Select" end,
					set = function(info, value)
						if string_lower(value) == "gui" then
							Recount:ShowReport("Main",Recount.ReportData)
						else
							Recount.db.profile.ReportLines = Recount.db.profile.ReportLines or 10
							Recount:ReportData(Recount.db.profile.ReportLines,string_lower(value),"")
						end
					end,
				},
				lines =  {
					  order = 3,
					  name = L["Lines Reported"],
					  desc = L["Set the maximum number of lines to report"],
					  type = 'range',
					  min = 1,
					  max = 25,
					  step = 1,
					  get = function(info) return Recount.db.profile.ReportLines or 10 end,
					  set = function(info, v)
							Recount.db.profile.ReportLines = v
							Recount:Print(L["Lines reported set to: "]..v)
					  end, 
				},	
			}
		}
		
Recount.consoleOptions2.args.realtime = {
			name = L["Realtime"],
			type = 'group', 
			desc = L["Specialized Realtime Graphs"],
			args = {
				netfps = {
					name = L["Network and FPS"],
					type = 'group', inline = true,
					args = {
						fps = {
							name = L["FPS"],
							desc = L["Starts a realtime window tracking your FPS"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("FPS","FPS","") end
						},
						lag = {
							name = L["Lag"],
							desc = L["Starts a realtime window tracking your latency"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("Latency","LAG","") end
						},
						uptraffic = {
							name = L["Upstream Traffic"],
							desc = L["Starts a realtime window tracking your upstream traffic"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("Upstream Traffic","UP_TRAFFIC","") end
						},
						downtraffic = {
							name = L["Downstream Traffic"],
							desc = L["Starts a realtime window tracking your downstream traffic"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("Downstream Traffic","DOWN_TRAFFIC","") end
						},
						bandwidth = {
							name = L["Available Bandwidth"],
							desc = L["Starts a realtime window tracking amount of available AceComm bandwidth left"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("Bandwidth Available","AVAILABLE_BANDWIDTH","") end
						},
					},
				},
				raid = {
					name = L["Raid"],
					desc = L["Tracks your entire raid"],
					type = 'group', inline = true,

					args = {
						dps = {
							name = L["DPS"],
							desc = L["Tracks Raid Damage Per Second"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("!RAID","DAMAGE","Raid DPS") end
						},
						dtps = {
							name = L["DTPS"],
							desc = L["Tracks Raid Damage Taken Per Second"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("!RAID","DAMAGETAKEN","Raid DTPS") end
						},
						hps = {
							name = L["HPS"],
							desc = L["Tracks Raid Healing Per Second"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("!RAID","HEALING","Raid HPS") end
						},
						htps = {
							name = L["HTPS"],
							desc = L["Tracks Raid Healing Taken Per Second"],
							type = 'execute',
							func = function() Recount:CreateRealtimeWindow("!RAID","HEALINGTAKEN","Raid HTPS") end
						},
					}
				}
			}
}

function Recount:ReportVersions() -- Elsia: Functionified so GUI can use it too
	Recount:Print(L["Displaying Versions"])
	if Recount.VerTable then -- Elsia: Fixed nil error on non sync situation.
		for k,v in pairs(Recount.VerTable) do
			Recount:Print(k.." "..v)
		end
	end
end

function Recount:ShowCombatantList()
	for k,v in pairs(dbCombatants) do
		Recount:Print(k.." "..(v.Name or "nil").." "..(v.type or "nil").." "..(v.level or "nil").." "..(v.enClass or "nil").." "..(v.GUID or "nil"))
	end
	Recount:ShowNrCombatants()
end

function Recount:NrCombatants()
	local counter = 0
	for k,v in pairs(dbCombatants) do counter = counter + 1 end
	return counter
end

function Recount:ShowNrCombatants()
	Recount:Print(Recount:NrCombatants())
end

function Recount:ResetData()
	if Recount.GraphWindow then
		Recount.GraphWindow:Hide()
		Recount.GraphWindow.LineGraph:LockXMin(false)
		Recount.GraphWindow.LineGraph:LockXMax(false)
		Recount.GraphWindow.TimeRangeSet=false
	end

	if Recount.DetailWindow then
		Recount.DetailWindow:Hide()
	end

	for k,v in pairs(dbCombatants) do
		Recount:DeleteGuardianOwnerByGUID(dbCombatants[k])
		dbCombatants[k]=nil
	end

	for k,v in pairs(Recount.db2.CombatTimes) do
		Recount.db2.CombatTimes[k]=nil
	end

	if Recount.MainWindow and Recount.MainWindow.DispTableSorted then
		Recount.MainWindow.DispTableSorted=Recount:GetTable()
		Recount.MainWindow.DispTableLookup=Recount:GetTable()
	end

	if Recount.MainWindow then
		Recount:RefreshMainWindow()
	end

	if #Recount.db2.FoughtWho > 0 then
		Recount:SendReset() -- Elsia: Sync the reset if we actually fought something
	end
 
	Recount.db2.FoughtWho={}

	Recount:ResetTableCache()
	
	if Recount.db.profile.CurDataSet ~= "CurrentFightData" and Recount.db.profile.CurDataSet ~= "LastFightData" then
		Recount.db.profile.CurDataSet = "OverallData"
	end
	
	if RecountDeathTrack then
		RecountDeathTrack:DeleteAllTracks()
		RecountDeathTrack:SetFight(Recount.db.profile.CurDataSet)
	end
	
	Recount.db2.FightNum=0

	for k,v in pairs(dbCombatants) do
		v.LastFightIn=0
	end
	
	--Perform a garbage collect if they are resetting the data
	collectgarbage("collect")
end

function Recount:FindUnit(name)
	local unit --, UnitObj
	--Handle this as two passes
	
	unit=Recount:GetUnitIDFromName(name) -- We shouldn't need to find roster units.

	if unit then
		return unit
	end

	unit=Recount:FindTargetedUnit(name)

	return unit
end

local Epsilon=0.000000000000000001

function Recount:ResetFightData(data)

   if not data then
      data = {}
   else
      for k, v in pairs(data) do
	 if type(v)=="table" then
	    Recount:ResetFightData(v)
	 elseif type(v)=="number" then
	    data[k] = 0
	 elseif type(v)=="string" then
	    data[k] = nil
	 elseif type(v)=="boolean" then
	    data[k] = nil
	 end
      end
   end
end   

--[[
function Recount:ResetFightData2(data)
	--Init Data tracked
	data = data or {}
	data.Damage=0
	data.FDamage=0
	data.DamageTaken=0
	data.Healing=0
	data.HealingTaken=0
	data.Overhealing=0
	data.DeathCount=0
	data.DOT_Time=0
	data.HOT_Time=0
	data.Interrupts=0
	data.Dispels=0
	data.Dispelled=0
	data.ActiveTime=0
	data.TimeHeal=0
	data.TimeDamage=0
	data.CCBreak=0
	data.ManaGain=0
	data.EnergyGain=0
	data.RageGain=0
	data.RunicPowerGain=0
	data.Ressed=0

	for k, v in pairs(data) do
		if type(v)=="table" then
			for k2 in pairs(v) do
				if type(v[k2])=="table" then
					Recount:FreeTable(v[k2])
				end
				v[k2]=nil
			end
		else
			data[k]=0
		end

	end
end
]]

function Recount:InitFightData(data)
	--Init Data tracked
	data.Damage=0
	data.FDamage=0
	data.DamageTaken=0
	data.Healing=0
	data.HealingTaken=0
	data.Overhealing=0
	data.DeathCount=0
	data.DOT_Time=0
	data.HOT_Time=0
	data.Interrupts=0
	data.Dispels=0
	data.Dispelled=0
	data.ActiveTime=0
	data.TimeHeal=0
	data.TimeDamage=0
	data.CCBreak=0
	data.ManaGain=0
	data.EnergyGain=0
	data.RageGain=0
	data.RunicPowerGain=0
	data.Ressed=0

	--Ability Data
	data.Attacks=Recount:GetTable()
	data.FAttacks=Recount:GetTable()
	data.Heals=Recount:GetTable()
	data.OverHeals=Recount:GetTable()
	data.DOTs=Recount:GetTable()
	data.HOTs=Recount:GetTable()
	data.InterruptData=Recount:GetTable()
	data.CCBroken=Recount:GetTable()

	--Interaction Data
	data.DamagedWho=Recount:GetTable() --Who did I damage?
	data.FDamagedWho=Recount:GetTable() --Who did I damage?
	data.WhoDamaged=Recount:GetTable() --Who damaged me?
	data.HealedWho=Recount:GetTable() --Who did I heal?
	data.WhoHealed=Recount:GetTable() --Who healed me?
	data.DispelledWho=Recount:GetTable() --Who did I dispel?
	data.WhoDispelled=Recount:GetTable() --Who dispelled me?
	data.TimeSpent=Recount:GetTable()	--Where did I spend my time
	data.TimeDamaging=Recount:GetTable()	--Where did I spend my time attacking
	data.TimeHealing=Recount:GetTable()	--Where did I spend my time healing
	data.ManaGained=Recount:GetTable()	--Where did I gain mana
	data.EnergyGained=Recount:GetTable() --Where did I gain energy
	data.RageGained=Recount:GetTable() --Where did I gain rage
	data.RunicPowerGained=Recount:GetTable() --Where did I gain runic power
	data.ManaGainedFrom=Recount:GetTable()	--Where did I gain mana
	data.EnergyGainedFrom=Recount:GetTable() --Where did I gain energy
	data.RageGainedFrom=Recount:GetTable() --Where did I gain rage
	data.RunicPowerGainedFrom=Recount:GetTable() --Where did I gain runic power
	data.PartialResist=Recount:GetTable()	--What spells partially resisted
	data.PartialBlock=Recount:GetTable() -- What attacks partially blocked
	data.PartialAbsorb=Recount:GetTable() -- What damage partially absorbed
	data.RessedWho=Recount:GetTable()

	--Elemental Tracking
	data.ElementDone=Recount:GetTable()
	data.ElementDoneResist=Recount:GetTable()
	data.ElementDoneBlock=Recount:GetTable()
	data.ElementDoneAbsorb=Recount:GetTable()
	data.ElementTaken=Recount:GetTable()
	data.ElementTakenResist=Recount:GetTable()
	data.ElementTakenBlock=Recount:GetTable()
	data.ElementTakenAbsorb=Recount:GetTable()

	data.ElementHitsDone=Recount:GetTable()
	data.ElementHitsTaken=Recount:GetTable()
end

function Recount:CreateOwnerFlags(nameFlags)
	local ownerFlags=bit_band(nameFlags,COMBATLOG_OBJECT_AFFILIATION_MASK+COMBATLOG_OBJECT_REACTION_MASK+COMBATLOG_OBJECT_CONTROL_MASK)
	if bit_band(nameFlags,COMBATLOG_OBJECT_CONTROL_PLAYER)~=0 then
		ownerFlags = ownerFlags + COMBATLOG_OBJECT_TYPE_PLAYER
	else -- NPC
		ownerFlags = ownerFlags + COMBATLOG_OBJECT_TYPE_NPC
	end	
	
	return ownerFlags
end

local FlagsToUnitID =
{
 [COMBATLOG_OBJECT_TARGET]				= "target",
 [COMBATLOG_OBJECT_FOCUS]				= "focus",
 [COMBATLOG_OBJECT_MAINTANK]			= "maintank",
 [COMBATLOG_OBJECT_MAINASSIST]			= "mainassist",
 [COMBATLOG_OBJECT_RAIDTARGET1]			= "raid1target",
 [COMBATLOG_OBJECT_RAIDTARGET2]			= "raid2target",
 [COMBATLOG_OBJECT_RAIDTARGET3]			= "raid3target",
 [COMBATLOG_OBJECT_RAIDTARGET4]			= "raid4target",
 [COMBATLOG_OBJECT_RAIDTARGET5]			= "raid5target",
 [COMBATLOG_OBJECT_RAIDTARGET6]			= "raid6target",
 [COMBATLOG_OBJECT_RAIDTARGET7]			= "raid7target",
 [COMBATLOG_OBJECT_RAIDTARGET8]			= "raid8target",
}

function Recount:FindPetUnitFromFlags(unitFlags, unitGUID)
	assert(bit_band(unitFlags,COMBATLOG_OBJECT_TYPE_PET))
	if bit_band(unitFlags,COMBATLOG_OBJECT_TYPE_PET)==0 then -- Elsia: Has to be a pet. Guardians don't yet have unitids
		return
	end
	
	-- Check for my pet
	if bit_band(unitFlags,COMBATLOG_OBJECT_TYPE_PET)~=0 and bit_band(COMBATLOG_OBJECT_AFFILIATION_MINE)~=0 then
		return "pet" -- Elsia: My pet is easy
	end

	local vGUID
	
	-- Check for raid and party pets.
	if bit_band(unitFlags,COMBATLOG_OBJECT_TYPE_PET)~=0 and bit_band(unitFlags,COMBATLOG_OBJECT_AFFILIATION_PARTY+COMBATLOG_OBJECT_AFFILIATION_RAID+COMBATLOG_OBJECT_AFFILIATION_MINE)~=0 then
		if bit_band(unitFlags,COMBATLOG_OBJECT_AFFILIATION_RAID)~=0 then
			local Num=GetNumRaidMembers() 
			if Num>0 then
				for i=1,Num do
					if vGUID == UnitGUID("raidpet"..i) then
						return "raidpet"..i
					end
				end
			end
		elseif bit_band(unitFlags,COMBATLOG_OBJECT_AFFILIATION_PARTY)~=0 then
			local Num=GetNumPartyMembers()
			if Num>0 then
				for i=1,Num do
					if vGUID == UnitGUID("partypet"..i) then
						return "partypet"..i
					end
				end
			end
		end
	end
	
	assert(false) -- This should never happen
	
	return nil
end

function Recount:FindUnitFromFlags(unitname,unitFlags)
-- Elisa: This check excludes pets.

	if bit_band(unitFlags,COMBATLOG_OBJECT_TYPE_PLAYER)~=0 and bit_band(unitFlags,COMBATLOG_OBJECT_AFFILIATION_PARTY+COMBATLOG_OBJECT_AFFILIATION_RAID+COMBATLOG_OBJECT_AFFILIATION_MINE)~=0 then
		return unitname -- Elsia: Covers all non-pet players in raid
	end

	-- This returns all target-inferable units from flags.
	for k,v in pairs(FlagsToUnitID) do
		if bit_band(k,unitFlags)~=0 then
			local vname, vrealm = UnitName(v)
			if vname and vname == unitname then
				return v
			end
		end
	end

	return nil
end

Recount.ElementalMobID = {
	[15430] = "3BF8", -- Earth elemental totem and it's greater elemental
	[15439] = "3C4E" -- Fire elemental totem
}

local gopts = {}

function Recount:AddGreaterElemental(opts)
	
	local nameGUID, petName, nameFlags, ownerGUID, owner, ownerFlags = unpack(opts)

	--Recount:Print(nameGUID)
	
	local newguid1 = tonumber(nameGUID:sub(-1-5,-1),16)+1
	local mobid = tonumber(nameGUID:sub(3+6,3+9),16)
	local newguid2 = tonumber(nameGUID:sub(3,3+5),16)
	local nameGUID2 = string_format("0x%06X",newguid2)..Recount.ElementalMobID[mobid]..string_format("%06X",newguid1)
	--Recount:Print(mobid.." "..nameGUID.." "..nameGUID2)
	
	RecountTempTooltip:SetOwner(UIParent, "ANCHOR_NONE")
	RecountTempTooltip:ClearLines()
	RecountTempTooltip:SetHyperlink("unit:" .. nameGUID2)	

	if RecountTempTooltip:NumLines() > 0 then
		petName = getglobal("RecountTempTooltipTextLeft1"):GetText()
		nameGUID = nameGUID2
		--Recount:Print("Adding Guardian: "..petName.." "..nameGUID)
		Recount:AddPetCombatant(nameGUID, petName, nameFlags, ownerGUID, owner, ownerFlags)
	--else
	--	Recount:Print("Eek: ".. RecountTempTooltip:NumLines())
	end
end

function Recount:FindGuardianFromTooltip(nameGUID)
	
	RecountTempTooltip:SetOwner(UIParent, "ANCHOR_NONE")
	RecountTempTooltip:ClearLines()
	RecountTempTooltip:SetHyperlink("unit:" .. nameGUID)	

	if RecountTempTooltip:NumLines() > 0 then
		local petName = getglobal("RecountTempTooltipTextLeft1"):GetText()
		return petName
	else
		return nil
	end
end
 
function Recount:ScanGUIDTooltip(nameGUID)
	local newguid1 = tonumber(nameGUID:sub(-1-5,-1),16)
	local mobid = tonumber(nameGUID:sub(3+6,3+9),16)
	local newguid2 = tonumber(nameGUID:sub(3,3+5),16)
	local nameGUID2 = string_format("0x%06X",newguid2)..string_format("%04X",mobid)..string_format("%06X",newguid1)
	Recount:Print(mobid.." "..nameGUID.." "..nameGUID2)

	RecountTempTooltip:SetOwner(UIParent, "ANCHOR_NONE")
	RecountTempTooltip:ClearLines()
	RecountTempTooltip:SetHyperlink("unit:" .. nameGUID2)	
	
	local tooltipName = "RecountTempTooltip"

	local textLeft, textRight, ttextLeft, ttextRight;

	for idx = 1, RecountTempTooltip:NumLines() do
		ttextLeft = getglobal(tooltipName.."TextLeft"..idx)
		if ttextLeft then
			textLeft = ttextLeft:GetText()
			if textLeft then
				Recount:Print("left"..idx..": "..textLeft)
			end
		else
			textLeft = nil
		end
			
		ttextRight = getglobal(tooltipName.."TextRight"..idx)
		if ttextRight then
			textRight = ttextRight:GetText()
			if textRight then
				Recount:Print("right"..idx..": "..textRight)
			end
		else
			textRight = nil
		end
	end
end

function Recount:GetGuardianOwnerByGUID(nameGUID)
	return Recount.GuardianOwnerGUIDs and Recount.GuardianOwnerGUIDs[nameGUID]
end

function Recount:GetInheritGuardian(owner)
	local latestGuardian = owner.GuardianReverseGUIDs[name].LatestGuardian
	local petName = owner.Pet
	local petGUID = owner.GuardianReverseGUIDs and owner.GuardianReverseGUIDs[petName] and owner.GuardianReverseGUIDs[petName].GUIDs[latestGuardian]
	return petName, petGUID
end

function Recount:TrackGuardianOwnerByGUID(owner, name, nameGUID)

	owner.GuardianReverseGUIDs = owner.GuardianReverseGUIDs or {}
	Recount.GuardianOwnerGUIDs = Recount.GuardianOwnerGUIDs or {}

	local oldGUID = owner.GuardianReverseGUIDs and owner.GuardianReverseGUIDs[name] and type(owner.GuardianReverseGUIDs[name])~="string"
	local latestGuardian = 0
	
	if not oldGUID then
	    owner.GuardianReverseGUIDs[name] = {}
		owner.GuardianReverseGUIDs[name].LatestGuardian = 0
		owner.GuardianReverseGUIDs[name].GUIDs =  {}
		owner.GuardianReverseGUIDs[name].GUIDs[latestGuardian] = nameGUID
		Recount.GuardianOwnerGUIDs[nameGUID]=owner.Name
	else
		if not owner.GuardianReverseGUIDs[name].LatestGuardian then
		   owner.GuardianReverseGUIDs[name].LatestGuardian = 0
		   owner.GuardianReverseGUIDs[name].GUIDs =  {}
		end

		latestGuardian = owner.GuardianReverseGUIDs[name].LatestGuardian+1

		owner.GuardianReverseGUIDs[name].GUIDs[latestGuardian] = nameGUID
		if latestGuardian > 12 then -- Elsia: Max guardians set to 20 for now: edit, reduced to 12 to improve performance
		   latestGuardian = 0
		end
		owner.GuardianReverseGUIDs[name].LatestGuardian = latestGuardian
		Recount.GuardianOwnerGUIDs[nameGUID]=owner.Name
	end
end

function Recount:DeleteGuardianOwnerByGUID(owner)
	if owner.GuardianReverseGUIDs then

		for k,v in pairs(owner.GuardianReverseGUIDs) do
			if Recount.GuardianOwnerGUIDs and owner.GuardianReverseGUIDs[v] and owner.GuardianReverseGUIDs[v].GUIDs then
			   	for i,v2 in ipairs(owner.GuardianReverseGUIDs[v].GUIDs) do
				    Recount.GuardianOwnerGUIDs[v2] = nil
				end
			end
		end
	end
end

function Recount:IsFriend(flags)
	return bit_band(flags,COMBATLOG_OBJECT_REACTION_FRIENDLY) ~= 0
end

function Recount:IsPlayer(flags)
	return bit_band(flags, COMBATLOG_OBJECT_TYPE_PLAYER)==COMBATLOG_OBJECT_TYPE_PLAYER
end
	
function Recount:IsPet(flags)
	return bit_band(flags,COMBATLOG_OBJECT_TYPE_PET+COMBATLOG_OBJECT_TYPE_GUARDIAN)~=0
end	
	
function Recount:InGroup(flags)	
	return bit_band(flags, COMBATLOG_OBJECT_AFFILIATION_MINE+COMBATLOG_OBJECT_AFFILIATION_PARTY+COMBATLOG_OBJECT_AFFILIATION_RAID)~=0
end
	
function Recount:IsFriendlyFire(srcFlags,dstFlags)

   return (bit_band(srcFlags,COMBATLOG_OBJECT_REACTION_FRIENDLY)~=0) and (bit_band(dstFlags,COMBATLOG_OBJECT_REACTION_FRIENDLY)~=0)

--	return (Recount:IsFriend(srcFlags)==Recount:IsFriend(dstFlags)) and ((Recount:IsPlayer(srcFlags) or Recount:IsPet(srcFlags)) and (Recount:IsPlayer(dstFlags) or Recount:IsPet(dstFlags))) -- We only care for friendly fire between players now Edit: and pets
end

local lastSummonPetName
local lastSummonPetGUID
local lastSummonOwnerName
local lastSummonOwnerGUID
	
function Recount:AddPetCombatant(nameGUID, petName, nameFlags, ownerGUID, owner, ownerFlags)
	if lastSummonOwnerGUID and lastSummonOwnerGUID == nameGUID then
		Recount:DPrint("Inheriting Pet: ".. lastSummonPetName.." from ".. petName)
		petName = lastSummonPetName
		nameGUID = lastSummonPetGUID
	else
		lastSummonPetName = petName
		lastSummonPetGUID = nameGUID
		lastSummonOwnerName = owner
		lastSummonOwnerGUID = ownerGUID
	end
	
	local name=petName.." <"..owner..">"
	local combatant=dbCombatants[name] or {}

	if bit_band(ownerFlags, COMBATLOG_OBJECT_AFFILIATION_MINE+COMBATLOG_OBJECT_AFFILIATION_PARTY+COMBATLOG_OBJECT_AFFILIATION_RAID+COMBATLOG_OBJECT_REACTION_FRIENDLY)==0 then
		--return -- Elsia: We only keep affiliated or friendly pets. These flags can be horribly wrong unfortunately
	end
	
	if petName:match("<(.-)>") or owner:match("<(.-)>") then
		--Recount:DPrint(petName.." : "..owner.." !Double owner detected! Please report the trace below")
		--Recount:DPrint(debugstack(2, 3, 2))
			
		
	end
	
	local inheritowner = Recount:GetGuardianOwnerByGUID(ownerGUID)
	if inheritowner then -- This should only happen for pets of pets such as greater elementals
		owner = inheritowner 
	end
	
	--local elementschool = petName:match("(.*) Elemental Totem")
	--Recount:Print(petName.." "..(elementschool or "nil").." "..nameGUID:sub(3,-1))
--	if bit_band(nameFlags, COMBATLOG_OBJECT_TYPE_GUARDIAN) then
--[[		local mobid = tonumber(nameGUID:sub(3+6,3+9),16) -- Removed this for inheritance testing
		if Recount.ElementalMobID[mobid] then -- This really summoned a greater fire elemental totem, which is what we really care about.

			--Recount:Print("Elem!")
			gopts = {nameGUID, petName, nameFlags, ownerGUID, owner, ownerFlags }
			Recount:ScheduleTimer("AddGreaterElemental", 0.2, gopts)
		--else
			--Recount:Print(mobid)
		end--]]
		if dbCombatants[owner] then -- We have a valid stored owner.
			Recount:TrackGuardianOwnerByGUID(dbCombatants[owner], petName, nameGUID)
		else
			Recount:SetOwner(combatant,name,owner,ownerGUID,ownerFlags)
			if dbCombatants[owner] then -- We have a valid stored owner.
				Recount:TrackGuardianOwnerByGUID(dbCombatants[owner], petName, nameGUID)
--[[			else
				Recount.tempGuards = Recount.tempGuards or {}
				Recount.tempGuards[ownerGUID] = {}
				Recount.tempGuards[ownerGUID].name = owner
				Recount:TrackGuardianOwnerByGUID(Recount.tempGuards[ownerGUID], petName, nameGUID)
				Recount:DPrint("special guardian tracking: "..owner.." "..petName)
				end --]]
			end
		end
--	end

--[[	if Recount.tempGuards[petGUID] and dbCombatants[owner] then -- This propagates temporary guardians forward. Note that this ignores flags
		petName,nameGUID = Recount:GetInheritGuardian(Recount.tempGuards[petGUID])
		name=petName.." <"..owner..">"
		Recount:DPrint("special guardian tracking: "..name.." "..nameGUID)
		Recount.tempGuards = nil -- Get rid of it to avoid accummulation
	end --]]
		
	combatant.GUID=nameGUID
	combatant.LastFlags=nameFlags
	
	if combatant.Name then -- Already have such a pet!
		--Recount:DPrint("Pet1: "..name.." "..owner.." "..petName)
		return
	end
	
	combatant.Name=petName
	Recount:SetOwner(combatant,name,owner,ownerGUID,ownerFlags)
	combatant.type="Pet"
	combatant.enClass="PET"

	
	-- Elsia: We inherit flags from owner, as currently 2.4 ptr the pet flags are not useful (typically 0xa28 for outsider,neutral, npc)
	combatant.unit = Recount:FindPetUnitFromFlags(nameFlags, nameGUID)
	if combatant.unit then
		combatant.level = UnitLevel(combatant.unit)
	else
		combatant.level=dbCombatants[owner].level -- Elsia: For guardians and other unidentifiable unitid pets, assume the owner level (heuristic)
	end

	--Recount:DPrint("Pet2: "..name.." "..owner.." "..petName)
	
	combatant.LastFightIn=Recount.db2.FightNum
	combatant.UnitLockout=Recount.CurTime
	
end

function Recount:AddCombatant(name,owner,nameGUID,nameFlags,ownerGUID)
	local combatant = {}
	
	if not nameFlags then
		Recount:Print("Improper: ".. name.." "..(nameFlags or "nil"))

		return -- Elsia: Improper!
	end

	combatant.GUID=nameGUID
	
	-- Handle Attributes that can be extracted from flags.
	local inGroup = Recount:InGroup(nameFlags) --bit_band(nameFlags, COMBATLOG_OBJECT_AFFILIATION_MINE+COMBATLOG_OBJECT_AFFILIATION_PARTY+COMBATLOG_OBJECT_AFFILIATION_RAID)~=0
	local isPlayer=Recount:IsPlayer(nameFlags) --bit_band(nameFlags, COMBATLOG_OBJECT_TYPE_PLAYER)==COMBATLOG_OBJECT_TYPE_PLAYER
	local isFriend=Recount:IsFriend(nameFlags) --bit_band(nameFlags,COMBATLOG_OBJECT_REACTION_FRIENDLY) ~= 0
	
	-- Handle identified pets
	if owner then
		combatant.Name=string_match(name,"(.-) <")
		if not combatant.Name then -- Elsia: not sure when this can happen
			Recount:DPrint("EEK:"..name.." "..owner)
			combatant.Name = name
			name = name.." <"..owner..">"
			Recount:DPrint(name)
		end
		if combatant.Name:match("<(.-)>") or owner:match("<(.-)>") then
			--Recount:DPrint(combatant.Name.." : "..owner.." !Double owner detected! Please report the trace below")
			--Recount:DPrint(debugstack(2, 3, 2))
		end
	
		Recount:SetOwner(combatant,name,owner,ownerGUID, Recount:CreateOwnerFlags(nameFlags))
		combatant.type="Pet"
		combatant.enClass="PET"
		combatant.level=1
--		combatant.unit = Recount:FindPetUnitFromFlags(nameFlags, nameGUID)
--		if combatant.unit then
--			combatant.level = UnitLevel(combatant.unit)
--		else
--			combatant.level=dbCombatants[owner].level -- Elsia: For guardians and other unidentifiable unitid pets, assume the owner level (heuristic)
--		end
	else
	-- Handle non-pet units
		combatant.Name=name
		combatant.Owner=false -- Not a pet
		
		-- Handle Friendly combatants
		if isFriend and (inGroup or isPlayer)  then
			-- Can find Unit from this
			--unit = Recount:FindUnitFromFlags(name,nameFlags)
			
--			if unit and combatant.isPlayer then -- Player Units
			if isPlayer then -- Player Units
				if Recount.PlayerName == name then
					combatant.type = "Self"
					_, combatant.enClass=UnitClass("player")
					combatant.level = UnitLevel("player")
				-- Handle Friendly grouped combatants
				elseif inGroup then
					local unit = Recount:FindUnitFromFlags(name,nameFlags)
					combatant.type = "Grouped"
					_, combatant.enClass=UnitClass(unit)
					combatant.level = UnitLevel(unit)
				-- Handle Friendly ungrouped combatants
				else
					combatant.type = "Ungrouped"
					local unit = Recount:FindTargetedUnit(name)
					if unit then
						_, combatant.enClass=UnitClass(unit)
						combatant.level = UnitLevel(unit)
					else
						combatant.enClass = "UNGROUPED" -- Check for target uid here
						combatant.level = 1
					end
				end
			else
				--Recount:Print("Got non-player grouped entity: "..name) -- Elsia: This proves to be pets!
				--Recount:Print(debugstack(2, 3, 2))
			end
				--combatant.unit=unit
				--combatant.level=UnitLevel(unit)
		-- Handle hostile combatants
		elseif isPlayer then
			combatant.type = "Hostile"
			local unit = Recount:FindTargetedUnit(name)
			if unit then
				_, combatant.enClass=UnitClass(unit)
				combatant.level = UnitLevel(unit)
			else
				combatant.enClass = "HOSTILE" -- Check for target uid here
				combatant.level = 1
			end
		elseif bit_band(nameFlags,COMBATLOG_OBJECT_NONE) ~= COMBATLOG_OBJECT_NONE then -- Mob units that were flag targets
			combatant.enClass="MOB"
			local unit = Recount:FindTargetedUnit(name)
			combatant.level=unit and UnitLevel(unit) or 1
			if unit and UnitIsTrivial(unit) then
				combatant.type="Trivial"
			elseif combatant.level==-1 or Recount.IsBoss(nameGUID) then 
		    	        combatant.level=-1
				combatant.type="Boss"
			else
				combatant.type="Nontrivial"
			end
			combatant.enClass="MOB"
		     else
			Recount:DPrint("Unknown spotted")
			combatant.type="Unknown"
			combatant.enClass="UNKNOWN"
		end
	end

	combatant.LastFightIn=Recount.db2.FightNum
	combatant.UnitLockout=Recount.CurTime
	dbCombatants[name]=combatant
	Recount:InitCombatant(name)
end

function Recount:InitCombatant(name)
	local combatant = dbCombatants[name]
	
	combatant.Fights = {}
end

function Recount:PartyPetOwnerFromGUID(who,petName,petGUID, petFlags)
	local ownerName, ownerGUID = Recount:FindOwnerPetFromGUID(petName,petGUID)
	--Recount:SetOwner(who,petName,ownerName, ownerGUID, Recount:CreateOwnerFlags(petFlags))
end

function Recount:SetOwner(who,petName,owner,ownerGUID,ownerFlags)

	who.Owner=owner

	if who.Owner then
		if not dbCombatants[who.Owner] then
			Recount:AddCombatant(who.Owner, nil,ownerGUID,ownerFlags)
		end
		if not dbCombatants[who.Owner].Pet then 
			dbCombatants[who.Owner].Pet = {}
		end
		
		for i,k in ipairs(dbCombatants[who.Owner].Pet) do -- Prevent multi-pet registration
			if k == petName then return end
		end
		tinsert(dbCombatants[who.Owner].Pet,petName)
	end
end

Recount.LastGroupCheck=0
function Recount:GroupCheck()
	local gettime = GetTime()

	if Recount.LastGroupCheck>gettime and gettime - Recount.LastGroupCheck <= 0.25 then
		return
	end
	Recount.LastGroupCheck=gettime+0.25

	for k,v in pairs(dbCombatants) do
	   if k ~= Recount.PlayerName then
	      local Unit = Recount:GetUnitIDFromName(k)

	      --Recount:Print(k.." "..(v.type or "nil").." "..(v.enClass or "nil"))
	      --Must be in our group
	      if Unit then
		 v.unit=Unit
		 v.type = "Grouped"
	      elseif v.type == "Grouped" then
		 v.type = "Ungrouped"
		 Recount:DeleteVersion(k)
	      end
	   end
	end
end

local FilterWeights={}
local FilterMiddle=0

function Recount:CreateFilterWeights()
	local sum=0
	local val,widthUp,widthDown
	local DownAt=FilterSize-RampDown
	widthUp=1/RampUp
	widthDown=1/RampDown

	for i=1,FilterSize do
		if i<=RampUp then
			val=i*widthUp
			FilterWeights[#FilterWeights+1]=val
			sum=sum+val
		elseif i<=DownAt then
			FilterWeights[#FilterWeights+1]=1
			sum=sum+1
		else
			val=(FilterSize-i+1)*widthDown
			FilterWeights[#FilterWeights+1]=val
			sum=sum+val
		end
	end
	for i=1,FilterSize do
		FilterWeights[i]=FilterWeights[i]/sum
		FilterMiddle=FilterMiddle+i*FilterWeights[i]
	end

	FilterMiddle=math_floor(FilterMiddle)-1
end

local LinComp=0.3
function Recount:CheckIfAlmostLinear(TimeData, NewTime, NewVal)
	if #TimeData[1]<=1 or (NewTime-TimeData[1][#TimeData[1]])>10 then
		return false
	end

	local MidTime=TimeData[1][#TimeData[1]]
	local MidValue=TimeData[2][#TimeData[2]]

	local Width=NewTime-TimeData[1][#TimeData[1]-1]
	local Lerp=(MidTime-TimeData[1][#TimeData[1]-1])/Width
	local LinValue=Lerp*NewVal+(1-Lerp)*TimeData[2][#TimeData[2]-1]

	if Lerp>0.5 then
		Lerp=1-Lerp
	end

	local Weight=(MidValue-LinValue)/(Lerp*Width)

	if Weight<0 then
		Weight=-Weight
	end

	if Weight<LinComp then
		return true
	end
	return false
end

function Recount:IsTimeDataActive()
   local filters =  Recount.db.profile.Filters
   for k,v in pairs(filters.TimeData) do
      if v and filters.Data[k] then
	 Recount.TickTimeData = true
	 return
      end
   end
   Recount.TickTimeData = nil
end

function Recount:TimeTick()
	if not Recount.db.profile.GlobalDataCollect or not Recount.CurrentDataCollect then
		return
	end
	
	local Time=time()

	--First check if combat status changed
	if Recount.InCombat then
	   Recount:CheckCombat(Time)
	end
	Recount.CurTime=Time
	Recount.UnitLockout=Time-5

	if Recount.TickTimeData then
	   local TimeCheck=Time-FilterSize-1
	   local gotdeleted

	   --Need to increment where data gets put and erase the old ones
	   Recount.TimeStep=Recount.TimeStep+1
	   if Recount.TimeStep>FilterSize then
	      Recount.TimeStep=1
	   end
	   
	   local filters =  Recount.db.profile.Filters
	   
	   for name,v in pairs(Recount.db2.combatants) do
	      local ctype = v.type
	      if filters.Data[ctype] and filters.TimeData[ctype] and v.TimeLast and v.TimeLast["OVERALL"] and v.TimeLast["OVERALL"]>=TimeCheck then -- Elsia: Added global collection switch
		 --First threat data
	      
		 for k, v2 in pairs(v.TimeWindows) do
		    local Temp
		    local NewEntry=0
		    
		    if v.TimeLast and v.TimeLast[k] and v.TimeLast[k]>=TimeCheck then
		       --Something is strange here but this works
		       for k,v3 in ipairs(v2) do
			  Temp = (FilterSize-k)+Recount.TimeStep
			  if Temp>FilterSize then
			     NewEntry=NewEntry+v3*FilterWeights[Temp-FilterSize]
			  else
			     NewEntry=NewEntry+v3*FilterWeights[Temp]
			  end
		       end
		       --Need to set where we will be putting new data to 0
		       v2[Recount.TimeStep]=0
		    end
		    
		    v.TimeData = v.TimeData or {}
		    v.TimeData[k] = v.TimeData[k] or {{},{}}
		    local TimeData=v.TimeData[k]
		    if NewEntry~=0 then
		       --do we need a leading zero?
		       if not v.TimeNeedZero or not v.TimeNeedZero[k] then
			  TimeData[1][#TimeData[1]+1]=Time-1-FilterMiddle
			  TimeData[2][#TimeData[2]+1]=0
			  
			  v.TimeNeedZero = v.TimeNeedZero or {}
			  v.TimeNeedZero[k]=true
		       end
		       
		       if not Recount:CheckIfAlmostLinear(TimeData, Time-FilterMiddle, NewEntry) then
			  TimeData[1][#TimeData[1]+1]=Time-FilterMiddle
			  TimeData[2][#TimeData[2]+1]=NewEntry
		       else
			  --If almost linear write over the old value
			  TimeData[1][#TimeData[1] ]=Time-FilterMiddle
			  TimeData[2][#TimeData[2] ]=NewEntry
		       end
		    elseif v.TimeNeedZero and v.TimeNeedZero[k] then --Check if we need a trailing zero
		       TimeData[1][#TimeData[1]+1]=Time-FilterMiddle
		       TimeData[2][#TimeData[2]+1]=0
		       v.TimeNeedZero = v.TimeNeedZero or {}
		       v.TimeNeedZero[k]=false
		    end
		 end
	      end
	      
	      
	      local idler = v.type == "Unknown" or v.enClass == "UNKNOWN" or (not filters.Data[v.type] and not filters.Show[v.type])
	      
	      v.LastActive = v.LastActive or Time
	      if idler and Time-v.LastActive > 30 then
		 Recount:DeleteCombatant(name)
		 gotdeleted = true
		 --		elseif idler then
		 --			Recount:Print(name.."t: "..(Time-v.LastActive))
	      end
	      
	      --		if name == Recount.Player and not v.inGroup then
	      --			Recount:GroupCheck()
	      --			--if not v.inGroup then
	      --				--Recount:DPrint("Yikes, can't get player into group status!")
	      --			--end
	      --		     end
	   end
	   if gotdeleted then
	      Recount:SetMainWindowMode(Recount.db.profile.MainWindowMode)
	      Recount:FullRefreshMainWindow()
	   end

	   if Recount.db.profile.AutoDelete and math_fmod(Time,10)==0 then
	      Recount:DeleteOldTimeData(Time)
	   end
	end
end

function Recount:PutInCombat()
	Recount.InCombat=true
	Recount.InCombatT=Recount.CurTime
	Recount.InCombatT2=GetTime()
	Recount.InCombatF=date("%H:%M:%S")
	Recount.FightingWho=""
	Recount.FightingLevel=0

	if Recount.db.profile.MainWindow.AutoHide then
		Recount.MainWindow:Hide()
	end

	if Recount.db.profile.CurDataSet=="LastFightData" then
		Recount.db.profile.CurDataSet="CurrentFightData"
		
	end

	--If current mode is not overall data we need to reset disp table
	if Recount.db.profile.CurDataSet=="CurrentFightData" then -- Elsia: Fix for double entry in CurAndLast mode
		Recount.MainWindow.DispTableSorted=Recount:GetTable()
		Recount.MainWindow.DispTableLookup=Recount:GetTable()
	end
	
	if RecountDeathTrack then
		RecountDeathTrack:SetFight(Recount.db.profile.CurDataSet)
	end
end


function Recount:CheckCombat(Time)
   
   if Recount:CheckPartyCombatWithPets() then
      if Recount.db.profile.EnableSync then
	 Recount:CheckVisible()
      end
   else
      Recount:LeaveCombat(Time)
   end
end

--Moved into a seperate function
function Recount:LeaveCombat(Time)

	if Recount.db.profile.MainWindow.AutoHide then
		Recount.RefreshMainWindow()
		Recount.MainWindow:Show()
	end

	--Did we actually fight someone?
	Recount.InCombat=false
	if (Recount.FightingWho=="") then
		return
	end

	-- Elsia: Only sync for actual fights
	if Recount.db.profile.GlobalDataCollect and Recount.CurrentDataCollect and Recount.db.profile.EnableSync  then -- Elsia: Only sync if collecting
		Recount:BroadcastLazySync()
	end

	if abs(Time-Recount.InCombatT)>3 then
		Recount.db2.CombatTimes[#Recount.db2.CombatTimes+1]={Recount.InCombatT,Time,Recount.InCombatF,date("%H:%M:%S"),Recount.FightingWho}

		--Save current data as the last fight
		Recount.Fights:MoveFights()

		if Recount.db.profile.CurDataSet=="CurrentFightData" then
			Recount.db.profile.CurDataSet="LastFightData"
		end

		--If current mode is not overall data we need to reset disp table
		if Recount.db.profile.CurDataSet~="OverallData" then
			Recount.MainWindow.DispTableSorted=Recount:GetTable()
			Recount.MainWindow.DispTableLookup=Recount:GetTable()
		end

		Recount.db2.FightNum=Recount.db2.FightNum+1
	else
		Recount.Fights:CopyCurrentFights()

	end
	
end

function Recount:DeleteOldTimeData(Time)
	local DeleteTime=Time-60*Recount.db.profile.AutoDeleteTime

	for name,v in pairs(dbCombatants) do
		if v.TimeData then
			for _,Check in pairs(v.TimeData) do
				while Check[1][1] and Check[1][1]<DeleteTime do
					tremove(Check[1],1)
					tremove(Check[2],1)
				end
			end
		end
	end

	local Fights=Recount.db2.CombatTimes

	while Fights[1] and Fights[1][2]<DeleteTime do
		tremove(Fights,1)
	end
end

function Recount:FixLastTime()
	local Time=GetTime()
	for name,v in pairs(dbCombatants) do
		v.LastAbility=Time
	end
end

function Recount:DelayedResizeWindows()
	Recount:ResizeMainWindow()
	--DelayedResizeWindows=nil
end

function Recount:HandleProfileChanges()
	if not Recount.MainWindow then
		return
	end

	Recount:SetBarTextures(Recount.db.profile.BarTexture)
	Recount:RestoreMainWindowPosition(Recount.db.profile.MainWindow.Position.x,Recount.db.profile.MainWindow.Position.y,Recount.db.profile.MainWindow.Position.w,Recount.db.profile.MainWindow.Position.h)
	Recount:ResizeMainWindow()
	Recount:FullRefreshMainWindow()
	Recount:SetupMainWindowButtons()

	if Recount.db.profile.GraphWindow then
		Recount.GraphWindow:ClearAllPoints()
		Recount.GraphWindow:SetPoint("TOPLEFT",UIParent,"TOPLEFT",Recount.db.profile.GraphWindowX,Recount.db.profile.GraphWindowY)
	end

	if Recount.db.profile.DetailWindow then
		Recount.DetailWindow:ClearAllPoints()
		Recount.DetailWindow:SetPoint("TOPLEFT",UIParent,"TOPLEFT",Recount.db.profile.DetailWindowX,Recount.db.profile.DetailWindowY)
	end

	Recount.profilechange = true
	Recount:CloseAllRealtimeWindows()
	
	if Recount.db.profile.RealtimeWindows then
		local Windows=Recount.db.profile.RealtimeWindows
		for k,v in pairs(Windows) do
			if v[8] and v[8] == true then -- Elsia: Make sure to respect closed windows as closed on startup
				Recount:CreateRealtimeWindowSized(v[1],v[2],v[3],v[4],v[5],v[6],v[7])
			end
		end
	end
	Recount.Colors:UpdateAllColors()
	Recount.profilechange = nil

	Recount:ShowConfig()
	
	Recount:SetStrataAndClamp()
	
	Recount:LockWindows(Recount.db.profile.Locked)
end

function Recount:InitCombatData()
	Recount.db2.combatants = Recount.db2.combatants or {}
	Recount.db2.CombatTimes = Recount.db2.CombatTimes or {}
	Recount.db2.FoughtWho = Recount.db2.FoughtWho or {}
	
end

function Recount.LocalizeCombatants()
	dbCombatants = Recount.db2.combatants
end

function Recount:OnInitialize()
	local acedb = LibStub:GetLibrary("AceDB-3.0")
	Recount.db = acedb:New("RecountDB", Default_Profile)
--	Recount.db2 = acedb:New("RecountPerCharDB", DefaultConfig)
	RecountPerCharDB = RecountPerCharDB or {}
	Recount.db2 = RecountPerCharDB
	Recount.db2.char = nil -- Elsia: Dump old db data hard.
	Recount.db2.global = nil
	
	Recount:InitCombatData()
	Recount.LocalizeCombatants()

	self.db.RegisterCallback( self, "OnNewProfile", "HandleProfileChanges" )
	self.db.RegisterCallback( self, "OnProfileReset", "HandleProfileChanges" )
	self.db.RegisterCallback( self, "OnProfileChanged", "HandleProfileChanges" )
	self.db.RegisterCallback( self, "OnProfileCopied", "HandleProfileChanges" )

	Recount.consoleOptions2.args.profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(Recount.db)
	LibStub("AceConfig-3.0"):RegisterOptionsTable("Recount", Recount.consoleOptions2, "recount")
	LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("Recount Report",Recount.consoleOptions2.args.report)
	LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("Recount Realtime",Recount.consoleOptions2.args.realtime)
 	LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("Recount Blizz", Recount.consoleOptions)

	LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("Recount Profile", Recount.consoleOptions2.args.profile)
	
	AceConfigDialog:AddToBlizOptions("Recount Blizz", "Recount")
	AceConfigDialog:AddToBlizOptions("Recount Profile", "Profile", "Recount")
	AceConfigDialog:AddToBlizOptions("Recount Report", "Report", "Recount")
	AceConfigDialog:AddToBlizOptions("Recount Realtime", "Realtime", "Recount")
	
	if Recount.db2["version"]~=DataVersion then
		Recount:ResetData()

		Recount.db2.version=DataVersion
	end

	RecountTempTooltip = CreateFrame("GameTooltip", "RecountTempTooltip", nil, "GameTooltipTemplate")
	RecountTempTooltip:SetOwner(UIParent, "ANCHOR_NONE")

	Recount.TimeStep=1
	Recount.InCombat=false
	Recount.db.profile.CurDataSet=Recount.db.profile.CurDataSet or "OverallData"

	if Recount.db.profile.CurDataSet=="CurrentFightData" then
		Recount.db.profile.CurDataSet="LastFightData"
	end
	
	Recount.FightingLevel=0
	Recount.CurTime=time()

	Recount.CurrentDataCollect = true
	
	Recount:CreateMainWindow()

	Recount:CreateDetailWindow()
	Recount:CreateGraphWindow()
	Recount:CreateFilterWeights()
	Recount:InitOrder()

	Recount:SetupMainWindow()
	Recount:ScheduleTimer("DelayedResizeWindows",0.1)

	SM.RegisterCallback(Recount, "LibSharedMedia_Registered", "UpdateBarTextures")
	SM.RegisterCallback(Recount, "LibSharedMedia_SetGlobal", "UpdateBarTextures")
	if Recount.db.profile.BarTexture then
		Recount:SetBarTextures(Recount.db.profile.BarTexture)
	end

	if Recount.db.profile.GraphWindowX then
		Recount.GraphWindow:ClearAllPoints()
		Recount.GraphWindow:SetPoint("TOPLEFT",UIParent,"TOPLEFT",Recount.db.profile.GraphWindowX,Recount.db.profile.GraphWindowY)
	end

	if Recount.db.profile.DetailWindowX then
		Recount.DetailWindow:ClearAllPoints()
		Recount.DetailWindow:SetPoint("TOPLEFT",UIParent,"TOPLEFT",Recount.db.profile.DetailWindowX,Recount.db.profile.DetailWindowY)
	end

	if Recount.db.profile.RealtimeWindows then
		local Windows=Recount.db.profile.RealtimeWindows
		for k,v in pairs(Windows) do
			if v[8] and v[8] == true then -- Elsia: Make sure to respect closed windows as closed on startup
				Recount:CreateRealtimeWindowSized(v[1],v[2],v[3],v[4],v[5],v[6],v[7])
			end
		end
	end
	
	Recount.PlayerName=UnitName("player")
	Recount.PlayerGUID=nil
	Recount.PlayerLevel=UnitLevel("player")

--	Recount.GuardiansGUIDs={} -- No need to db, guardians are not persistent GUIDs
--	Recount.LatestGuardian=0

	Recount.EventNum={}
	Recount.EventNum["DAMAGE"]={}
	Recount.EventNum["HEALING"]={}

	if Recount.db.profile.EnableSync then
		Recount:ConfigComm()
	end
	
	Recount:FixLastTime()
	--Recount:ScaleWindows(Recount.db.profile.Scaling,true)
	Recount:ScaleWindows(Recount.db.profile.Scaling) -- Elsia: Bug: Even for first time we need in place code for scaling.

	Recount:SetStrataAndClamp()
	
	Recount:LockWindows(Recount.db.profile.Locked)
end

function Recount:OnEnable(first)

        Recount:IsTimeDataActive() -- Make sure we don't tick time data if we don't have to.
	Recount.TimeTick() -- Elsia: Prevent that time data is not initialized when an event comes in before the first tick.
	
	Recount:ScheduleTimer("GroupCheck",2) -- Elsia: Lowered this and synced duration with party based collection check

	Recount:ScheduleRepeatingTimer("TimeTick",1)

	--Recount:RegisterEvent("Threat_Activate") -- Elsia: Threat-1.0 deactivated until Threat-2.0 is ready.
	--Recount:RegisterEvent("Threat_Deactivate")

--	Recount:RegisterEvent("UNIT_PET")
--	Recount:RegisterEvent("PLAYER_PET_CHANGED")

	Recount:RegisterEvent("ZONE_CHANGED_NEW_AREA","DetectInstanceChange") -- Elsia: This is needed for zone change deletion and collection
	Recount:RegisterEvent("PLAYER_ENTERING_WORLD","DetectInstanceChange") -- Attempt to fix Onyxia instance entrance which isn't a new zone.
	
	Recount:DetectInstanceChange() -- Elsia: We need to do this regardless for Zone filtering.

	--if Recount.db.profile.DeleteJoinRaid or Recount.db.profile.DeleteJoinGroup then
		Recount:ScheduleTimer("InitPartyBasedDeletion", 2) -- Elsia: Wait 5 seconds before enabling auto-delete to prevent startup popups.
	--end -- Elsia: This is obsolete due to deletion code also handling visibility and solo collection checks.
	
	--Parser Events
	Recount:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED","CombatLogEvent")
	
	if RecountDeathTrack then
		RecountDeathTrack:SetFight(Recount.db.profile.CurDataSet)
	end
	
	Recount.HasEnabled=true
end

function Recount:OnDisable()
	if not Recount.HasEnabled then
		return
	end
	Recount.HasEnabled=false
	Recount:UnregisterAllEvents()
end

function Recount:Threat_Activate()
	Recount.ThreatActive=true
end

function Recount:Threat_Deactivate()
	Recount.ThreatActive=false
end

local Tables={}
function Recount:FreeTable(t)

	if type(t)~="table" then
		return
	end

	for k in pairs(t) do
		t[k]=nil
	end

	for _,v in pairs(Tables) do
		if v==t then
			return
		end
	end

	tinsert(Tables,t)
end

function Recount:FreeTableRecurse(t)
	--Check the table first before recursing
	for _,v in pairs(Tables) do
		if v==t then
			return
		end
	end

	for k in pairs(t) do
		if type(t[k])=="table" then
			Recount:FreeTableRecurse(t[k])
		end
		t[k]=nil
	end

	tinsert(Tables,t)
end

function Recount:FreeTableRecurseLimit(t,depth)
	--Check the table first before recursing
	if depth<0 then
		return
	end

	for k in pairs(t) do
		if type(t[k])=="table" then
			Recount:FreeTableRecurseLimit(t[k],depth-1)
		end
		t[k]=nil
	end

	tinsert(Tables,t)
end

function Recount:GetTable()
	local t
	if #Tables>0 then
		t=Tables[1]
		tremove(Tables,1)
		if #t>0 then
			Recount:Print("WARNING! For some reason there is "..#t.." entries left. There is probably a table in use that shouldn't have been freed")
		end
		return t
	else
		return {}
	end
end

function Recount:HowManyTables(str)
	if str==nil then
		str=""
	else
		str=str.." "
	end
	Recount:Print(str.."Free Tables: "..#Tables)
end

function Recount:ResetTableCache()
	Tables=Recount:GetTable()
end

function Recount:ResetPositions()
	Recount:ResetPositionAllWindows()
end

local TestPie
local Amount=0
function Recount:TestPie()
	TestPie:ResetPie()
	TestPie:AddPie(Amount,{0.0,1.0,0.0})
	TestPie:CompletePie({0.2,0.2,1.0})

	Amount=Amount+1
	if Amount>=100 then
		Amount=1
	end
end

local function TestPieChart()
	local Graph = LibStub:GetLibrary("LibGraph-2.0")
	local g=Graph:CreateGraphPieChart("TestPieChart",UIParent,"LEFT","LEFT",0,0,150,150)
	TestPie=g
	g:AddPie(35,{1.0,0.0,0.0})
	g:AddPie(21,{0.0,1.0,0.0})
	g:CompletePie({0.2,0.2,1.0})
	Recount:ScheduleRepeatingTimer("PieTest",Recount.TestPie,0)
end
