local compost = AceLibrary("Compost-2.0")
local parser = ParserLib:GetInstance("1.1")
local roster = AceLibrary("RosterLib-2.0")

-- Link these after all files are loaded.
local defaultFormats
local defaultColors
local L

------------------------
--         Core         --
------------------------

SimpleCombatLog = AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceDebug-2.0")

-- Return a deep copy of the table.
function SimpleCombatLog.CopyTable(into, from)
	for key, val in pairs(from) do
		if( type(val) == "table" ) then
			if not into[key] then into[key] = {} end
			SimpleCombatLog.CopyTable(into[key], val)
		else
			into[key] = val
		end
	end
	return into
end

--- SimpleCombatLog.modulePrototype.core = SimpleCombatLog

-- Hook the FCF_Tab_OnClick() to check for alt-rightclick.
function SimpleCombatLog:FCF_Tab_OnClick(button)
	if IsAltKeyDown() and button == 'RightButton' then
		self:LoadSettingMenu(this:GetID())
	else
		self.old_FCF_Tab_OnClick(button)
	end
end

-- Hook ChatFrame_OnEvent to suppress the default combat log.
function SimpleCombatLog:ChatFrame_OnEvent(event)
	local id = this:GetID()
	
	-- Note to self: must do ( self.events[event] == nil ) here, cannot do  ( not self.events[event] ), since some events can be 'false' by default.
	if self.events[event] == nil or not id or not self.settings[id] or not self.settings[id].suppress then
		self.old_ChatFrame_OnEvent(event)
	end
end



-- Interested events, the flag are also used as the default theme event settings. (So false has a different meaning to nil here)
SimpleCombatLog.events = {
	['CHAT_MSG_COMBAT_PET_HITS'] = true,
	['CHAT_MSG_COMBAT_PET_MISSES'] = true,
	['CHAT_MSG_COMBAT_SELF_HITS'] = true,
	['CHAT_MSG_COMBAT_SELF_MISSES'] = true,	
	['CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS'] = true,
	['CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES'] = true,
	['CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS'] = true,
	['CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES'] = true,
	['CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS'] = true,
	['CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES'] = true,
	['CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS'] = true,
	['CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES'] = true,
	['CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS'] = true,
	['CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES'] = true,
	['CHAT_MSG_COMBAT_PARTY_HITS'] = true,
	['CHAT_MSG_COMBAT_PARTY_MISSES'] = true,
	['CHAT_MSG_SPELL_PET_BUFF'] = true,
	['CHAT_MSG_SPELL_PET_DAMAGE'] = true,
	['CHAT_MSG_SPELL_SELF_BUFF'] = true,
	['CHAT_MSG_SPELL_SELF_DAMAGE'] = true,
	['CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF'] = true,
	['CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE'] = true,
	['CHAT_MSG_SPELL_CREATURE_VS_PARTY_BUFF'] = true,
	['CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE'] = true,
	['CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF'] = true,
	['CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE'] = true,
	['CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF'] = true,
	['CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE'] = true,
	['CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF'] = true,
	['CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE'] = true,
	['CHAT_MSG_SPELL_PARTY_BUFF'] = true,
	['CHAT_MSG_SPELL_PARTY_DAMAGE'] = true,
	['CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS'] = true,
	['CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE'] = true,
	['CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS'] = true,	
	['CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF'] = true,	
	['CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS'] = true,
	['CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE'] = true,
	['CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS'] = true,
	['CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE'] = true,
	['CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS'] = true,
	['CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE'] = true,
	['CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS'] = true,
	['CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE'] = true,
	['CHAT_MSG_SPELL_AURA_GONE_OTHER'] = true,
	['CHAT_MSG_SPELL_AURA_GONE_SELF'] = true,
	['CHAT_MSG_SPELL_AURA_GONE_PARTY'] = true,
	['CHAT_MSG_SPELL_BREAK_AURA'] = true,
	['CHAT_MSG_COMBAT_FRIENDLY_DEATH'] = true,
	['CHAT_MSG_COMBAT_HOSTILE_DEATH'] = true,
	['CHAT_MSG_SPELL_ITEM_ENCHANTMENTS'] = true,
	['CHAT_MSG_COMBAT_XP_GAIN'] = true,
	['CHAT_MSG_COMBAT_HONOR_GAIN'] = true,
	['CHAT_MSG_COMBAT_FACTION_CHANGE'] = true,
	['CHAT_MSG_SPELL_TRADESKILLS'] = true,
	['CHAT_MSG_SPELL_FAILED_LOCALPLAYER'] = false,
}

SimpleCombatLog.defaultColors = {

	player = "7f7fff",
	pet = "7f4c26",
	raid = "ff7133",
	party = "a5ffa5",
	target = "ff77ff",
	targettarget = "994c99",
	other = "ffffff",
	
	physical = "ffffff",
	holy = "ffff4c",
	fire = "ff262d",
	nature = "66ff66",
	frost = "4c4ce5",
	shadow = "ffb2ff",
	arcane = "bfbfbf",
	
	heal = "ffff4c",
	miss = "ff7f7f",
	buff = "33ff33",
	debuff = "ff3333",
	skill = "ffff66",
	
	dirty = "eda55f",
}


function SimpleCombatLog:OnInitialize()
	
	defaultFormats = self.loc.defaultFormats
	defaultColors = self.defaultColors
	L = self.loc.core
	
	-- nil out the localization table, so that unused part will be GC'ed out.
	self.loc = nil
	
	self.old_FCF_Tab_OnClick = FCF_Tab_OnClick
	FCF_Tab_OnClick = function(button) self:FCF_Tab_OnClick(button) end
	
	self.old_ChatFrame_OnEvent = ChatFrame_OnEvent
	ChatFrame_OnEvent = function(event) self:ChatFrame_OnEvent(event) end

	-- index to Blizzard chat frames.
	self.chatFrames = { ChatFrame1, ChatFrame2, ChatFrame3, ChatFrame4, ChatFrame5, ChatFrame6, ChatFrame7 } 
	
	self:RegisterChatCommand( { "/scl" }, {
		type = 'group',
		args = {
			help = {	
				type = 'execute',
				name = 'help',
				desc = L["CmdHelpDesc"],
				func = "ShowHelp",
			},
			reset = {
				type = 'execute',
				name = 'reset',
				desc = L["CmdResetDesc"],
				func = "LoadInitialSettings",
			},
			show = {
				type = 'text',
				name = 'show',
				desc = L["CmdShowDesc"],
				get = false,
				set = function(id) self:LoadSettingMenu(tonumber(id)) end,
-- 				input = true, 	-- dunno why, this isn't working.
				validate = { '1', '2', '3', '4', '5', '6', '7' },
				usage = "<ChatFrame ID>",
			}
		}
	} )
	

	self:InitGlobalDB()
	self:LoadThemes()

	self.settings = {}

	self:InitPerCharDB()
	self:LoadSettings()
	
	if self.firstLoad then
		self:LoadInitialSettings()
		self:ShowHelp()
	end

	
end

function SimpleCombatLog:InitGlobalDB()
	
	if not SimpleCombatLogDB or not SimpleCombatLogDB.version then
		self:Print("SCL version changed, resetting global data.")
		SimpleCombatLogDB = {
			version = self.version,
			themes = {}
		}
	end
	
	self.themeDB = SimpleCombatLogDB.themes	
end

function SimpleCombatLog:InitPerCharDB()

	if not SimpleCombatLogDBPerChar or not SimpleCombatLogDBPerChar.version then
		self:Print("SCL version changed, resetting per-char data.")
		self.firstLoad = true		
		SimpleCombatLogDBPerChar = {
			version = self.version,
			settings = {}
		}
	end	
	
	self.settingDB = SimpleCombatLogDBPerChar.settings
end

-- Load themes into 
function SimpleCombatLog:LoadThemes()
	for i, theme in pairs(self.themeDB) do
		self.themes[i] = theme
	end	
end

function SimpleCombatLog:SetTheme(id, themeName)
	local themeTable
	
	if self.themes[themeName] then
		self.settingDB[id] = themeName
		self.settings[id] = self.themes[themeName]
	end		
	
	self:RefreshSettings()
end

function SimpleCombatLog:LoadSettings()
	for id, setting in pairs(self.settingDB) do
		if type(setting) == 'string' then -- this is a theme.
			self:SetTheme(id, setting)
			-- self.settings[id] = self.themes[setting]
		else
			self.settings[id] = setting
		end
	end
end

function SimpleCombatLog:ShowHelp()
	for i, msg in ipairs(L["Welcome"]) do
		self:Print(msg)
	end
end

function SimpleCombatLog:OnEnable()
	self:RefreshSettings()
end

function SimpleCombatLog:OnDisable()
	parser:UnregisterAllEvents("SimpleCombatLog")
end


function SimpleCombatLog:OnCombatEvent(event, info)
	self:Debug("OnCombatEvent", event, arg1, info.type)

	-- Parse for the message type.
	local infoType = info.type
	local msgType
	if infoType == 'hit' then
		if info.isCrit then 
			msgType = 'hitCrit'
		elseif info.isDOT then 
			msgType = 'hitDOT'
		else
			msgType = 'hit'
		end
	elseif infoType == 'heal' then
		if info.isCrit then
			msgType = 'healCrit'
		elseif info.isDOT then
			msgType = 'healDOT'
		else
			msgType = 'heal'
		end
	elseif infoType == 'dispel' then
		if info.isFailed then
			msgType = 'dispelFailed'
		else
			msgType = 'dispel'
		end
	elseif infoType == 'cast' then
		if info.isBegin then
			msgType = 'castBegin'
		elseif info.victim then
			msgType = 'castTargeted'
		else
			msgType = 'cast'
		end
	elseif infoType == 'honor' then
		if not info.amount then
			msgType = 'dishonor'
		elseif info.source then
			msgType = 'honorKill'
		else
			msgType = 'honor'
		end
	elseif info.type == 'reputation' then
		if info.rank then
			msgType = 'reputationRank'
		elseif info.isNegative then
			msgType = 'reputationMinus'
		else
			msgType = 'reputation'
		end
	elseif info.type == 'death' then
		if info.source then
			msgType = 'deathSource'
		elseif info.skill then
			msgType = 'deathSkill'
		else
			msgType = 'death'
		end
	elseif info.type == 'unknown' then
		ChatFrame1:AddMessage(string.format("%s: %s", event, info.message),1,0,0)
		return
	else
		msgType = infoType
	end

	-- Get necessary fields out of info table.
	local tokens = compost:Acquire()
	local fields = defaultFormats[msgType][2]
	for i, v in pairs(fields) do
		tokens[v] = info[v]
	end
	
	-- Common conversion for all chat frames.
	if tokens.skill == ParserLib_MELEE then tokens.skill = L["Melee"] end
	if tokens.skill == ParserLib_DAMAGESHIELD then tokens.skill = L["Damage Shields"] end
	
	if infoType == 'hit' then
		if not info.element then
			tokens.element = 'physical'
		else
			tokens.element = self:GetElementType(info.element)
		end
	elseif infoType == 'heal' then
		tokens.element = 'heal'
	elseif infoType == 'buff' or infoType == 'debuff' then
		if info.amountRank then
			tokens.skill = string.format("%s(%d)", tokens.skill, info.amountRank)
		end
		tokens.element = infoType
	elseif infoType == 'durability' then
		if not tokens.item then tokens.item = L["All Items"] end
	elseif infoType == 'miss' then
		tokens.missType = L.missType[tokens.missType]
	elseif infoType == 'environment' then
		tokens.damageType = L.damageType[tokens.damageType]
	end

	for id, settings in pairs(self.settings) do
		if settings.events and settings.events[event] and self:FilterCheck(id, info) then
			if infoType == 'hit' or infoType == 'environment' then
				tokens.trailers = self:GetTrailerString(id, info)
			elseif info.type == 'experience' then
				tokens.trailers = self:GetExpTrailerString(id, info)
			end
			self:ParseInfo(id, msgType, tokens)
		end
	end
	
	compost:Reclaim(tokens)

end

function SimpleCombatLog:ParseInfo(id, msgType, tokens)
	self:Debug("ParseInfo", id, msgType)
	
	local settings = self.settings[id]
	
	local myTokens = compost:Acquire()
	for i, v in pairs(tokens) do
		myTokens[i] = v
	end
	
	if myTokens.source then 
		if myTokens.source == ParserLib_SELF then
			myTokens.source = self:Colorize(L["You"], self:GetColorHex(id, 'player' ) )
		else
			myTokens.source = self:Colorize(myTokens.source, self:GetColorHex(id, self:GetUnitType(myTokens.source, true) ) )
		end
	end	
	if myTokens.victim then 
		if myTokens.victim == ParserLib_SELF then
			myTokens.victim = self:Colorize(L["You"], self:GetColorHex(id, 'player' ) )
		else
			myTokens.victim = self:Colorize(myTokens.victim, self:GetColorHex(id, self:GetUnitType(myTokens.victim, true) ) )
		end
	end
	if myTokens.sourceGained then 
		if myTokens.sourceGained == ParserLib_SELF then
			myTokens.sourceGained = self:Colorize(L["You"], self:GetColorHex(id, 'player' ) )
		else
			myTokens.sourceGained = self:Colorize(myTokens.sourceGained, self:GetColorHex(id, self:GetUnitType(myTokens.sourceGained, true) ) )
		end
	end	
	
	if myTokens.skill then
		if	settings.colorspell and myTokens.element then
			myTokens.skill = self:Colorize(myTokens.skill, self:GetColorHex(id, myTokens.element) )
		else
			myTokens.skill = self:Colorize(myTokens.skill, self:GetColorHex(id, "skill") )
		end
	end
	
	if myTokens.amount and myTokens.element then
		myTokens.amount = self:Colorize(myTokens.amount, self:GetColorHex(id, myTokens.element) )
	end
	
	local fields = defaultFormats[msgType][2]
	local fieldCount = table.getn(fields)
	
	local outputString
	if fieldCount == 0 then
		outputString = self:GetFormat(id, msgType)
	elseif fieldCount == 1 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ] )
	elseif fieldCount == 2 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ] )
	elseif fieldCount == 3 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ], myTokens[fields[3] ] )
	elseif fieldCount == 4 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ], myTokens[fields[3] ], myTokens[fields[4] ] )
	elseif fieldCount == 5 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ], myTokens[fields[3] ], myTokens[fields[4] ], myTokens[fields[5] ] )
	elseif fieldCount == 6 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ], myTokens[fields[3] ], myTokens[fields[4] ], myTokens[fields[5] ], myTokens[fields[6] ] )
	elseif fieldCount == 7 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ], myTokens[fields[3] ], myTokens[fields[4] ], myTokens[fields[5] ], myTokens[fields[6] ], myTokens[fields[7] ] )
	elseif fieldCount == 8 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ], myTokens[fields[3] ], myTokens[fields[4] ], myTokens[fields[5] ], myTokens[fields[6] ], myTokens[fields[7] ], myTokens[fields[8] ] )
	elseif fieldCount == 9 then
		outputString = string.format( self:GetFormat(id, msgType), myTokens[fields[1] ], myTokens[fields[2] ], myTokens[fields[3] ], myTokens[fields[4] ], myTokens[fields[5] ], myTokens[fields[6] ], myTokens[fields[7] ], myTokens[fields[8] ], myTokens[fields[9] ] )
	end
	

	-- Get the ChatFrame to display.
	
	local chatframe
	if type(id) == 'number' then -- this is a default chat frame.
		chatframe = getglobal("ChatFrame" .. id)
	elseif type(id) == 'string' then -- this is a custom chat frame.
		chatframe = getglobal(id)
	end
	
	if chatframe then
		if settings.colorEvent then
			local e = string.sub(event, 10)
			local info = ChatTypeInfo[e]
			chatframe:AddMessage(outputString, info.r, info.g, info.b)
		else	
			chatframe:AddMessage(outputString)
		end
	end

	compost:Reclaim(myTokens)

	
end

function SimpleCombatLog:Colorize(text, hexColor)
	return string.format('|cff%s%s|r', hexColor, text)
end


function SimpleCombatLog:GetValue(id, field)
	if not self.settings[id] then
		return false
	else
		return self.settings[id][field]
	end
end


function SimpleCombatLog:GetEvent(id, event)
	local db = self.settings[id]
	if not db or not db.events or not db.events[event] then
		return false
	else
		return db.events[event]
	end
end


SimpleCombatLog.filterFlags = {
	{
		player = 1,
		pet = 2,
		party = 3,
		raid = 4,
		target = 5,
		targettarget = 6,
		other = 7		
	},
	{
		player = 8,
		pet = 9,
		party = 10,
		raid = 11,
		target = 12,
		targettarget = 13,
		other = 14	
	}
}

function SimpleCombatLog:GetFilter(id, filterType, nameFilter, isSource)
	local db = self.settings[id]
	if not db or not db.filters or not db.filters[filterType] then
		return false
	else	
		local source
		if isSource then source = 1 else source = 2 end
		local flag = self.filterFlags[source][nameFilter]
		return db.filters[filterType][flag]
	end
end




-- Return values: hex, isDefault
function SimpleCombatLog:GetColorHex(id, colorType)
	assert( id and colorType )
	local hex, isDefault
	if not self.settings[id] or not self.settings[id].colors or not self.settings[id].colors[colorType] then
		hex = defaultColors[colorType]	
		isDefault = true
	else
		hex = self.settings[id].colors[colorType]
		isDefault = false
	end
	return hex, isDefault
end




function SimpleCombatLog:GetFormat(id, msgType)
	assert( id and msgType )
	local db = self.settings[id]
	if not db or not db.formats or not db.formats[msgType] then
		return defaultFormats[msgType][1], true
	else
		return db.formats[msgType], false
	end
end


function SimpleCombatLog:GetWatchList(id, watchType)
	local db = self.settings[id]
	if db and db.watchList and db.watchList[watchType] then
		return db.watchList[watchType]
	end
end


function SimpleCombatLog:RefreshSettings()

	local usedEvents = {}
	
	for event in pairs(self.events) do
		for j in pairs(self.settings) do			
			if self:GetEvent(j, event) then
				usedEvents[event] = true
				if not parser:IsEventRegistered("SimpleCombatLog", event) then
					parser:RegisterEvent("SimpleCombatLog", event, function(event, info) self:OnCombatEvent(event, info) end)
				end
			end
			
		end
	end

	
	-- Unregister non-used events from ParserLib.
	for event in pairs(self.events) do
		if not usedEvents[event] and parser:IsEventRegistered("SimpleCombatLog", event) then
			parser:UnregisterEvent("SimpleCombatLog", event)
		end
	end
	

	for id, setting in self.settings do
		local chatframe = getglobal("ChatFrame" .. id)
		if chatframe then
			if setting.resize then				
				chatframe:SetMaxResize(1000, 700)
				chatframe:SetMinResize(40, 40)	
			else
				chatframe:SetMaxResize(608, 400)
				chatframe:SetMinResize(296, 75)		
			end
		end
	end
		
	

end

-- Get constant element string from localized element string.
function SimpleCombatLog:GetElementType(element)
	for elementType, keyword in self.fixCombatLog do
		if element == keyword then
			return elementType
		end
	end
		
--[[
	if element == SPELL_SCHOOL0_CAP then return 'physical'
	elseif element == SPELL_SCHOOL1_CAP then return 'holy'
	elseif element == SPELL_SCHOOL2_CAP then return 'fire'
	elseif element == SPELL_SCHOOL3_CAP then return 'nature'
	elseif element == SPELL_SCHOOL4_CAP then return 'frost'
	elseif element == SPELL_SCHOOL5_CAP then return 'shadow'
	elseif element == SPELL_SCHOOL6_CAP then return 'arcane'
	end
]]
	self:Debug("Unknown element:", element)
	return 'physical'
end

-- Get trailer string by parsing info.
function SimpleCombatLog:GetTrailerString(id, info)
	local trailer = ''
	if info.isCrushing then trailer = trailer .. self:GetFormat(id, 'crushing')end
	if info.isGlancing then trailer = trailer .. self:GetFormat(id, 'glancing')end
	if info.amountAbsorb then trailer = trailer .. format(self:GetFormat(id, 'absorb'), info.amountAbsorb) end
	if info.amountResist then trailer = trailer .. format(self:GetFormat(id, 'resist'), info.amountResist) end
	if info.amountBlock then trailer = trailer .. format(self:GetFormat(id, 'block'), info.amountBlock) end
	if info.amountVulnerable then trailer = trailer .. format(self:GetFormat(id, 'vulnerable'), info.amountVulnerable) end
	return trailer
end

function SimpleCombatLog:GetExpTrailerString(id, info)
	local trailer = ''
	if info.source then trailer = trailer .. format(self:GetFormat(id, 'expSource'), info.source) end
	if info.bonusAmount then 
		trailer = trailer .. format(self:GetFormat(id, 'expBonus'), info.bonusType, info.bonusAmount) 
	elseif info.penaltyAmount then
		trailer = trailer .. format(self:GetFormat(id, 'expBonus'), info.penaltyType, info.penaltyAmount) 
	end
	if info.amountGroupBonus then
		trailer = trailer .. format(self:GetFormat(id, 'expGroup'), info.amountGroupBonus)
	elseif info.amountRaidPenalty  then
		trailer = trailer .. format(self:GetFormat(id, 'expRaid'), info.amountGroupBonus)
	end
	return trailer
end

-- Check for the filter settings, return true if this message can be shown, false if the message is filtered.
function SimpleCombatLog:FilterCheck(id, info)
	
	-- These message ignore name filters.
	if info.type == 'experience'
	or info.type == 'honor'
	or info.type == 'reputation' 
	or info.type == 'fail' then
		return true
	end	
	
	if not self.settings[id] then
		return true
	end
	
	local watch = self:GetWatchList(id, 'skill')
	
	-- Custom skill watch?
	if watch and info.skill and watch[info.skill] then
		return true
	end
	
	
	-- Checking names
	if not info.source and not info.victim then return true end
	
	if info.source then
		local name = info.source
		
		-- Custom name watch.
		watch = self:GetWatchList(id, 'source')
		if watch and watch[name]  then return true end
		
		if self:GetFilter(id, info.type, self:GetUnitType(name), true) then
			return true
		end
		if self:IsTarget(name) and self:GetFilter(id, info.type, 'target', true) then
			return true
		end
		if self:IsTargetTarget(name) and self:GetFilter(id, info.type, 'targettarget', true) then
			return true
		end
	end
	
	if info.victim then
		local name = info.victim
		
		-- Custom name watch.
		watch = self:GetWatchList(id, 'victim')
		if watch and watch[name]  then return true end
		
		if self:GetFilter(id, info.type, self:GetUnitType(name)) then
			return true
		end
		if self:IsTarget(name) and self:GetFilter(id, info.type, 'target') then
			return true
		end
		if self:IsTargetTarget(name) and self:GetFilter(id, info.type, 'targettarget') then
			return true
		end
	end
	
	-- The message does not match any filter setting, block.
	return false
	
end

function SimpleCombatLog:IsTarget(name)
	return name == UnitName("target")
end

function SimpleCombatLog:IsTargetTarget(name)
	return name == UnitName("targettarget")
end


-- Get what is this name : player, pet, party, raid, or others.
function SimpleCombatLog:GetUnitType(name, checkTarget)
	if not name then return end
	
	if checkTarget then
		if name == UnitName('target') then return 'target' end
		if name == UnitName('targettarget') then return 'targettarget' end
	end
	
	if name == ParserLib_SELF then return 'player' end
		
	-- This is NOT player, but someone which has an identical name to player ( most likely a pet name).
	if name == UnitName('player') then return 'other' end	

	local unit = roster:GetUnitIDFromName(name)
	
	if not unit then return 'other' end
	
	if unit == 'pet' then return 'pet' end
	
	if string.find(unit, 'party', 1, true) then return 'party' end
	
	return 'raid'
	
end


function SimpleCombatLog:LoadInitialSettings()
	SimpleCombatLogDB = nil
	SimpleCombatLogDBPerChar = nil
	self:InitGlobalDB()
	self:InitPerCharDB()
	self.settings = {}
	self:SetTheme(2, 'default')
	self:Print("Loaded default settings (custom themes will exist until next login).")
end

function SimpleCombatLog:LoadSettingMenu(id)
	if not self.ShowSettingMenu then
		self:Print("Dropdown menu component is not loaded.")
	else
		self:ShowSettingMenu(id)
	end
end


-- Save the table as base locales if there isn't one, update the current locales if there is one.
function SimpleCombatLog:UpdateLocales(loc)
	if not self.loc then
		self.loc = loc
	else
		self.CopyTable(self.loc, loc)
	end
end
