--[[

Name: ParserLib

Revision: $Revision: 19097 $

Author(s): rophy (rophy123@gmail.com)

Website: http://www.wowace.com/index.php/ParserLib

Documentation: http://www.wowace.com/index.php/ParserLib

SVN: http://svn.wowace.com/root/trunk/ParserLib

Description: An embedded combat log parser, which works on all localizations.

Dependencies: CompostLib (optional) or Compost-2.0 (optional).

]]



---------------------------------------------------------------------------

--	To Get an instance of ParserLib, call this:

-- 	local parser = ParserLib:GetInstance(version)

-- 	where the version is the variable 'vmajor' you see here.

---------------------------------------------------------------------------

local vmajor, vminor = "1.1", tonumber(string.sub("$Revision: 19097 $", 12, -3))



local stubvarname = "TekLibStub"

local libvarname = "ParserLib"



-- Check to see if an update is needed

-- if not then just return out now before we do anything

local libobj = getglobal(libvarname)

if libobj and not libobj:NeedsUpgraded(vmajor, vminor) then return end



local lua51 = loadstring("return function(...) return ... end") and true or false

local string_gmatch = lua51 and string.gmatch or string.gfind

local table_setn = lua51 and function() end or table.setn



local function print(msg, r, g, b)

	ChatFrame1:AddMessage(string.format("<%s-%s-%s> %s", libvarname, vmajor, vminor, msg), r, g, b)

end



---------------------------------------------------------------------------

-- Embedded Library Registration Stub

-- Written by Iriel <iriel@vigilance-committee.org>

-- Version 0.1 - 2006-03-05

-- Modified by Tekkub <tekkub@gmail.com>

---------------------------------------------------------------------------



local stubobj = getglobal(stubvarname)

if not stubobj then

	stubobj = {}

	setglobal(stubvarname, stubobj)



	-- Instance replacement method, replace contents of old with that of new

	function stubobj:ReplaceInstance(old, new)

		 for k,v in pairs(old) do old[k]=nil end

		 for k,v in pairs(new) do old[k]=v end

	end



	-- Get a new copy of the stub

	function stubobj:NewStub(name)

		local newStub = {}

		self:ReplaceInstance(newStub, self)

		newStub.libName = name

		newStub.lastVersion = ''

		newStub.versions = {}

		return newStub

	end





	-- Get instance version

	function stubobj:NeedsUpgraded(vmajor, vminor)

		local versionData = self.versions[vmajor]

		if not versionData or versionData.minor < vminor then return true end

	end





	-- Get instance version

	function stubobj:GetInstance(version)

		if not version then version = self.lastVersion end

		local versionData = self.versions[version]

		if not versionData then print(string.format("<%s> Cannot find library version: %s", self.libName, version or "")) return end

		return versionData.instance

	end





	-- Register new instance

	function stubobj:Register(newInstance)

		 local version,minor = newInstance:GetLibraryVersion()

		 self.lastVersion = version

		 local versionData = self.versions[version]

		 if not versionData then

				-- This one is new!

				versionData = {

					instance = newInstance,

					minor = minor,

					old = {},

				}

				self.versions[version] = versionData

				newInstance:LibActivate(self)

				return newInstance

		 end

		 -- This is an update

		 local oldInstance = versionData.instance

		 local oldList = versionData.old

		 versionData.instance = newInstance

		 versionData.minor = minor

		 local skipCopy = newInstance:LibActivate(self, oldInstance, oldList)

		 table.insert(oldList, oldInstance)

		 if not skipCopy then

				for i, old in ipairs(oldList) do self:ReplaceInstance(old, newInstance) end

		 end

		 return newInstance

	end

end





if not libobj then

	libobj = stubobj:NewStub(libvarname)

	setglobal(libvarname, libobj)

end





local lib = {}





-- Return the library's current version

function lib:GetLibraryVersion()

	return vmajor, vminor

end





-- Activate a new instance of this library

function lib:LibActivate(stub, oldLib, oldList)

	local maj, min = self:GetLibraryVersion()



	if oldLib then

		local omaj, omin = oldLib:GetLibraryVersion()

		----------------------------------------------------

		-- ********************************************** --

		-- **** Copy over any old data you need here **** --

		-- ********************************************** --

		----------------------------------------------------

		self.frame = oldLib.frame

		self:OnLoad()



		if omin < 11 and oldLib.clients then

			for event in pairs(oldLib.clients) do

				for i in pairs(oldLib.clients[event]) do

					if type(oldLib.clients[event][i]["func"]) == "string" then

						oldLib.clients[event][i]["func"] = getglobal(oldLib.clients[event][i]["func"])

					end

				end

			end

		end

		self.clients = oldLib.clients



		

	else

		---------------------------------------------------

		-- ********************************************* --

		-- **** Do any initialization you need here **** --

		-- ********************************************* --

		---------------------------------------------------

		self:OnLoad()

	end

	-- nil return makes stub do object copy

end















----------------------------------------------

--	*ParserLib Public Methods*      --

----------------------------------------------



-- Register an event to ParserLib.

function lib:RegisterEvent(addonID, event, handler)



	local eventExist

	for i, v in pairs(self.supportedEvents) do

		if v == event then

			eventExist = true

			break

		end

	end

	

	if not eventExist then

		self:Print( string.format("Event %s is not supported. (AddOnID %s)", event, addonID), 1, 0, 0 )

		return

	end

	



	-- self:Print(string.format("Registering %s for addon %s.", event, addonID) );	 -- debug



	if type(handler) == "string" then handler = getglobal(handler) end

	

	-- if not handler then self:Print("nil handler from " .. addonID, 1, 0, 0) end -- debug



	if self.clients[event] == nil then

		self.clients[event] = {};	

	end

	

	-- load pattern list & info when event is registering

	self:PreLoadPatternInfo(event);

	

	table.insert(self.clients[event], { ["id"]=addonID, ["func"]=handler } );

	self.frame:RegisterEvent(event);



end



-- Check if you have registered an event.

function lib:IsEventRegistered(addonID, event)

	if self.clients[event] then

		for i, v in pairs(self.clients[event]) do

			if v.id == addonID then return true end

		end

	end

end



-- Unregister an event.

function lib:UnregisterEvent(addonID, event)

	local empty = true

	

	

	if not self.clients[event] then return end

	

	for i, v in pairs(self.clients[event]) do

		if v.id == addonID then

			-- self:Print( format("Removing %s from %s", v.id, event) )		 -- debug

			table.remove(self.clients[event], i)

		else

			empty = false

		end

	end

	

	if empty then

		-- self:Print("Unregistering event " .. event) -- debug

		self.frame:UnregisterEvent(event)

		self.clients[event] = nil

	end

end



-- Unregister all events.

function lib:UnregisterAllEvents(addonID)

	local event, index, empty;

	

	for event in pairs(self.clients) do

		empty = true;

		

		for i, v in pairs(self.clients[event]) do

			if v.id == addonID then

				-- self:Print( format("Removing %s for %s", v.id, event) ) -- debug

				table.remove(self.clients[event], i)

--				self.clients[event][index] = nil;

			else

				empty = false;

			end

		end

		

		if empty then

			-- self:Print("Unregistering event " .. event) -- debug

			self.frame:UnregisterEvent(event);

			self.clients[event] = nil;

		end

		

	end	



end



-- Parse custom messages, check documentation.html for more info.

function lib:Deformat(text, pattern)

	if not self.customPatterns then self.customPatterns = {} end		

	if not self.customPatterns[pattern] then

		self.customPatterns[pattern] = self:Curry(pattern)

	end

	return self.customPatterns[pattern](text)

end



--------------------------------------------------------

-- Methods to control ParserLib behaviour --

--------------------------------------------------------



-- Use CompostLib or not?

-- Not that at 1.1-23 CompostLib no longer slows down the speed of ParserLib, 

--   because I found out that I was calling CompostLib:Recycle too frequently, which can be avoided.

function lib:UseCompost(flag)

	self.vars.noCompost = not flag

end





---------------------------------------------------

--	*End of ParserLib Public Methods* --

---------------------------------------------------





----------------------------------------------

--	ParserLib Private Methods

----------------------------------------------



-- Constants

ParserLib_SELF = 103

ParserLib_MELEE = 112

ParserLib_DAMAGESHIELD = 113



-- lib.timing = true -- timer



-- Stub function called by frame.OnEvent

local function ParserOnEvent() lib:OnEvent() end



-- Sort the pattern so that they can be parsed in a correct sequence, will only do once for each registered event.

local function PatternCompare(a, b)

	

	local pa = getglobal(a)

	local pb = getglobal(b)

	

	if not pa then ChatFrame1:AddMessage("|cffff0000Nil pattern: ".. a.."|r") end

	if not pb then ChatFrame1:AddMessage("|cffff0000Nil pattern: ".. b.."|r") end

		

	local ca=0

	for _ in string_gmatch(pa, "%%%d?%$?[sd]") do ca=ca+1 end

	local cb=0

	for _ in string_gmatch(pb, "%%%d?%$?[sd]") do cb=cb+1 end



	pa = string.gsub(pa, "%%%d?%$?[sd]", "")	

	pb = string.gsub(pb, "%%%d?%$?[sd]", "")

	

	if string.len(pa) == string.len(pb) then

		return  ca < cb;

	else

		return string.len(pa) > string.len(pb)

	end

	

end



local FindString = {

	[0] = function(m,p,t) return string.find(m,p), t end,

	[1] = function(m,p,t) _,_,t[1] = string.find(m,p) if t[1] then return true, t else return false, t end end,

	[2] = function(m,p,t) _,_,t[1],t[2] = string.find(m,p) if t[2] then return true, t else return false, t end end,

	[3] = function(m,p,t) _,_,t[1],t[2],t[3] = string.find(m,p) if t[3] then return true, t else return false, t end end,

	[4] = function(m,p,t) _,_,t[1],t[2],t[3],t[4] = string.find(m,p) if t[4] then return true, t else return false, t end end,

	[5] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5] = string.find(m,p) if t[5] then return true, t else return false, t end end,

	[6] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6] = string.find(m,p) if t[6] then return true, t else return false, t end end,

	[7] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6],t[7] = string.find(m,p) if t[7] then return true, t else return false, t end end,

	[8] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8] = string.find(m,p) if t[8] then return true, t else return false, t end end,

	[9] = function(m,p,t) _,_,t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9] = string.find(m,p) if t[9] then return true, t else return false, t end end,

}



-- Currently supported event list.

lib.supportedEvents = {



	"CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS",

	"CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES",

	"CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS",

	"CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES",

	"CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS",

	"CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES",

	"CHAT_MSG_COMBAT_FACTION_CHANGE",

	"CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS",

	"CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES",

	"CHAT_MSG_COMBAT_FRIENDLY_DEATH",

	"CHAT_MSG_COMBAT_HONOR_GAIN",

	"CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS",

	"CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES",

	"CHAT_MSG_COMBAT_HOSTILE_DEATH",

	"CHAT_MSG_COMBAT_PARTY_HITS",

	"CHAT_MSG_COMBAT_PARTY_MISSES",

	"CHAT_MSG_COMBAT_PET_HITS",

	"CHAT_MSG_COMBAT_PET_MISSES",

	"CHAT_MSG_COMBAT_SELF_HITS",

	"CHAT_MSG_COMBAT_SELF_MISSES",

	"CHAT_MSG_COMBAT_XP_GAIN",

	"CHAT_MSG_SPELL_AURA_GONE_OTHER",

	"CHAT_MSG_SPELL_AURA_GONE_SELF",

	"CHAT_MSG_SPELL_AURA_GONE_PARTY",

	"CHAT_MSG_SPELL_BREAK_AURA",

	"CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF",

	"CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE",

	"CHAT_MSG_SPELL_CREATURE_VS_PARTY_BUFF",

	"CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE",

	"CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF",

	"CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE",

	"CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS",

	"CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF",

	"CHAT_MSG_SPELL_FAILED_LOCALPLAYER",

	"CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF",

	"CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE",

	"CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF",

	"CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE",

	"CHAT_MSG_SPELL_ITEM_ENCHANTMENTS",

	"CHAT_MSG_SPELL_PARTY_BUFF",

	"CHAT_MSG_SPELL_PARTY_DAMAGE",

	"CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS",

	"CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE",

	"CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS",

	"CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE",

	"CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS",

	"CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE",

	"CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS",

	"CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE",

	"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS",

	"CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE",

	"CHAT_MSG_SPELL_PET_BUFF",

	"CHAT_MSG_SPELL_PET_DAMAGE",

	"CHAT_MSG_SPELL_SELF_BUFF",

	"CHAT_MSG_SPELL_SELF_DAMAGE",

	"CHAT_MSG_SPELL_TRADESKILLS",



}



function lib:GetCompost()



	if self.vars.noCompost then

	

		if not self.myCompost then

			self.myCompost = {

				Recycle = function() return {} end,

				Acquire = function() return {} end,

				Reclaim = function() end,

			}					

		end

		return self.myCompost



	else

	

		if not self.compost then

			if AceLibrary and AceLibrary:HasInstance("Compost-2.0") then

				self.compost = AceLibrary:GetInstance("Compost-2.0")

			elseif CompostLib then

				self.compost = CompostLib:GetInstance("compost-1")

			else

				-- Cannot find the existance of CompostLib

				self.vars.noCompost = true

				return self:GetCompost()

			end			

		end

		return self.compost



	end

	

end



-- Convert "%s hits %s for %d." to "(.+) hits (.+) for (%d+)."

-- Will additionaly return the sequence of tokens, for example:	                    

--  "%2$s reflects %3$d %4$s damage to %1$s."   will return: 

--    "(.-) reflects (%+) (.-) damage to (.-)%.",  4 1 2 3. 

--  (    [1]=2,[2]=3,[3]=4,[4]=1  Reverting indexes and become  [1]=4, [2]=[1],[3]=2,[4]=3. )

function lib:ConvertPattern(pattern, anchor)



	local seq



	-- Add % to escape all magic characters used in LUA pattern matching, except $ and %

	pattern = string.gsub(pattern,"([%^%(%)%.%[%]%*%+%-%?])","%%%1");

	

	-- Do these AFTER escaping the magic characters.

	pattern = string.gsub(pattern,"%%s","(.-)"); -- %s to (.-)

	pattern = string.gsub(pattern,"%%d","(%-?%%d+)"); -- %d to (%d+)			



	if string.find(pattern,"%$") then

		seq = {}; -- fills with ordered list of $s as they appear

		local idx = 1; -- incremental index into field[]



		local tmpSeq = {}

		for i in string_gmatch(pattern,"%%(%d)%$.") do

			tmpSeq[idx] = tonumber(i);

			idx = idx + 1

		end

		for i, j in ipairs(tmpSeq) do

			seq[j] = i

		end

		table_setn(seq, #(tmpSeq))

		pattern = string.gsub(pattern,"%%%d%$s","(.-)"); -- %1$s to (.-)

		pattern = string.gsub(pattern,"%%%d%$d","(%-?%%d+)"); -- %1$d to (%d+)

	end



	-- Escape $ now.

	pattern = string.gsub(pattern,"%$","%%$");



	-- Anchor tag can improve string.find() performance by 100%.

	if anchor then pattern = "^"..pattern end	

	

	-- If the pattern ends with (.-), replace it with (.+), or the capsule will be lost.

	if string.sub(pattern, -4) == "(.-)" then

		pattern = string.sub(pattern, 0, -5) .. "(.+)";

	end

	

	if not seq then return pattern end

	

	return pattern, seq[1], seq[2], seq[3], seq[4], seq[5], seq[6], seq[7], seq[8], seq[9], seq[10]

end



function lib:OnLoad()



	-- Both table starts out empty, and load the data only when required.

	self.eventTable = {}

	self.patternTable = {}

	

	

	self.vars = {}

	

	if self.timing then

		self.timer = {

			ParseMessage_LoadPatternList = 0,

			ParseMessage_FindPattern = 0,

			ParseMessage_FindPattern_Regexp = 0,

			ParseMessage_FindPattern_Regexp_FindString = 0,

			ParseMessage_FindPattern_LoadPatternInfo = 0,			

			ParseMessage_ParseInformation = 0,

			ParseMessage_ParseTrailers = 0,

			ParseMessage_ConvertTypes = 0,

			NotifyClients = 0,

			Compost_Acquire = 0,

			Compost_Recycle = 0,

			Compost_Reclaim = 0,

		}

	end



	if not self.clients then self.clients = {} end

	

	if not self.frame then

		self.frame = CreateFrame("FRAME", "ParserLibFrame")

		self.frame:SetScript("OnEvent", ParserOnEvent )

		self.frame:Hide()

	end

	

	

end

	

function lib:OnEvent(e, a1)



	if not e then e = event end

	if not a1 then a1 = arg1 end



	-- self:Print("Event: |cff3333ff"..e.."|r") -- debug

	

	-- Titan Honor+ was changing the global events... just change it back.

	if e == "CHAT_MSG_HONORPLUS" then e = "CHAT_MSG_COMBAT_HONOR_GAIN" end

	



	if self:ParseMessage(a1, e) then

		

-- 		local timer = GetTime() -- timer

		self:NotifyClients(e)

-- 		self.timer.NotifyClients = self.timer.NotifyClients + GetTime() - timer -- timer

				

	end

	



end



function lib:NotifyClients(event)



	if not self.clients or not self.clients[event] then 

		-- self:Print(event .. " has no client to notify.") -- debug

		return 

	end

	

	-- Noneed to recycle the table if there is only one client.

	if #(self.clients[event]) == 1 then

		-- self:Print(event .. ", calling " .. self.clients[event][1].id) -- debug

		self.clients[event][1].func(event, self.info)

		return

	end



-- 	local timer = GetTime() -- timer

	local info = self:GetCompost():Acquire()	

-- 	self.timer.Compost_Acquire = GetTime() - timer + self.timer.Compost_Acquire -- timer



	for i, client in pairs(self.clients[event]) do

		-- self:Print(event .. ", calling " .. client.id) -- debug

				

		-- I can just do a compost:Recycle() here, but I hope this can improve the performance.

		for j in pairs(info) do if not self.info[j] then info[j] = nil end end

		for j, v in pairs(self.info) do info[j] = v end

		

		client.func(event, info)

	end

	

-- 	timer = GetTime() -- timer

	self:GetCompost():Reclaim(info)

-- 	self.timer.reclaim = GetTime() - timer + self.timer.reclaim -- timer



end



lib.Print = print



-- load pattern list & info

function lib:PreLoadPatternInfo(event)

	if not event then return end

	

	if not self.eventTable[event] then self.eventTable[event] = self:LoadPatternList(event) end

	local list = self.eventTable[event]

	if list then

		for i, v in pairs(list) do

			if not self.patternTable[v] then self.patternTable[v] = self:LoadPatternInfo(v) end

		end

	end

end



-- message : the arg1 in the event

-- event : name says it all.

-- info : the table which will store the passed result, so THIS IS THE OUTPUT.

-- return : true if pattern found and parsed, nil otherwise.

function lib:ParseMessage(message, event)



-- --	local currTime -- timer



	

-- 	currTime = GetTime() -- timer

	if not self.eventTable[event] then self.eventTable[event] = self:LoadPatternList(event) end -- loaded by registering already

	local list = self.eventTable[event]

-- 	self.timer.ParseMessage_LoadPatternList = self.timer.ParseMessage_LoadPatternList + GetTime() - currTime -- timer

	

	if not list then return end



	-- Get the table to store parsed results.

	if not self.info then 

-- 		timer = GetTime() -- timer

		self.info = self:GetCompost():Acquire() 

-- 		self.timer.Compost_Acquire = GetTime() - timer + self.timer.Compost_Acquire -- timer

	else 

-- 		timer = GetTime() -- timer

		self.info = self:GetCompost():Recycle(self.info) 

-- 		self.timer.Compost_Recycle = GetTime() - timer + self.timer.Compost_Recycle -- timer

	end



	

-- 	currTime = GetTime() -- timer

	local pattern = self:FindPattern(message, list)

-- 	self.timer.ParseMessage_FindPattern = GetTime() - currTime + self.timer.ParseMessage_FindPattern -- timer



	

	if not pattern then 

		-- create "unknown" event type.

		self.info.type = "unknown"

		self.info.message = message		

		return true

	end

	

-- 	currTime = GetTime() -- timer

	self:ParseInformation(pattern)

-- 	self.timer.ParseMessage_ParseInformation = GetTime() - currTime + self.timer.ParseMessage_ParseInformation -- timer

	

	

-- 	currTime = GetTime() -- timer

	if self.info.type == "hit" or self.info.type == "environment" then

		self:ParseTrailers(message)

	end

-- 	self.timer.ParseMessage_ParseTrailers = GetTime() - currTime + self.timer.ParseMessage_ParseTrailers -- timer

	

-- 	currTime = GetTime() -- timer

	self:ConvertTypes(self.info)

-- 	self.timer.ParseMessage_ConvertTypes = GetTime() - currTime + self.timer.ParseMessage_ConvertTypes -- timer



	return true



	

end





-- Search for pattern in 'patternList' which matches 'message', parsed tokens will be stored in table self.info

function lib:FindPattern(message, patternList)

	

	local pt, timer, found



	for i, v in pairs(patternList) do

	

-- 		timer = GetTime() -- timer

		if not self.patternTable[v] then self.patternTable[v] = self:LoadPatternInfo(v) end -- loaded by registering already

-- 		self.timer.ParseMessage_FindPattern_LoadPatternInfo = GetTime() - timer + self.timer.ParseMessage_FindPattern_LoadPatternInfo -- timer

		

		pt = self.patternTable[v]

		

		found = false



		if not pt then return end -- check patternTable

		

-- 		timer = GetTime() -- timer

		if self:OptimizerCheck(message, v) then

-- 			timer = GetTime() -- timer

			found, self.info = FindString[pt.tc](message, pt.pattern, self.info)

-- 			self.timer.ParseMessage_FindPattern_Regexp_FindString = GetTime() - timer + self.timer.ParseMessage_FindPattern_Regexp_FindString -- timer

		end

-- 		self.timer.ParseMessage_FindPattern_Regexp = GetTime() - timer + self.timer.ParseMessage_FindPattern_Regexp -- timer

		

		if found then 

			-- self:Print(message.." = " .. v .. ":" .. pt.pattern)  -- debug

			return v	

		end





	end

	

	

end





-- Parses for trailors.

function lib:ParseTrailers(message)

	local found, amount, info

	

	info = self.info

	

	

	if not self.trailers then 

		self.trailers = {

			CRUSHING_TRAILER = self:ConvertPattern(CRUSHING_TRAILER),

			GLANCING_TRAILER = self:ConvertPattern(GLANCING_TRAILER),

			ABSORB_TRAILER = self:ConvertPattern(ABSORB_TRAILER),

			BLOCK_TRAILER = self:ConvertPattern(BLOCK_TRAILER),

			RESIST_TRAILER = self:ConvertPattern(RESIST_TRAILER),

			VULNERABLE_TRAILER = self:ConvertPattern(VULNERABLE_TRAILER),

		}

	end

	

	found = string.find(message, self.trailers.CRUSHING_TRAILER)

	if found then 

		info.isCrushing = true

	end

	found = string.find(message, self.trailers.GLANCING_TRAILER)

	if found then 

		info.isGlancing = true

	end

	found, _, amount = string.find(message, self.trailers.ABSORB_TRAILER)

	if found then 

		info.amountAbsorb = amount

	end

	found, _, amount = string.find(message, self.trailers.BLOCK_TRAILER)

	if found then 

		info.amountBlock = amount

	end

	found, _, amount = string.find(message, self.trailers.RESIST_TRAILER)

	if found then 

		info.amountResist = amount

	end

	found, _, amount = string.find(message, self.trailers.VULNERABLE_TRAILER)

	if found then 

		info.amountVulnerable = amount

	end



end



function lib:ParseInformation(patternName)



	local patternInfo = self.patternTable[patternName]

	local info = self.info



	-- Create an info table from pattern table, copies everything except the pattern string.	

	for i, v in pairs(patternInfo) do

		if i == 1 then

			info.type = v

		elseif type(i) == "number" then

			if type(v) == "number" and v < 100 then

				info[ self:GetInfoFieldName( self.patternTable[patternName][1], i) ] = info[v]

			else

				info[ self:GetInfoFieldName( self.patternTable[patternName][1], i) ] = v

			end

		end

	end



	if info.type == "honor" and not info.amount then

		info.isDishonor = true

	

	elseif info.type == "durability" and not info.item  then

		info.isAllItems = true

	end



	for i in ipairs(info) do

		info[i] = nil

	end

	

end



function lib:ConvertTypes(info)

	for i in pairs(info) do

		if string.find(i, "^amount") then info[i] = tonumber(info[i]) end

	end

end



function lib:OptimizerCheck(message, patternName)



	--if 1 then return true end

	if not ParserLibOptimizer then return true end

	

	if not ParserLibOptimizer[patternName] then return true end

	

	if string.find(message, ParserLibOptimizer[patternName], 1, true) then return true end

	

	return false

end



-- Most of the parts were learnt from BabbleLib by chknight, so credits goes to him.

function lib:Curry(pattern)

	local cp, tt, n, f, o

	local DoNothing = function(tok) return tok end	

	

	tt = {}

	for tk in string_gmatch(pattern, "%%%d?%$?([sd])") do

		table.insert(tt, tk)

	end	

	

	cp = { self:ConvertPattern(pattern, true) }

	cp.p = cp[1]

	

	n = #(cp)

	for i=1,n-1 do

		cp[i] = cp[i+1]

	end

	table.remove(cp, n)

	

	f = {}

	o = {}

	n = #(tt)

	for i=1, n do

		if tt[i] == "s" then

			f[i] = DoNothing

		else

			f[i] = tonumber

		end

	end



	if not cp[1] then

		if n == 0 then

			return function() end

		elseif n == 1 then

			return function(text)

				_, _, o[1] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1])

				end

			end

		elseif n == 2 then

			return function(text)

				_, _, o[1], o[2]= string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2])

				end

			end

		elseif n == 3 then

			return function(text)

				_, _, o[1], o[2], o[3] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2]), f[3](o[3])

				end

			end

		elseif n == 4 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4])

				end

			end

		elseif n == 5 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5])

				end

			end

		elseif n == 6 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6])

				end

			end

		elseif n == 7 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6]), f[7](o[7])

				end

			end

		elseif n == 8 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6]), f[7](o[7]), f[8](o[8])

				end

			end

		elseif n == 9 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9] = string.find(text, cp.p)

				if o[1] then

					return f[1](o[1]), f[2](o[2]), f[3](o[3]), f[4](o[4]), f[5](o[5]), f[6](o[6]), f[7](o[7]), f[8](o[8]), f[9](o[9])

				end

			end

		end

	else	

		if n == 0 then

			return function() end

		elseif n == 1 then

			return function(text)

				_, _, o[1] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]])

				end

			end				elseif n == 2 then

			return function(text)

				_, _, o[1], o[2] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]])

				end

			end				elseif n == 3 then

			return function(text)

				_, _, o[1], o[2], o[3] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]])

				end

			end		

		elseif n == 4 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]])

				end

			end				elseif n == 5 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]])

				end

			end				elseif n == 6 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]])

				end

			end				elseif n == 7 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]]), f[cp[7]](o[cp[7]])

				end

			end				elseif n == 8 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]]), f[cp[7]](o[cp[7]]), f[cp[8]](o[cp[8]])

				end

			end				elseif n == 9 then

			return function(text)

				_, _, o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8], o[9] = string.find(text, cp.p)

				if o[1] then

					return f[cp[1]](o[cp[1]]), f[cp[2]](o[cp[2]]), f[cp[3]](o[cp[3]]), f[cp[4]](o[cp[4]]), f[cp[5]](o[cp[5]]), f[cp[6]](o[cp[6]]), f[cp[7]](o[cp[7]]), f[cp[8]](o[cp[8]]), f[cp[9]](o[cp[9]])

				end

			end		

		end		

	end

end





function lib:PrintTable(args)

	for k, v in pairs(args) do

		ChatFrame1:AddMessage(tostring(k) .. " = " .. tostring(v));

	end

	ChatFrame1:AddMessage("");

end



-- Used to test the correcteness of ParserLib on different languages.

function lib:TestPatterns(sendToClients)

	

	

	self:LoadEverything()

	



	-- Creating the combat messages.	

	local testNumber = 123

	local message

	local messages = self:GetCompost():Acquire()

	for patternName in pairs(self.patternTable) do

		messages[patternName] = self:GetCompost():Acquire()

		messages[patternName].message = getglobal(patternName)

		for i, v in pairs(self.patternTable[patternName]) do

			if i ~= "tc" and type(v) == "number" and v < 100 and i~=1 then

				messages[patternName][v] =  self:GetInfoFieldName(self.patternTable[patternName][1], i)

			end

		end

		for i, v in ipairs(messages[patternName]) do

			if string.find(v, "^amount") then

				messages[patternName].message = string.gsub(messages[patternName].message, "%%%d?%$?d", testNumber, 1)

			else

				messages[patternName].message = string.gsub(messages[patternName].message, "%%%d?%$?s", string.upper(v), 1)

			end

		end

	end

	



	-- Begin the test.

	

	local info, msg

	local startTime = GetTime() 

	local startMem = collectgarbage("count")

	

	for _, event in pairs(self.supportedEvents) do

		for _, pattern in pairs(self:LoadPatternList(event)) do

			msg = messages[pattern].message

			if sendToClients then self:OnEvent(event, msg)	end

			if self:ParseMessage(msg, event) then

				info = self.info

				for i, v in ipairs(messages[pattern]) do

					if not info[v] 

					or ( string.find(v, "^amount") and info[v] ~= testNumber ) 

					or ( not string.find(v, "^amount") and info[v] ~= string.upper(v) ) then

						self:Print("Event: " .. event)

						self:Print("Pattern: " .. pattern)

						self:Print("Message: " .. msg)

						self:PrintTable(messages[pattern])

						self:PrintTable(info)

					end

				end

			end

		end

	end



	self:Print( string.format("Test completed in %.4fs, memory cost %.2fKB.", GetTime() - startTime, collectgarbage("count") - startMem) )



	self:GetCompost():Reclaim(messages, 1)

	

end



function lib:LoadEverything()



	-- Load all patterns and events.

	for _, v in pairs(self.supportedEvents) do

		for _, w in pairs(self:LoadPatternList(v)) do

			if not self.patternTable[w] then

				self.patternTable[w] = self:LoadPatternInfo(w)

			end

		end

	end

	

end



function lib:PrintTimers()

	if not self.timer then return end



	local total = 0

	for i in pairs(self.timer) do

		total = total + self.timer[i]

	end



	if not self.timerIndex then 

		self.timerIndex = {}

		for i in pairs(self.timer) do

			table.insert(self.timerIndex, i)

		end

		table.sort(self.timerIndex)

	end



	DEFAULT_CHAT_FRAME:AddMessage("Time\t%\tDescription")

	for i, idx in pairs(self.timerIndex) do

		DEFAULT_CHAT_FRAME:AddMessage(string.format("%.3f\t%.1f\t%s", self.timer[idx], 100*self.timer[idx]/total, idx) )

	end	

	

	DEFAULT_CHAT_FRAME:AddMessage(total .. "\t100\tTotal")

end

-- Used to load eventTable elements on demand.

function lib:LoadPatternList(eventName)

	local list

	

--------------- Melee Hits ----------------	



	if eventName == "CHAT_MSG_COMBAT_SELF_HITS" then		

	

		if not self.eventTable["CHAT_MSG_COMBAT_SELF_HITS"] then

			

			self.eventTable["CHAT_MSG_COMBAT_SELF_HITS"] = 

				self:LoadPatternCategoryTree(

				{

					"HitSelf",

					"EnvSelf",

				}

			)

			

		end



		list = self.eventTable["CHAT_MSG_COMBAT_SELF_HITS"] 

		

	elseif eventName == "CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS" 

	or eventName == "CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS" 

	or eventName == "CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS" 

	or eventName == "CHAT_MSG_COMBAT_PARTY_HITS" 

	or eventName == "CHAT_MSG_COMBAT_PET_HITS" then



		if not self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS"] then 

			self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS"] = 

				self:LoadPatternCategoryTree( {

					"HitOtherOther",

					"EnvOther",

				} )

		end

		list = self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS"]

	

	

	elseif eventName == "CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS" 

	or eventName == "CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS"  then



		if not self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"] then 

			self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"] = 

				self:LoadPatternCategoryTree( {

					{

						"HitOtherOther",

						"HitOtherSelf",

					},

					"EnvOther",

				} )

		end

		list = self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"]



	



--------------- Melee Misses ----------------	





		

	elseif eventName == "CHAT_MSG_COMBAT_SELF_MISSES" then

		if not self.eventTable["CHAT_MSG_COMBAT_SELF_MISSES"] then

			self.eventTable["CHAT_MSG_COMBAT_SELF_MISSES"] = 

				self:LoadPatternCategoryTree( {

					"MissSelf",

				} )

		end

		list = self.eventTable["CHAT_MSG_COMBAT_SELF_MISSES"]

		

	elseif eventName == "CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES"

	or eventName == "CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES"

	or eventName == "CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES"

	or eventName == "CHAT_MSG_COMBAT_PARTY_MISSES"

	or eventName == "CHAT_MSG_COMBAT_PET_MISSES" then



		if not self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES"] then

			self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES"] = 

			self:LoadPatternCategoryTree( {

					"MissOtherOther",

			} )

		end



		list = self.eventTable["CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES"]	

	

	

	elseif eventName == "CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES"

	or eventName == "CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES" then



		if not self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"] then

			self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"] = 

			self:LoadPatternCategoryTree( {

				{

					"MissOtherOther",

					"MissOtherSelf",

				}

			} )

		end



		list = self.eventTable["CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"]	

		

--------------- Spell Buffs ----------------	

	elseif eventName == "CHAT_MSG_SPELL_SELF_BUFF" then

		if not self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"] then

		

			if GetLocale() ~= "deDE"  then

			self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"] =  self:LoadPatternCategoryTree(

				{

					"HealSelf",

					"EnchantSelf",

					"CastSelf",

					"PerformSelf",

					"DispelFailSelf",

					"SPELLCASTSELFSTART",

					"SPELLPERFORMSELFSTART",

					{

						"DrainSelf",

						"PowerGainSelf",

						"ExtraAttackSelf",

					},

					"SPELLSPLITDAMAGESELFOTHER",

					{

						"ProcResistSelf",

						"SpellMissSelf",

					}

				}

			)



			else

			self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"] =  self:LoadPatternCategoryTree(

				{

					"HealSelf",

					"CastSelf",

					"PerformSelf",

					"DispelFailSelf",

					"SPELLCASTSELFSTART",

					"SPELLPERFORMSELFSTART",

					{

						"DrainSelf",

						"PowerGainSelf",

						"ExtraAttackSelf",

					},

					"SPELLSPLITDAMAGESELFOTHER",

					{

						"ProcResistSelf",

						"SpellMissSelf",

					}

				}

			)

			end



		end		



		list = self.eventTable["CHAT_MSG_SPELL_SELF_BUFF"]



		

	elseif eventName == "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF"

	or eventName == "CHAT_MSG_SPELL_CREATURE_VS_PARTY_BUFF"  

	or eventName == "CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF"  

	or eventName == "CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF"  

	or eventName == "CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF" 

	or eventName == "CHAT_MSG_SPELL_PARTY_BUFF" 

	or eventName == "CHAT_MSG_SPELL_PET_BUFF" then

	

		if not self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] then

		

			if GetLocale() ~= "deDE"  then

				self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] = self:LoadPatternCategoryTree(

					{

						{

							"HealOther",

							"PowerGainOther",

							"ExtraAttackOther",

							"DrainOther",

						},

						"SPELLCASTOTHERSTART",

						{

							"EnchantOther",

							"CastOther",

							"PerformOther",

						},

						"SPELLPERFORMOTHERSTART",

						"SpellMissOther",

						"ProcResistOther",

						"SplitDamageOther",

						"DispelFailOther",

					}

				)



			else -- Remove "EnchantOther" from German, since it's 100% ambiguous with SIMPLECASTOTHEROTHER, which is unsolvable.

				self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"] = self:LoadPatternCategoryTree(

					{

						{

							"HealOther",

							"PowerGainOther",

							"ExtraAttackOther",

							"DrainOther",

						},

						"SPELLCASTOTHERSTART",

						{

							"CastOther",

							"PerformOther",

						},

						"SPELLPERFORMOTHERSTART",

						"SpellMissOther",

						"ProcResistOther",

						"SplitDamageOther",

						"DispelFailOther",

					}

				)

			end

		end

		

		list = self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF"]





--------------- Spell Damages ----------------	

		

	elseif eventName == "CHAT_MSG_SPELL_SELF_DAMAGE" then	

		if not self.eventTable["CHAT_MSG_SPELL_SELF_DAMAGE"] then

			self.eventTable["CHAT_MSG_SPELL_SELF_DAMAGE"] = 

				self:LoadPatternCategoryTree( {

					"SpellHitSelf",

					{

						"CastSelf",

						"DurabilityDamageSelf",

					},

					"PerformSelf",

					"SpellMissSelf",

					"SPELLCASTSELFSTART",

					"SPELLPERFORMSELFSTART",

					"InterruptSelf",

					"DispelFailSelf",

					"ExtraAttackSelf",

					"DrainSelf",

					

				} )



		end		

		list = self.eventTable["CHAT_MSG_SPELL_SELF_DAMAGE"]	





	elseif eventName == "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE" 

	or eventName == "CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE"  

	or eventName == "CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE"  

	or eventName == "CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE"  

	or eventName == "CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE" 

	or eventName == "CHAT_MSG_SPELL_PARTY_DAMAGE"  

	or eventName == "CHAT_MSG_SPELL_PET_DAMAGE"  then



		if not self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"] then

			self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"] = 

				self:LoadPatternCategoryTree( {

					"SpellHitOther",

					"SPELLCASTOTHERSTART",

					"SPELLPERFORMOTHERSTART",

					"DrainOther",

					"SpellMissOther",

					{

						"INSTAKILLOTHER",

						"INSTAKILLSELF",

					},

					{

						"PROCRESISTOTHEROTHER",

						"PROCRESISTOTHERSELF",

					},

					"SplitDamageOther",

					{

						"CastOther",

						"InterruptOther",

						"DurabilityDamageOther",

					},

					"PerformOther",

					"ExtraAttackOther",

					{

						"DISPELFAILEDOTHEROTHER",

						"DISPELFAILEDOTHERSELF",						

					},

				})



		end

		list = self.eventTable["CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"]

	

		

--------------- Periodic Buffs ----------------	

		

	elseif eventName == "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS" then

	

		if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"] then

		

			self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"] = 

				self:LoadPatternCategoryTree( {

					{

						"HotOther",

						"HotSelf",

					},

					{

						"BuffSelf",

						"BuffOther",

						"PowerGainOther",

						"PowerGainSelf",

					},

					"DrainSelf",

					"DotSelf",	-- Don't think this will hapen but add it anyway.

				} )

		end		

		list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"]	





	elseif eventName == "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS"

	or eventName == "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS"

	or eventName == "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"

	or eventName == "CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS" then

		

		if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] then

			self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] = 

				self:LoadPatternCategoryTree( {

					{

						"HotOther",

--						"DrainOther",	-- Dont think this would happen but add it anyway.

					},

					{

						"BuffOther",

						"PowerGainOther",

						"DrainOther",	-- When other players use Skull of Impending Doom.

					},

					"DotOther",	-- Dont think this will happen but add anyway.

					"DebuffOther", -- Was fired on older WoW version.

				} )

		end

		

		list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"]





		

--------------- Periodic Damages ----------------	

		

	elseif eventName == "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE" then

		if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"] then

		

			self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"] = 

				self:LoadPatternCategoryTree( {

					{

						"DotSelf",

						"DotOther",

					},

					{

						"DebuffSelf",

						"DebuffOther",

					},

					{

						"SPELLLOGABSORBOTHEROTHER",

						"SPELLLOGABSORBOTHERSELF",

						"SPELLLOGABSORBSELFSELF",

						"SPELLLOGABSORBSELFOTHER",

					},

					"DrainSelf",

				}	)

		end	

		list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE"]	

		

		



	elseif eventName == "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"

	or eventName == "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE"

	or eventName == "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"

	or eventName == "CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE" then

	

		if not self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] then

			self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] = 

				self:LoadPatternCategoryTree( {

					"DebuffOther",

					"DotOther",

					{

						"SPELLLOGABSORBOTHEROTHER",

						"SPELLLOGABSORBSELFOTHER",

					},					

					"DrainOther",

					{

						"PowerGainOther",

						"BuffOther", -- Was fired on older WoW version.					

					}

				} )

		end			

		list = self.eventTable["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"]



--------------- Damage Shields ----------------	

		

		

	elseif eventName == "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF" then

		if not self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] then

			self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] = {

				"SPELLRESISTOTHEROTHER",

				"SPELLRESISTSELFOTHER",

				"DAMAGESHIELDOTHEROTHER",

				"DAMAGESHIELDSELFOTHER",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"] , PatternCompare)

		end

		list = self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF"]	

		

	elseif eventName == "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS" then

		if not self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] then

			self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] = {

				"SPELLRESISTOTHEROTHER",

				"SPELLRESISTOTHERSELF",

				"DAMAGESHIELDOTHEROTHER",

				"DAMAGESHIELDOTHERSELF",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"] , PatternCompare)

		end		

		list = self.eventTable["CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS"]

		

		

		

--------------- Auras ----------------	



	elseif eventName == "CHAT_MSG_SPELL_AURA_GONE_PARTY"

	or eventName == "CHAT_MSG_SPELL_AURA_GONE_OTHER" then

	

		if not self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"] then

			self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"] = {

				"AURAREMOVEDOTHER",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"] , PatternCompare)

		end

		list = self.eventTable["CHAT_MSG_SPELL_AURA_GONE_OTHER"]

	

	elseif  eventName == "CHAT_MSG_SPELL_AURA_GONE_SELF" then

	

		if not self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"] then

			self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"] = {

				"AURAREMOVEDOTHER",

				"AURAREMOVEDSELF",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"] , PatternCompare)

		end

		list = self.eventTable["CHAT_MSG_SPELL_AURA_GONE_SELF"]

		

	elseif eventName == "CHAT_MSG_SPELL_BREAK_AURA" then

	

		if not self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"] then

			self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"] = {

				"AURADISPELSELF",

				"AURADISPELOTHER",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"] , PatternCompare)

		end		

		list = self.eventTable["CHAT_MSG_SPELL_BREAK_AURA"]			

		

		

		

	elseif eventName == "CHAT_MSG_SPELL_ITEM_ENCHANTMENTS" then

	

		if not self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"] then

			self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"] = {

				"ITEMENCHANTMENTADDSELFSELF",

				"ITEMENCHANTMENTADDSELFOTHER",

				"ITEMENCHANTMENTADDOTHEROTHER",

				"ITEMENCHANTMENTADDOTHERSELF",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"] , PatternCompare)

		end			

		list = self.eventTable["CHAT_MSG_SPELL_ITEM_ENCHANTMENTS"]	



--------------- Trade Skills ----------------	



		

	elseif eventName == "CHAT_MSG_SPELL_TRADESKILLS" then

		if not self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"] then

			self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"] = {

				"TRADESKILL_LOG_FIRSTPERSON",

				"TRADESKILL_LOG_THIRDPERSON",

				"FEEDPET_LOG_FIRSTPERSON",

				"FEEDPET_LOG_THIRDPERSON",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"], PatternCompare )

		end		

		list = self.eventTable["CHAT_MSG_SPELL_TRADESKILLS"]	

		

	elseif eventName == "CHAT_MSG_SPELL_FAILED_LOCALPLAYER" then

	

		if not self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"] then

			self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"] = {

				"SPELLFAILPERFORMSELF",

				"SPELLFAILCASTSELF",

			}

			table.sort(self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"], PatternCompare)

		end		

		list = self.eventTable["CHAT_MSG_SPELL_FAILED_LOCALPLAYER"] 	

			

	

	elseif eventName == "CHAT_MSG_COMBAT_FACTION_CHANGE" then

	

		if not self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"] then

		

			self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"] = {

				"FACTION_STANDING_CHANGED",

				"FACTION_STANDING_DECREASED",

				"FACTION_STANDING_INCREASED",

			}

			table.sort(self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"] , PatternCompare)

		end		

		list = self.eventTable["CHAT_MSG_COMBAT_FACTION_CHANGE"]

		

	elseif eventName == "CHAT_MSG_COMBAT_HONOR_GAIN" then

	

		if not self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"] then

			self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"] = {

			"COMBATLOG_HONORAWARD",

			"COMBATLOG_HONORGAIN",

			"COMBATLOG_DISHONORGAIN",

			}

			table.sort(self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"] , PatternCompare)

		end		

		list = self.eventTable["CHAT_MSG_COMBAT_HONOR_GAIN"]

	elseif eventName == "CHAT_MSG_COMBAT_XP_GAIN" then

	

		if not self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"] then

			self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"] = {

				"COMBATLOG_XPGAIN",

				"COMBATLOG_XPGAIN_EXHAUSTION1",

				"COMBATLOG_XPGAIN_EXHAUSTION1_GROUP",

				"COMBATLOG_XPGAIN_EXHAUSTION1_RAID",

				"COMBATLOG_XPGAIN_EXHAUSTION2",

				"COMBATLOG_XPGAIN_EXHAUSTION2_GROUP",

				"COMBATLOG_XPGAIN_EXHAUSTION2_RAID",

				"COMBATLOG_XPGAIN_EXHAUSTION4",

				"COMBATLOG_XPGAIN_EXHAUSTION4_GROUP",

				"COMBATLOG_XPGAIN_EXHAUSTION4_RAID",

				"COMBATLOG_XPGAIN_EXHAUSTION5",

				"COMBATLOG_XPGAIN_EXHAUSTION5_GROUP",

				"COMBATLOG_XPGAIN_EXHAUSTION5_RAID",

				"COMBATLOG_XPGAIN_FIRSTPERSON",

				"COMBATLOG_XPGAIN_FIRSTPERSON_GROUP",

				"COMBATLOG_XPGAIN_FIRSTPERSON_RAID",

				"COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED",

				"COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_GROUP",

				"COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_RAID",

				"COMBATLOG_XPLOSS_FIRSTPERSON_UNNAMED",

			}

			table.sort(self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"] , PatternCompare)

		end		

		list = self.eventTable["CHAT_MSG_COMBAT_XP_GAIN"]		

		

	elseif eventName == "CHAT_MSG_COMBAT_FRIENDLY_DEATH" 

	or eventName == "CHAT_MSG_COMBAT_HOSTILE_DEATH" then

	

		if not self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"] then

			self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"] = {

				"SELFKILLOTHER",

				"PARTYKILLOTHER",

				"UNITDESTROYEDOTHER",

				"UNITDIESOTHER",

				"UNITDIESSELF",

			}

			

			table.sort(self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"] , PatternCompare)

		end		

		list = self.eventTable["CHAT_MSG_COMBAT_HOSTILE_DEATH"]	



	end





	if not list then

		-- self:Print(string.format("Event '%s' not found.", eventName), 1, 0,0); -- debug

	end



	return list



end



function lib:LoadPatternCategory(category)



	local list



	if category == "AuraChange" then		list = {

			"AURACHANGEDOTHER",

			"AURACHANGEDSELF",

		}

	elseif category == "AuraDispel" then		list = {

			"AURADISPELOTHER",

			"AURADISPELSELF",

		}

	elseif category == "BuffOther" then		list = {

			"AURAADDEDOTHERHELPFUL",

			"AURAAPPLICATIONADDEDOTHERHELPFUL",

		}

	elseif category == "BuffSelf" then		list = {

			"AURAADDEDSELFHELPFUL",

			"AURAAPPLICATIONADDEDSELFHELPFUL",

		}

	elseif category == "CastOther" then	list = {

			"SIMPLECASTOTHEROTHER",

			"SIMPLECASTOTHERSELF",

			"SPELLTERSE_OTHER",

		}

	elseif category == "CastSelf" then	list = {

			"SIMPLECASTSELFOTHER",

			"SIMPLECASTSELFSELF",

			"SPELLTERSE_SELF",

		}

	elseif category == "DebuffOther" then		list = {

			"AURAADDEDOTHERHARMFUL",

			"AURAAPPLICATIONADDEDOTHERHARMFUL",

		}

	elseif category == "DebuffSelf" then		list = {

			"AURAADDEDSELFHARMFUL",

			"AURAAPPLICATIONADDEDSELFHARMFUL",

		}

	elseif category == "DispelFailOther" then	list = {

			"DISPELFAILEDOTHEROTHER",

			"DISPELFAILEDOTHERSELF",

		

		}

	elseif category == "DispelFailSelf" then		list = {

			"DISPELFAILEDSELFOTHER",

			"DISPELFAILEDSELFSELF",

		}

	elseif category == "DmgShieldOther" then list = {

			"DAMAGESHIELDOTHEROTHER",

			"DAMAGESHIELDOTHERSELF",

		}

	elseif category == "DmgShieldSelf" then		list = {

			"DAMAGESHIELDSELFOTHER",

		}

	elseif category == "DurabilityDamageSelf" then list = {

			"SPELLDURABILITYDAMAGEALLSELFOTHER",

			"SPELLDURABILITYDAMAGESELFOTHER",	

	}

	elseif category == "DurabilityDamageOther" then list = {

			"SPELLDURABILITYDAMAGEALLOTHEROTHER",

			"SPELLDURABILITYDAMAGEALLOTHERSELF", 

			"SPELLDURABILITYDAMAGEOTHEROTHER", 

			"SPELLDURABILITYDAMAGEOTHERSELF",

	}

	elseif category == "EnchantOther" then		list  =  {

			"ITEMENCHANTMENTADDOTHEROTHER",

			"ITEMENCHANTMENTADDOTHERSELF",

		}

	elseif category == "EnchantSelf" then		list = {

			"ITEMENCHANTMENTADDSELFOTHER",

			"ITEMENCHANTMENTADDSELFSELF",

		}

	elseif category == "ExtraAttackOther" then		list = {

			"SPELLEXTRAATTACKSOTHER",

			"SPELLEXTRAATTACKSOTHER_SINGULAR",

		}		

	elseif category == "ExtraAttackSelf" then		list = {

			"SPELLEXTRAATTACKSSELF",

			"SPELLEXTRAATTACKSSELF_SINGULAR",

		}		

	elseif category == "Fade" then		list = {

			"AURAREMOVEDOTHER",

			"AURAREMOVEDSELF",

		}

	elseif category == "HealOther" then		list = {

			"HEALEDCRITOTHEROTHER",

			"HEALEDCRITOTHERSELF",

			"HEALEDOTHEROTHER",

			"HEALEDOTHERSELF",

		}

	elseif category == "HealSelf" then		list = {

			"HEALEDCRITSELFOTHER",

			"HEALEDCRITSELFSELF",

			"HEALEDSELFOTHER",

			"HEALEDSELFSELF",

		}

	elseif category == "HitOtherOther" then		list = {

			"COMBATHITCRITOTHEROTHER",

			"COMBATHITCRITSCHOOLOTHEROTHER",

			"COMBATHITOTHEROTHER",

			"COMBATHITSCHOOLOTHEROTHER",

		}

	elseif category == "HitOtherSelf" then		list = {

	

			"COMBATHITCRITOTHERSELF",

			"COMBATHITCRITSCHOOLOTHERSELF",

			"COMBATHITOTHERSELF",

			"COMBATHITSCHOOLOTHERSELF",

		}

	elseif category == "HitSelf" then		list = {

			"COMBATHITSCHOOLSELFOTHER",

			"COMBATHITSELFOTHER",

			"COMBATHITCRITSCHOOLSELFOTHER",

			"COMBATHITCRITSELFOTHER",

      "SPELLLOGSELFOTHER",

      "SPELLLOGCRITSELFOTHER",

      "SPELLLOGSCHOOLSELFOTHER",

      "SPELLLOGCRITSCHOOLSELFOTHER",

		}

	elseif category == "MissOtherOther" then	list = {

			"MISSEDOTHEROTHER",

			"VSABSORBOTHEROTHER",

			"VSBLOCKOTHEROTHER",

			"VSDEFLECTOTHEROTHER",

			"VSDODGEOTHEROTHER",

			"VSEVADEOTHEROTHER",

			"VSIMMUNEOTHEROTHER",

			"VSPARRYOTHEROTHER",

			"VSRESISTOTHEROTHER",

			"IMMUNEDAMAGECLASSOTHEROTHER",

			"IMMUNEOTHEROTHER",

			

		}	

	elseif category == "MissOtherSelf" then	list = {

			"MISSEDOTHERSELF",

			"VSABSORBOTHERSELF",

			"VSBLOCKOTHERSELF",

			"VSDEFLECTOTHERSELF",

			"VSDODGEOTHERSELF",

			"VSEVADEOTHERSELF",

			"VSIMMUNEOTHERSELF",

			"VSPARRYOTHERSELF",

			"VSRESISTOTHERSELF",	

			"IMMUNEDAMAGECLASSOTHERSELF",

			"IMMUNEOTHERSELF",

		}	

	elseif category == "MissSelf" then	list = {

				"MISSEDSELFOTHER",

				"VSABSORBSELFOTHER",

				"VSBLOCKSELFOTHER",

				"VSDEFLECTSELFOTHER",

				"VSDODGESELFOTHER",

				"VSEVADESELFOTHER",

				"VSIMMUNESELFOTHER",

				"VSPARRYSELFOTHER",

				"VSRESISTSELFOTHER",

				"IMMUNEDAMAGECLASSSELFOTHER",

				"IMMUNESELFOTHER",

				"IMMUNESELFSELF",

        "SPELLMISSSELFOTHER",

		}

	elseif category == "PowerGainOther" then		list = {

			"POWERGAINOTHEROTHER",

			"POWERGAINOTHERSELF",

		}

	elseif category == "PerformOther" then list = {

			"OPEN_LOCK_OTHER",

			"SIMPLEPERFORMOTHEROTHER",

			"SIMPLEPERFORMOTHERSELF",

			"SPELLTERSEPERFORM_OTHER",

		}

	elseif category == "PerformSelf" then	list = {

			"OPEN_LOCK_SELF",

			"SIMPLEPERFORMSELFOTHER",

			"SIMPLEPERFORMSELFSELF",

			"SPELLTERSEPERFORM_SELF",

		}

	elseif category == "ProcResistOther" then list = {

			"PROCRESISTOTHEROTHER",

			"PROCRESISTOTHERSELF",

		}

	elseif category == "ProcResistSelf" then	list = {

			"PROCRESISTSELFOTHER",

			"PROCRESISTSELFSELF",

		}

	elseif category == "EnvOther" then list = {

			"VSENVIRONMENTALDAMAGE_DROWNING_OTHER",

			"VSENVIRONMENTALDAMAGE_FALLING_OTHER",

			"VSENVIRONMENTALDAMAGE_FATIGUE_OTHER",

			"VSENVIRONMENTALDAMAGE_FIRE_OTHER",

			"VSENVIRONMENTALDAMAGE_LAVA_OTHER",

			"VSENVIRONMENTALDAMAGE_SLIME_OTHER",

		}

	elseif category == "EnvSelf" then	list = {

			"VSENVIRONMENTALDAMAGE_DROWNING_SELF",

			"VSENVIRONMENTALDAMAGE_FALLING_SELF",

			"VSENVIRONMENTALDAMAGE_FATIGUE_SELF",

			"VSENVIRONMENTALDAMAGE_FIRE_SELF",

			"VSENVIRONMENTALDAMAGE_LAVA_SELF",

			"VSENVIRONMENTALDAMAGE_SLIME_SELF",

		}

	-- HoT effects on others. (not casted by others)

	elseif category == "HotOther" then	list = {

			"PERIODICAURAHEALOTHEROTHER",

			"PERIODICAURAHEALSELFOTHER",

		}

	-- HoT effects on you. (not casted by you)

	elseif category == "HotSelf" then	list = {

			"PERIODICAURAHEALSELFSELF",

			"PERIODICAURAHEALOTHERSELF",

		}

	elseif category == "PowerGainSelf" then	list = {

			"POWERGAINSELFSELF",

			"POWERGAINSELFOTHER",

		}

	elseif category == "BuffOther" then	list = {

		"AURAAPPLICATIONADDEDOTHERHELPFUL",

		"AURAADDEDOTHERHELPFUL",

		}

	elseif category == "BuffSelf" then	list = {

			"AURAADDEDSELFHELPFUL",

			"AURAAPPLICATIONADDEDSELFHELPFUL",

		}

	elseif category == "DrainSelf" then	list = {	

			"SPELLPOWERLEECHSELFOTHER",

			"SPELLPOWERDRAINSELFOTHER",

			"SPELLPOWERDRAINSELFSELF",

		}

	elseif category == "DrainOther" then	list = {	

			"SPELLPOWERLEECHOTHEROTHER",

			"SPELLPOWERLEECHOTHERSELF",

			"SPELLPOWERDRAINOTHEROTHER",

			"SPELLPOWERDRAINOTHERSELF",

		}

	-- DoT effects on others (not casted by others)

	elseif category == "DotOther" then	list = {

			"PERIODICAURADAMAGEOTHEROTHER",

			"PERIODICAURADAMAGESELFOTHER",

		}

	-- DoT effects on you (not casted by you)

	elseif category == "DotSelf" then	list = {

			"PERIODICAURADAMAGEOTHERSELF",

			"PERIODICAURADAMAGESELFSELF",

		}

	elseif category == "SpellHitOther" then	list = {

			"SPELLLOGCRITOTHEROTHER",

			"SPELLLOGCRITOTHERSELF",

			"SPELLLOGCRITSCHOOLOTHEROTHER",

			"SPELLLOGCRITSCHOOLOTHERSELF",

			"SPELLLOGOTHEROTHER",

			"SPELLLOGOTHERSELF",

			"SPELLLOGSCHOOLOTHEROTHER",

			"SPELLLOGSCHOOLOTHERSELF",

		}

	elseif category == "SpellHitSelf" then	list = {

			"SPELLLOGCRITSELFOTHER",

			"SPELLLOGCRITSELFSELF",

			"SPELLLOGCRITSCHOOLSELFOTHER",

			"SPELLLOGCRITSCHOOLSELFSELF",

			"SPELLLOGSELFOTHER",

			"SPELLLOGSELFSELF",

			"SPELLLOGSCHOOLSELFOTHER",

			"SPELLLOGSCHOOLSELFSELF",

		}

	elseif category == "SpellMissSelf" then		list = {

			"IMMUNESPELLSELFOTHER",

			"IMMUNESPELLSELFSELF",

			"SPELLBLOCKEDSELFOTHER",

			"SPELLDEFLECTEDSELFOTHER",

			"SPELLDEFLECTEDSELFSELF",

			"SPELLDODGEDSELFOTHER",

			"SPELLDODGEDSELFSELF",

			"SPELLEVADEDSELFOTHER",

			"SPELLEVADEDSELFSELF",

			"SPELLIMMUNESELFOTHER",

			"SPELLIMMUNESELFSELF",

			"SPELLLOGABSORBSELFOTHER",

			"SPELLLOGABSORBSELFSELF",

			"SPELLMISSSELFOTHER",

			"SPELLMISSSELFSELF",

			"SPELLPARRIEDSELFOTHER",

			"SPELLPARRIEDSELFSELF",

			"SPELLREFLECTSELFOTHER",

			"SPELLREFLECTSELFSELF",

			"SPELLRESISTSELFOTHER",

			"SPELLRESISTSELFSELF",

		}

	elseif category == "SpellMissOther" then		list = {

			"IMMUNESPELLOTHEROTHER",

			"IMMUNESPELLOTHERSELF",

			"SPELLBLOCKEDOTHEROTHER",

			"SPELLBLOCKEDOTHERSELF",

			"SPELLDODGEDOTHEROTHER",

			"SPELLDODGEDOTHERSELF",

			"SPELLDEFLECTEDOTHEROTHER",

			"SPELLDEFLECTEDOTHERSELF",

			"SPELLEVADEDOTHEROTHER",

			"SPELLEVADEDOTHERSELF",

			"SPELLIMMUNEOTHEROTHER",

			"SPELLIMMUNEOTHERSELF",

			"SPELLLOGABSORBOTHEROTHER",

			"SPELLLOGABSORBOTHERSELF",

			"SPELLMISSOTHEROTHER",

			"SPELLMISSOTHERSELF",

			"SPELLPARRIEDOTHEROTHER",

			"SPELLPARRIEDOTHERSELF",

			"SPELLREFLECTOTHEROTHER",

			"SPELLREFLECTOTHERSELF",

			"SPELLRESISTOTHEROTHER",

			"SPELLRESISTOTHERSELF",

		}	

	elseif category == "InterruptOther" then	list = {

			"SPELLINTERRUPTOTHEROTHER",

			"SPELLINTERRUPTOTHERSELF",

		}

	elseif category == "InterruptSelf" then	list = {

			"SPELLINTERRUPTSELFOTHER",

		}

	elseif category == "SplitDamageOther" then list = {

		"SPELLSPLITDAMAGEOTHEROTHER",

		"SPELLSPLITDAMAGEOTHERSELF",

	}		

	else return { category }

	end

	

	return list

	

end



-- Load categories recursively. First layer will not be sorted.

function lib:LoadPatternCategoryTree(catTree, reSort)

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

	

	local resultList = {}

	local list

	

	for i, v in pairs(catTree) do

	

		if type(v) == "table" then

			list = self:LoadPatternCategoryTree(v, true)

		else -- should be string.		

			list = self:LoadPatternCategory(v)

			table.sort(list, PatternCompare)

		end

		

		for j, w in pairs(list) do

			table.insert(resultList, w)

		end

		

	end

	

	if reSort then

		table.sort(resultList, PatternCompare)

	end

	

	return resultList





end

 

-- Used to load patternTable elements on demand.

function lib:LoadPatternInfo(patternName)



	local patternInfo

	

	if patternName == "AURAADDEDOTHERHELPFUL" then

		patternInfo = { "buff", 1, 2, nil, }

	elseif patternName == "AURAADDEDSELFHELPFUL" then

		patternInfo = { "buff", ParserLib_SELF, 1, nil, }

	elseif patternName == "AURAAPPLICATIONADDEDOTHERHELPFUL" then

		patternInfo = { "buff", 1, 2, 3, }

	elseif patternName == "AURAAPPLICATIONADDEDSELFHELPFUL" then

		patternInfo = { "buff", ParserLib_SELF, 1, 2, }

	

	elseif patternName == "OPEN_LOCK_OTHER" then

		patternInfo = { "cast", 1, 2, 3, nil, true, }

	elseif patternName == "OPEN_LOCK_SELF" then 

		patternInfo = { "cast", ParserLib_SELF, 1, 2, nil, true, }

	elseif patternName == "SIMPLECASTOTHEROTHER" then

		patternInfo = { "cast", 1, 2, 3, nil, nil, }

	elseif patternName == "SIMPLECASTOTHERSELF" then

		patternInfo = { "cast", 1, 2, ParserLib_SELF, nil, nil, }

	elseif patternName == "SIMPLECASTSELFOTHER" then

		patternInfo = { "cast", ParserLib_SELF, 1, 2, nil, nil, }

	elseif patternName == "SIMPLECASTSELFSELF" then

		patternInfo = { "cast", ParserLib_SELF, 1, ParserLib_SELF, nil, nil, }

	elseif patternName == "SIMPLEPERFORMOTHEROTHER" then

		patternInfo = { "cast", 1, 2, 3, nil, true, }

	elseif patternName == "SIMPLEPERFORMOTHERSELF" then

		patternInfo = { "cast", 1, 2, ParserLib_SELF, nil, true, }

	elseif patternName == "SIMPLEPERFORMSELFOTHER" then

		patternInfo = { "cast", ParserLib_SELF, 1, 2, nil, true, }

	elseif patternName == "SIMPLEPERFORMSELFSELF" then

		patternInfo = { "cast", ParserLib_SELF, 1, ParserLib_SELF, nil, true, }

	elseif patternName == "SPELLCASTOTHERSTART" then

		patternInfo = { "cast", 1, 2, nil, true, nil, }

	elseif patternName == "SPELLCASTSELFSTART" then

		patternInfo = { "cast", ParserLib_SELF, 1, nil, true, nil, }

	elseif patternName == "SPELLPERFORMOTHERSTART" then

		patternInfo = { "cast", 1, 2, nil, true, true, }

	elseif patternName == "SPELLPERFORMSELFSTART" then

		patternInfo = { "cast", ParserLib_SELF, 1, nil, true, true, }

	elseif patternName == "SPELLTERSEPERFORM_OTHER" then

		patternInfo = { "cast", 1, 2, nil, nil, true, }

	elseif patternName == "SPELLTERSEPERFORM_SELF" then

		patternInfo = { "cast", ParserLib_SELF, 1, nil, nil, true, }

	elseif patternName == "SPELLTERSE_OTHER" then

		patternInfo = { "cast", 1, 2, nil, nil, nil, }

	elseif patternName == "SPELLTERSE_SELF" then

		patternInfo = { "cast", ParserLib_SELF, 1, nil, nil, nil, }

	

	elseif patternName == "TRADESKILL_LOG_FIRSTPERSON" then

		patternInfo = { "create", ParserLib_SELF, 1, }

	elseif patternName == "TRADESKILL_LOG_THIRDPERSON" then

		patternInfo = { "create", 1, 2, }

	

	elseif patternName == "PARTYKILLOTHER" then

		patternInfo = { "death", 1, 2, nil, nil, }

	elseif patternName == "SELFKILLOTHER" then

		patternInfo = { "death", 1, ParserLib_SELF, nil, nil, }

	elseif patternName == "UNITDESTROYEDOTHER" then

		patternInfo = { "death", 1, nil, nil, true, }

	elseif patternName == "UNITDIESOTHER" then

		patternInfo = { "death", 1, nil, nil, nil, }

	elseif patternName == "UNITDIESSELF" then

		patternInfo = { "death", ParserLib_SELF, nil, nil, nil, }

	elseif patternName == "INSTAKILLOTHER" then

		patternInfo = { "death", 1, nil, 2, nil, }

	elseif patternName == "INSTAKILLSELF" then

		patternInfo = { "death", ParserLib_SELF, nil, true, nil }

	

	

	elseif patternName == "AURAADDEDOTHERHARMFUL" then

		patternInfo = { "debuff", 1, 2, nil, }

	elseif patternName == "AURAADDEDSELFHARMFUL" then

		patternInfo = { "debuff", ParserLib_SELF, 1, nil, }

	elseif patternName == "AURAAPPLICATIONADDEDOTHERHARMFUL" then

		patternInfo = { "debuff", 1, 2, 3, }

	elseif patternName == "AURAAPPLICATIONADDEDSELFHARMFUL" then

		patternInfo = { "debuff", ParserLib_SELF, 1, 2, }

	

	elseif patternName == "AURADISPELOTHER" then

		patternInfo = { "dispel", 1, 2, nil, nil, }

	elseif patternName == "AURADISPELSELF" then

		patternInfo = { "dispel", ParserLib_SELF, 1, nil, nil, }

	elseif patternName == "DISPELFAILEDOTHEROTHER" then

		patternInfo = { "dispel", 2, 3, 1, true, }

	elseif patternName == "DISPELFAILEDOTHERSELF" then

		patternInfo = { "dispel", ParserLib_SELF, 2, 1, true, }

	elseif patternName == "DISPELFAILEDSELFOTHER" then

		patternInfo = { "dispel", 1, 2, ParserLib_SELF, true, }

	elseif patternName == "DISPELFAILEDSELFSELF" then

		patternInfo = { "dispel", ParserLib_SELF, 1, ParserLib_SELF, true, }

	

	elseif patternName == "SPELLPOWERDRAINOTHEROTHER" then

		patternInfo = { "drain", 1, 5, 2, 3, 4, }

	elseif patternName == "SPELLPOWERDRAINOTHERSELF" then

		patternInfo = { "drain", 1, ParserLib_SELF, 2, 3, 4, }

	elseif patternName == "SPELLPOWERDRAINSELFOTHER" then

		patternInfo = { "drain", ParserLib_SELF, 4, 1, 2, 3, }

	elseif patternName == "SPELLPOWERDRAINSELFSELF" then

		patternInfo = { "drain", ParserLib_SELF, ParserLib_SELF, 1, 2, 3, }

	

	elseif patternName == "SPELLDURABILITYDAMAGEALLOTHEROTHER" then

		patternInfo = { "durability", 1, 2, 3, nil, }

	elseif patternName == "SPELLDURABILITYDAMAGEALLOTHERSELF" then

		patternInfo = { "durability", 1, 2, ParserLib_SELF, nil, }

	elseif patternName == "SPELLDURABILITYDAMAGEALLSELFOTHER" then

		patternInfo = { "durability", ParserLib_SELF, 1, 2, nil, }

	elseif patternName == "SPELLDURABILITYDAMAGEOTHEROTHER" then

		patternInfo = { "durability", 1, 2, 3, 4, }

	elseif patternName == "SPELLDURABILITYDAMAGEOTHERSELF" then

		patternInfo = { "durability", 1, 2, ParserLib_SELF, 3, }

	elseif patternName == "SPELLDURABILITYDAMAGESELFOTHER" then

		patternInfo = { "durability", ParserLib_SELF, 1, 2, 3, }

	

	elseif patternName == "ITEMENCHANTMENTADDOTHEROTHER" then

		patternInfo = { "enchant", 1, 3, 2, 4, }

	elseif patternName == "ITEMENCHANTMENTADDOTHERSELF" then

		patternInfo = { "enchant", 1, ParserLib_SELF, 2, 3, }

	elseif patternName == "ITEMENCHANTMENTADDSELFOTHER" then

		patternInfo = { "enchant", ParserLib_SELF, 2, 1, 3, }

	elseif patternName == "ITEMENCHANTMENTADDSELFSELF" then

		patternInfo = { "enchant", ParserLib_SELF, ParserLib_SELF, 1, 2, }

	

	elseif patternName == "VSENVIRONMENTALDAMAGE_DROWNING_OTHER" then

		patternInfo = { "environment", 1, 2, "drown", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_DROWNING_SELF" then

		patternInfo = { "environment", ParserLib_SELF, 1, "drown", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_FALLING_OTHER" then

		patternInfo = { "environment", 1, 2, "fall", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_FALLING_SELF" then

		patternInfo = { "environment", ParserLib_SELF, 1, "fall", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_FATIGUE_OTHER" then

		patternInfo = { "environment", 1, 2, "exhaust", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_FATIGUE_SELF" then

		patternInfo = { "environment", ParserLib_SELF, 1, "exhaust", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_FIRE_OTHER" then

		patternInfo = { "environment", 1, 2, "fire", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_FIRE_SELF" then

		patternInfo = { "environment", ParserLib_SELF, 1, "fire", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_LAVA_OTHER" then

		patternInfo = { "environment", 1, 2, "lava", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_LAVA_SELF" then

		patternInfo = { "environment", ParserLib_SELF, 1, "lava", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_SLIME_OTHER" then

		patternInfo = { "environment", 1, 2, "slime", }

	elseif patternName == "VSENVIRONMENTALDAMAGE_SLIME_SELF" then

		patternInfo = { "environment", ParserLib_SELF, 1, "slime", }

	

	elseif patternName == "COMBATLOG_XPGAIN" then

		patternInfo = { "experience", 2, nil, nil, nil, nil, nil, nil, nil, 1, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION1" then

		patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION1_GROUP" then

		patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, 5, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION1_RAID" then

		patternInfo = { "experience", 2, 1, 3, 4, nil, nil, 5, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION2" then

		patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION2_GROUP" then

		patternInfo = { "experience", 2, 1, 3, 4, nil, nil, nil, 5, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION2_RAID" then

		patternInfo = { "experience", 2, 1, 3, 4, nil, nil, 5, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION4" then

		patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION4_GROUP" then

		patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, 5, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION4_RAID" then

		patternInfo = { "experience", 2, 1, nil, nil, 3, 4, 5, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION5" then

		patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION5_GROUP" then

		patternInfo = { "experience", 2, 1, nil, nil, 3, 4, nil, 5, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_EXHAUSTION5_RAID" then

		patternInfo = { "experience", 2, 1, nil, nil, 3, 4, 5, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON" then

		patternInfo = { "experience", 2, 1, nil, nil, nil, nil, nil, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_GROUP" then

		patternInfo = { "experience", 2, 1, nil, nil, nil, nil, nil, 3, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_RAID" then

		patternInfo = { "experience", 2, 1, nil, nil, nil, nil, 3, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED" then

		patternInfo = { "experience", 1, nil, nil, nil, nil, nil, nil, nil, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_GROUP" then

		patternInfo = { "experience", 1, nil, nil, nil, nil, nil, nil, 2, nil, }

	elseif patternName == "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_RAID" then

		patternInfo = { "experience", 1, nil, nil, nil, nil, nil, 2, nil, nil, }

	elseif patternName == "COMBATLOG_XPLOSS_FIRSTPERSON_UNNAMED" then

		patternInfo = { "experience", 1, nil, nil, nil, nil, nil, nil, nil, nil, }

	

	elseif patternName == "SPELLEXTRAATTACKSOTHER" then

		patternInfo = { "extraattack", 1, 3, 2, }

	elseif patternName == "SPELLEXTRAATTACKSOTHER_SINGULAR" then

		patternInfo = { "extraattack", 1, 3, 2, }

	elseif patternName == "SPELLEXTRAATTACKSSELF" then

		patternInfo = { "extraattack", ParserLib_SELF, 2, 1, }

	elseif patternName == "SPELLEXTRAATTACKSSELF_SINGULAR" then

		patternInfo = { "extraattack", ParserLib_SELF, 2, 1, }

	

	elseif patternName == "AURAREMOVEDOTHER" then

		patternInfo = { "fade", 2, 1, }

	elseif patternName == "AURAREMOVEDSELF" then

		patternInfo = { "fade", ParserLib_SELF, 1, }

	

	elseif patternName == "SPELLFAILCASTSELF" then

		patternInfo = { "fail", ParserLib_SELF, 1, 2, }

	elseif patternName == "SPELLFAILPERFORMSELF" then

		patternInfo = { "fail", ParserLib_SELF, 1, 2, }

	

	elseif patternName == "FEEDPET_LOG_FIRSTPERSON" then

		patternInfo = { "feedpet", ParserLib_SELF, 1, }

	elseif patternName == "FEEDPET_LOG_THIRDPERSON" then

		patternInfo = { "feedpet", 1, 2, }

	

	elseif patternName == "POWERGAINOTHEROTHER" then

		patternInfo = { "gain", 4, 1, 5, 2, 3, }

	elseif patternName == "POWERGAINOTHERSELF" then

		patternInfo = { "gain", 3, ParserLib_SELF, 4, 1, 2, }

	elseif patternName == "POWERGAINSELFOTHER" then

		patternInfo = { "gain", ParserLib_SELF, 1, 4, 2, 3, }

	elseif patternName == "POWERGAINSELFSELF" then

		patternInfo = { "gain", ParserLib_SELF, ParserLib_SELF, 3, 1, 2, }

	

	elseif patternName == "HEALEDCRITOTHEROTHER" then

		patternInfo = { "heal", 1, 3, 2, 4, true, nil, }

	elseif patternName == "HEALEDCRITOTHERSELF" then

		patternInfo = { "heal", 1, ParserLib_SELF, 2, 3, true, nil, }

	elseif patternName == "HEALEDCRITSELFOTHER" then

		patternInfo = { "heal", ParserLib_SELF, 2, 1, 3, true, nil, }

	elseif patternName == "HEALEDCRITSELFSELF" then

		patternInfo = { "heal", ParserLib_SELF, ParserLib_SELF, 1, 2, true, nil, }

	elseif patternName == "HEALEDOTHEROTHER" then

		patternInfo = { "heal", 1, 3, 2, 4, nil, nil, }

	elseif patternName == "HEALEDOTHERSELF" then

		patternInfo = { "heal", 1, ParserLib_SELF, 2, 3, nil, nil, }

	elseif patternName == "HEALEDSELFOTHER" then

		patternInfo = { "heal", ParserLib_SELF, 2, 1, 3, nil, nil, }

	elseif patternName == "HEALEDSELFSELF" then

		patternInfo = { "heal", ParserLib_SELF, ParserLib_SELF, 1, 2, nil, nil, }

	elseif patternName == "PERIODICAURAHEALOTHEROTHER" then

		patternInfo = { "heal", 3, 1, 4, 2, nil, true, }

	elseif patternName == "PERIODICAURAHEALOTHERSELF" then

		patternInfo = { "heal", 2, ParserLib_SELF, 3, 1, nil, true, }

	elseif patternName == "PERIODICAURAHEALSELFOTHER" then

		patternInfo = { "heal", ParserLib_SELF, 1, 3, 2, nil, true, }

	elseif patternName == "PERIODICAURAHEALSELFSELF" then

		patternInfo = { "heal", ParserLib_SELF, ParserLib_SELF, 2, 1, nil, true, }

	

	elseif patternName == "COMBATHITCRITOTHEROTHER" then

		patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, nil, true, nil, nil, }

	elseif patternName == "COMBATHITCRITOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, nil, true, nil, nil, }

	elseif patternName == "COMBATHITCRITSCHOOLOTHEROTHER" then

		patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, 4, true, nil, nil, }

	elseif patternName == "COMBATHITCRITSCHOOLOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, 3, true, nil, nil, }

	elseif patternName == "COMBATHITCRITSCHOOLSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, 3, true, nil, nil, }

	elseif patternName == "COMBATHITCRITSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, nil, true, nil, nil, }

	elseif patternName == "COMBATHITOTHEROTHER" then

		patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, nil, nil, nil, nil, }

	elseif patternName == "COMBATHITOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, nil, nil, nil, nil, }

	elseif patternName == "COMBATHITSCHOOLOTHEROTHER" then

		patternInfo = { "hit", 1, 2, ParserLib_MELEE, 3, 4, nil, nil, nil, }

	elseif patternName == "COMBATHITSCHOOLOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_MELEE, 2, 3, nil, nil, nil, }

	elseif patternName == "COMBATHITSCHOOLSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, 3, nil, nil, nil, }

	elseif patternName == "COMBATHITSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 1, ParserLib_MELEE, 2, nil, nil, nil, nil, }

	elseif patternName == "DAMAGESHIELDOTHEROTHER" then

		patternInfo = { "hit", 1, 4, ParserLib_DAMAGESHIELD, 2, 3, nil, nil, nil, }

	elseif patternName == "DAMAGESHIELDOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, ParserLib_DAMAGESHIELD, 2, 3, nil, nil, nil, }

	elseif patternName == "DAMAGESHIELDSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 3, ParserLib_DAMAGESHIELD, 1, 2, nil, nil, nil, }

	elseif patternName == "PERIODICAURADAMAGEOTHEROTHER" then

		patternInfo = { "hit", 4, 1, 5, 2, 3, nil, true, nil, }

	elseif patternName == "PERIODICAURADAMAGEOTHERSELF" then

		patternInfo = { "hit", 3, ParserLib_SELF, 4, 1, 2, nil, true, nil, }

	elseif patternName == "PERIODICAURADAMAGESELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 1, 4, 2, 3, nil, true, nil, }

	elseif patternName == "PERIODICAURADAMAGESELFSELF" then

		patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 3, 1, 2, nil, true, nil, }

	elseif patternName == "SPELLLOGCRITOTHEROTHER" then

		patternInfo = { "hit", 1, 3, 2, 4, nil, true, nil, nil, }

	elseif patternName == "SPELLLOGCRITOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, nil, true, nil, nil, }

	elseif patternName == "SPELLLOGCRITSCHOOLOTHEROTHER" then

		patternInfo = { "hit", 1, 3, 2, 4, 5, true, nil, nil, }

	elseif patternName == "SPELLLOGCRITSCHOOLOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, 4, true, nil, nil, }

	elseif patternName == "SPELLLOGCRITSCHOOLSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, 4, true, nil, nil, }

	elseif patternName == "SPELLLOGCRITSCHOOLSELFSELF" then

		patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, 3, true, nil, nil, }

	elseif patternName == "SPELLLOGCRITSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, nil, true, nil, nil, }

	elseif patternName == "SPELLLOGCRITSELFSELF" then

		patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, nil, true, nil, nil, }

	elseif patternName == "SPELLLOGOTHEROTHER" then

		patternInfo = { "hit", 1, 3, 2, 4, nil, nil, nil, nil, }

	elseif patternName == "SPELLLOGOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, nil, nil, nil, nil, }

	elseif patternName == "SPELLLOGSCHOOLOTHEROTHER" then

		patternInfo = { "hit", 1, 3, 2, 4, 5, nil, nil, nil, }

	elseif patternName == "SPELLLOGSCHOOLOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, 4, nil, nil, nil, }

	elseif patternName == "SPELLLOGSCHOOLSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, 4, nil, nil, nil, }

	elseif patternName == "SPELLLOGSCHOOLSELFSELF" then

		patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, 3, nil, nil, nil, }

	elseif patternName == "SPELLLOGSELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, nil, nil, nil, nil, }

	elseif patternName == "SPELLLOGSELFSELF" then

		patternInfo = { "hit", ParserLib_SELF, ParserLib_SELF, 1, 2, nil, nil, nil, nil, }

	elseif patternName == "SPELLSPLITDAMAGEOTHEROTHER" then

		patternInfo = { "hit", 1, 3, 2, 4, nil, nil, nil, true, }

	elseif patternName == "SPELLSPLITDAMAGEOTHERSELF" then

		patternInfo = { "hit", 1, ParserLib_SELF, 2, 3, nil, nil, nil, true, }

	elseif patternName == "SPELLSPLITDAMAGESELFOTHER" then

		patternInfo = { "hit", ParserLib_SELF, 2, 1, 3, nil, nil, nil, true, }

	

	elseif patternName == "COMBATLOG_DISHONORGAIN" then

		patternInfo = { "honor", nil, 1, nil, }

	elseif patternName == "COMBATLOG_HONORAWARD" then

		patternInfo = { "honor", 1, nil, nil, }

	elseif patternName == "COMBATLOG_HONORGAIN" then

		patternInfo = { "honor", 3, 1, 2, }

	

	elseif patternName == "SPELLINTERRUPTOTHEROTHER" then

		patternInfo = { "interrupt", 1, 2, 3, }

	elseif patternName == "SPELLINTERRUPTOTHERSELF" then

		patternInfo = { "interrupt", 1, ParserLib_SELF, 2, }

	elseif patternName == "SPELLINTERRUPTSELFOTHER" then

		patternInfo = { "interrupt", ParserLib_SELF, 1, 2, }

	

	elseif patternName == "SPELLPOWERLEECHOTHEROTHER" then

		patternInfo = { "leech", 1, 5, 2, 3, 4, 6, 7, 8, }

	elseif patternName == "SPELLPOWERLEECHOTHERSELF" then

		patternInfo = { "leech", 1, ParserLib_SELF, 2, 3, 4, 5, 6, 7, }

	elseif patternName == "SPELLPOWERLEECHSELFOTHER" then

		patternInfo = { "leech", ParserLib_SELF, 4, 1, 2, 3, ParserLib_SELF, 5, 6, }

	

	elseif patternName == "IMMUNEDAMAGECLASSOTHEROTHER" then

		patternInfo = { "miss", 2, 1, ParserLib_MELEE, "immune", }

	elseif patternName == "IMMUNEDAMAGECLASSOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "immune", }

	elseif patternName == "IMMUNEDAMAGECLASSSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "immune", }

	elseif patternName == "IMMUNEOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "immune", }

	elseif patternName == "IMMUNEOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "immune", }

	elseif patternName == "IMMUNESELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "immune", }

	elseif patternName == "IMMUNESELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, ParserLib_MELEE, "immune", }

	elseif patternName == "IMMUNESPELLOTHEROTHER" then

		patternInfo = { "miss", 2, 1, 3, "immune", }

	elseif patternName == "IMMUNESPELLOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "immune", }

	elseif patternName == "IMMUNESPELLSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, 2, "immune", }

	elseif patternName == "IMMUNESPELLSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "immune", }

	elseif patternName == "MISSEDOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "miss", }

	elseif patternName == "MISSEDOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "miss", }

	elseif patternName == "MISSEDSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "miss", }

	elseif patternName == "PROCRESISTOTHEROTHER" then

		patternInfo = { "miss", 2, 1, 3, "resist", }

	elseif patternName == "PROCRESISTOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "resist", }

	elseif patternName == "PROCRESISTSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, 2, "resist", }

	elseif patternName == "PROCRESISTSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "resist", }

	elseif patternName == "SPELLBLOCKEDOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "block", }

	elseif patternName == "SPELLBLOCKEDOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "block", }

	elseif patternName == "SPELLBLOCKEDSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "block", }

	elseif patternName == "SPELLDEFLECTEDOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "deflect", }

	elseif patternName == "SPELLDEFLECTEDOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "deflect", }

	elseif patternName == "SPELLDEFLECTEDSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "deflect", }

	elseif patternName == "SPELLDEFLECTEDSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "deflect", }

	elseif patternName == "SPELLDODGEDOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "dodge", }

	elseif patternName == "SPELLDODGEDOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "dodge", }

	elseif patternName == "SPELLDODGEDSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "dodge", }

	elseif patternName == "SPELLDODGEDSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "dodge", }

	elseif patternName == "SPELLEVADEDOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "evade", }

	elseif patternName == "SPELLEVADEDOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "evade", }

	elseif patternName == "SPELLEVADEDSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "evade", }

	elseif patternName == "SPELLEVADEDSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "evade", }

	elseif patternName == "SPELLIMMUNEOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "immune", }

	elseif patternName == "SPELLIMMUNEOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "immune", }

	elseif patternName == "SPELLIMMUNESELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "immune", }

	elseif patternName == "SPELLIMMUNESELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "immune", }

	elseif patternName == "SPELLLOGABSORBOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "absorb", }

	elseif patternName == "SPELLLOGABSORBOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "absorb", }

	elseif patternName == "SPELLLOGABSORBSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "absorb", }

	elseif patternName == "SPELLLOGABSORBSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "absorb", }

	elseif patternName == "SPELLMISSOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "miss", }

	elseif patternName == "SPELLMISSOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "miss", }

	elseif patternName == "SPELLMISSSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "miss", }

	elseif patternName == "SPELLMISSSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "miss", }

	elseif patternName == "SPELLPARRIEDOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "parry", }

	elseif patternName == "SPELLPARRIEDOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "parry", }

	elseif patternName == "SPELLPARRIEDSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "parry", }

	elseif patternName == "SPELLPARRIEDSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "parry", }

	elseif patternName == "SPELLREFLECTOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "reflect", }

	elseif patternName == "SPELLREFLECTOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "reflect", }

	elseif patternName == "SPELLREFLECTSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "reflect", }

	elseif patternName == "SPELLREFLECTSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "reflect", }

	elseif patternName == "SPELLRESISTOTHEROTHER" then

		patternInfo = { "miss", 1, 3, 2, "resist", }

	elseif patternName == "SPELLRESISTOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, 2, "resist", }

	elseif patternName == "SPELLRESISTSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 2, 1, "resist", }

	elseif patternName == "SPELLRESISTSELFSELF" then

		patternInfo = { "miss", ParserLib_SELF, ParserLib_SELF, 1, "resist", }

	elseif patternName == "VSABSORBOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "absorb", }

	elseif patternName == "VSABSORBOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "absorb", }

	elseif patternName == "VSABSORBSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "absorb", }

	elseif patternName == "VSBLOCKOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "block", }

	elseif patternName == "VSBLOCKOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "block", }

	elseif patternName == "VSBLOCKSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "block", }

	elseif patternName == "VSDEFLECTOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "deflect", }

	elseif patternName == "VSDEFLECTOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "deflect", }

	elseif patternName == "VSDEFLECTSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "deflect", }

	elseif patternName == "VSDODGEOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "dodge", }

	elseif patternName == "VSDODGEOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "dodge", }

	elseif patternName == "VSDODGESELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "dodge", }

	elseif patternName == "VSEVADEOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "evade", }

	elseif patternName == "VSEVADEOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "evade", }

	elseif patternName == "VSEVADESELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "evade", }

	elseif patternName == "VSIMMUNEOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "immune", }

	elseif patternName == "VSIMMUNEOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "immune", }

	elseif patternName == "VSIMMUNESELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "immune", }

	elseif patternName == "VSPARRYOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "parry", }

	elseif patternName == "VSPARRYOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "parry", }

	elseif patternName == "VSPARRYSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "parry", }

	elseif patternName == "VSRESISTOTHEROTHER" then

		patternInfo = { "miss", 1, 2, ParserLib_MELEE, "resist", }

	elseif patternName == "VSRESISTOTHERSELF" then

		patternInfo = { "miss", 1, ParserLib_SELF, ParserLib_MELEE, "resist", }

	elseif patternName == "VSRESISTSELFOTHER" then

		patternInfo = { "miss", ParserLib_SELF, 1, ParserLib_MELEE, "resist", }

	

	elseif patternName == "FACTION_STANDING_CHANGED" then

		patternInfo = { "reputation", 2, nil, 1, nil, }

	elseif patternName == "FACTION_STANDING_DECREASED" then

		patternInfo = { "reputation", 1, 2, nil, true, }

	elseif patternName == "FACTION_STANDING_INCREASED" then

		patternInfo = { "reputation", 1, 2, nil, nil, }

	end

	

	if not patternInfo then

		-- self:Print("LoadPatternInfo(): Cannot find " .. patternName ); -- debug

		return

	end

	

	local pattern = getglobal(patternName);	-- Get the pattern from GlobalStrings.lua

	

	-- Add a function to fix some global strings.

	if FixGlobalString then

		local fixPattern = FixGlobalString(patternName, pattern);

		if pattern ~= fixPattern then

			--self:Print("PP : "..pattern)  -- debug

			--self:Print("FP : "..fixPattern)  -- debug

			setglobal(patternName, fixPattern);

			pattern = fixPattern

		end

	end

	

	-- How many regexp tokens in this pattern?

	local tc = 0

	for _ in string_gmatch(pattern, "%%%d?%$?([sd])") do tc = tc + 1 end

	

	-- Convert string.format tokens into LUA regexp tokens.

	pattern = { self:ConvertPattern(pattern, true) }		



	local n = #(pattern)	

	if n > 1 then	-- Extra return values are the remapped token sequences.

	

		for j in pairs(patternInfo) do

			if type(patternInfo[j]) == "number" and patternInfo[j] < 100 then

				patternInfo[j] = pattern[patternInfo[j]+1]	-- Remap to correct token sequence.

			end

		end

		

	end	



	patternInfo.tc = tc

	patternInfo.pattern = pattern[1]

	

	return patternInfo



end



-- Fields of the patternTable.

lib.infoMap = {

	hit = { "source", "victim", "skill", "amount", "element", "isCrit", "isDOT", "isSplit" },

	heal = { "source", "victim", "skill", "amount", "isCrit", "isDOT" },

	miss = { "source", "victim", "skill", "missType" },

	death = { "victim", "source", "skill", "isItem" },

	debuff = { "victim", "skill", "amountRank" },

	buff = { "victim", "skill", "amountRank" },

	fade = { "victim", "skill" },

	cast = { "source", "skill", "victim", "isBegin", "isPerform" },	

	gain = { "source", "victim", "skill", "amount", "attribute" },

	drain = { "source", "victim", "skill", "amount", "attribute" },

	leech = { "source", "victim", "skill", "amount", "attribute", "sourceGained", "amountGained", "attributeGained" },

	dispel = { "victim", "skill", "source", "isFailed" },

	extraattack = { "victim", "skill", "amount" },

	environment = { "victim", "amount", "damageType" },

	experience = { "amount", "source", "bonusAmount", "bonusType", "penaltyAmount", "penaltyType", "amountRaidPenalty", "amountGroupBonus", "victim" },

	reputation = { "faction", "amount", "rank", "isNegative" },

	feedpet = { "victim", "item" },

	enchant = { "source", "victim", "skill", "item" },

	fail = { "source", "skill", "reason" },

	interrupt = { "source", "victim", "skill" },

	create = { "source", "item" },

	honor = { "amount", "source", "sourceRank" }, -- if amount == nil then isDishonor = true.

	durability = { "source", "skill", "victim", "item" }, -- is not item then isAllItems = true 

	unknown = { "message" },	

}



function lib:GetInfoFieldName(infoType, fieldIndex)

	if self.infoMap[infoType] then

		return self.infoMap[infoType][fieldIndex-1]	-- Skip the first field in patternTable which is 'type'.

	end

end



--------------------------------

--      Load this bitch!      --

--------------------------------

libobj:Register(lib)

