Notifications = AsheylaLib:NewModule("Notifications","SpellLib","GUILib","TimerLib")
local currentinfo = {}
local specialevents = {
	["Player Buff Gain"] = "This is sent when you gain a buff. (%s: the buff)",
	["Player Debuff Gain"] = "This is sent when you get a debuff.  It is sent once for the debuff name, and once for its dispel type. (%s: the debuff or type)", 
	["Player Buff Time Remaining"] = "This is sent every second for each of your current buffs.  (%s: the buff, %d: amount time remaining)",
	["Player Debuff Time Remaining"] = "This is sent every second for each of your current debuffs.  (%s: the debuff, %d: amount time remaining)",
	["Player Buff Fade"] = "This is sent when a buff fades from you. (%s: the buff)",
	["Player Debuff Fade"] = "This is sent when a debuff fades from you. (%s: the debuff)",
	["Enemy Target Begin Casting"] = "This is sent when your hostile target begins casting a spell. (%s: the spell, %t: your target)",
	["Enemy Target Buff Gain"] = "This is sent when your hostile target gains a buff.  (%s: the buff, %t: your target)",
	["Enemy Target Debuff Gain"] = "This is sent when your hostile target is afflicted by a debuff (%s: the debuff, %t: your target)",
	["Enemy Target Buff/Debuff Fade"] = "This is sent when a buff or debuff fades from your hostile target. (%s: the (de)buff, %t: your target)",
	["Enemy Begin Casting"] = "This is sent when a hostile unit begins casting a spell. (%s: the spell, %t: the player)",
	["Enemy Buff Gain"] = "This is sent when a hostile unit gains a buff.  (%s: the buff, %t: the player)",
	["Enemy Debuff Gain"] = "This is sent when a hostile unit is afflicted by a debuff (%s: the debuff, %t: the player)",
	["Enemy Buff/Debuff Fade"] = "This is sent when a buff or debuff fades from a hostile unit. (%s: the (de)buff, %t: the player)",
	["Friendly Buff Gain"] = "This is sent when a friendly player gains a buff.  (%s: the buff, %t: the player)",
	["Combat Log"] = "This option requires that you have combat scanning turned on.  This is sent whenever a combat log message matches a matchstring you specify.  This is for advanced users only.  (%s,%t,%d: the return values (in order, any more are discarded) from your matchstring).",
	["DoT Time Remaining"] = "This option requires DoTimer in order to function.  This is sent every second for each of your DoTimer timers.  (%s: the spell, %t: its target, %d: amount time remaining)", --dotimer
	["DoT Break Early"] = "This option requires DoTimer in order to function.  This is sent when a DoT you cast is detected to have broken early from its target. (%s: the spell, %t: its target)", --dotimer
	["DoT Full Duration"] = "This option requires DoTimer in order to function.  This is sent when a DoT you cast expires due to full duration.  (%s: the spell, %t: its target)", --dotimer
	["DoT Begin Timer"] = "This option requires DoTimer in order to function.  This is sent when a DoT you cast successfully lands on its target.  (%s: the spell, %t: its target)", --dotimer
	["Cooldown Full Duration"] = "This option requires Cooldowns in order to function.  This is sent when a Cooldown finishes.  (%s: the cooldown, %t: Soulstone's target)", --cooldowns
	["Cooldown Time Remaining"] = "This option requires Cooldowns in order to function.  This is sent every second for each of your Cooldowns timers.  (%s: the spell, %d: amount time remaining, %t: Soulstone's target)", --cooldowns
	["Cooldown Begin Timer"] = "This option requires Cooldowns in order to function.  This is sent when a cooldown is initially activated.  (%s: the spell, %t: Soulstone's target)", --cooldowns
}
local regevents = {
	["Spell Begin Casting"] = "This is sent when you begin casting a spell.  (%s: the spell, %t: the spell's target)", 
	["Spell Finish Casting"] = "This is sent when you finish casting a spell.  (%s: the spell, %t: the spell's target)",
	["Item Usage"] = "This is sent when you use an item.  (%s: the item, %t: the item's target, if applicable)",
	["Spell Failed on Mob"] = "This is sent when a spell or ability you cast on a mob is resisted, dodged, evaded, etc.  (%s: the spell, %t: the target, %d: the reason for failure)", 
	["Spell Damage"] = "This is sent when a spell or ability you cast on a mob hits or crits.  (%s: the spell, %t: the target, %d: amount damage)",
	["Spell Heal"] = "This is sent when you heal someone with a spell or ability, regular or crit.  (%s: the spell, %t: the target, %d: amount damage)",
	["Spell Crit Mob"] = "This is sent when you crit a mob with a spell or ability (not white damage).  (%s: the spell, %t: the target, %d: amount damage)",
	["Spell Crit Heal"] = "This is sent when you crit someone with a heal.  (%s: the spell, %t: the target, %d: amount healed)",
}
local miscevents = {
	["Aggro Gain"] = "This is sent when your current hostile target switches its target to you from something else. (%t: your target)",
	["Aggro Loss"] = "This is sent when your current hostile target switches its target to something else from you.  (%t: your target)",
	["Health"] = "This is sent every time you gain or lose health.  (%d: your current health)",
	["Mana"] = "This is sent every time you gain or lose mana, energy, or rage.  (%d: your current mana/energy/rage)",
}
local orgeventlist = {
	{
		name = "Spells and Items",
		tooltip = "These events pertain to spell casting and item usage.",
		"Spell Begin Casting",
		"Spell Finish Casting",
		"Item Usage",
		"Spell Failed on Mob",
		"Spell Damage",
		"Spell Heal",
		"Spell Crit Mob",
	},
	{
		name = "DoTimer/Cooldowns",
		tooltip = "These events pertain to the addons DoTimer and Cooldowns.",
		"DoT Begin Timer",
		"DoT Time Remaining",
		"DoT Break Early",
		"DoT Full Duration",
		"Cooldown Begin Timer",
		"Cooldown Time Remaining",
		"Cooldown Full Duration",
	},
	{
		name = "The Player",
		tooltip = "These events pertain to you! the player.",
		"Player Buff Gain",
		"Player Debuff Gain",
		"Player Buff Fade",
		"Player Debuff Fade",
		"Player Buff Time Remaining",
		"Player Debuff Time Remaining",
	},
	{
		name = "Others",
		tooltip = "These events pertain to characters and mobs other than the player.",
		"Friendly Buff Gain",
		"Enemy Target Buff Gain",
		"Enemy Target Debuff Gain",
		"Enemy Target Buff/Debuff Fade",
		"Enemy Begin Casting",
		"Enemy Buff Gain",
		"Enemy Debuff Gain",
		"Enemy Buff/Debuff Fade",
		"Enemy Target Begin Casting",
	},
	{
		name = "Miscellaneous",
		tooltip = "These events don't really fit into the other categories.",
		"Aggro Gain",
		"Aggro Loss",
		"Health",
		"Mana",
		"Combat Log",
	},
}
local failmsgs = {
	["Resist"] = string.gsub(SPELLRESISTSELFOTHER,"%%.-s","(.+)"),
	["Evade"] = string.gsub(SPELLEVADEDSELFOTHER,"%%.-s","(.+)"),
	["Immune"] = string.gsub(SPELLIMMUNESELFOTHER,"%%.-s","(.+)"),
	["Reflect"] = string.gsub(SPELLREFLECTSELFOTHER,"%%.-s","(.+)"),
	["Dodge"] = string.gsub(SPELLDODGEDSELFOTHER,"%%.-s","(.+)"),
	["Parry"] = string.gsub(SPELLPARRIEDSELFOTHER,"%%.-s","(.+)"),
	["Miss"] = string.gsub(SPELLMISSSELFOTHER,"%%.-s","(.+)"),
	["Absorb"] = string.gsub(SPELLLOGABSORBSELFOTHER,"%%.-s","(.+)"),
}
local hitmsgs = {
	spellhit = string.gsub(SPELLLOGSCHOOLSELFOTHER,"%%.-[sd]","(.+)"),
	abilityhit = string.gsub(SPELLLOGSELFOTHER,"%%.-[sd]","(.+)"),
}
local critmsgs = {
	spellcrit = string.gsub(SPELLLOGCRITSCHOOLSELFOTHER,"%%.-[sd]","(.+)"),
	abilitycrit = string.gsub(SPELLLOGCRITSELFOTHER,"%%.-[sd]","(.+)"),
}
local healcritother = string.gsub(HEALEDCRITSELFOTHER,"%%.-[sd]","(.+)")
local healcritself = string.gsub(HEALEDCRITSELFSELF,"%%.-[sd]","(.+)")
local healhitother = string.gsub(HEALEDSELFOTHER,"%%.-[sd]","(.+)")
local healhitself = string.gsub(HEALEDSELFSELF,"%%.-[sd]","(.+)")
local enemygainsbuff = string.gsub(AURAADDEDOTHERHELPFUL,"%%.-[sd]","(.+)")
local enemylosesbuff = string.gsub(AURAREMOVEDOTHER,"%%.-[sd]","(.+)")
local spellcaststartother = string.gsub(SPELLCASTOTHERSTART,"%%.-[sd]","(.+)")
local playerclass
local prevmana
local prevhealth
local prevstate
local defaultsettings
local defaulttimersettings
local spelltarget = {}

function Notifications:OnLoad()
	this:RegisterEvent("PLAYER_ENTERING_WORLD")
	this:RegisterEvent("UNIT_SPELLCAST_SENT")
	this:RegisterEvent("UNIT_SPELLCAST_START")
	this:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE") --when you do damage with a spell
	this:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF") --when you heal with a spell
	this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS") --hostile player gaining a buff
	this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS") --when a creature gains a buff
	this:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_OTHER") --hostile losing a buff
	this:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE") --when a hostile player begins to cast a spell
	this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF") --creature begins to cast a beneficial spell
	this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE") --creature begins to cast a harmful spell
	this:RegisterEvent("COMBAT_TEXT_UPDATE") --player buff/debuff gain/loss
	this:RegisterEvent("UNIT_HEALTH")
	this:RegisterEvent("UNIT_MANA")
	this:RegisterEvent("PLAYER_TARGETS_CHANGED")
	this:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
end

function Notifications:Startup()
	self:RegisterSettings()
	self:AddDefaultSettings(defaultsettings)
	ProfileLib:RegisterForProfiles(self)
	Notifications:MakeSlashCmd("/notifications","/not")
	self:SetScript("OnTargetClick",function(i,module,arg1) if arg1 == "RightButton" then module:RemoveTarget(i) end end)
	self:SetScript("OnTimerClick",function(i,id,module,arg1) 
		if arg1 == "RightButton" then 
			module:RemoveTimer(i,id,"clicked")
		end
	end)
	self:SetScript("OnDragClick",function(arg1) 
		if arg1 == "LeftButton" then
			Notifications:Print("This is the |cff00ffffNotifications|r anchor.  Access |cff00ffffNotifications|r's menu by typing '|cff00ff00/not|r'.  Hide me by checking the '|cff00ff00Locked|r' checkbutton in the timer options menu.")
		end 
	end)
	self:SetScript("OnTimerEnter",function(i,id,module,this) 
		Notifications:CreateTimerTooltip(module:GetTarget(i),module:GetTimer(i,id),this) 
	end)
	local font = GameFontNormal:GetFont()
	NotificationsAlertFrameText:SetFont(font,50)
	local _,class = UnitClass("player")
	playerclass = class
	NotificationsTargetFrame:SetScript("OnUpdate",function() Notifications:CheckTarget(arg1) end)
	NotificationsTargetFrame.time = .5
	self:CreateTimerInstance()
	if DoTimer then
		self:Hook(DoTimer,"RemoveTimer","pre",function(self,i,id,reason)
			local timer = DoTimer:GetTimer(i,id)
			local target = DoTimer:GetTarget(i)
			if timer.module:TimerIsReal(timer) then
				local module = timer.module
				local prefix
				if module == DoTimer then
					prefix = "DoT"
				elseif module == Cooldowns then
					prefix = "Cooldown"
				else
					return
				end
				if reason == "broke" then
					if module == Cooldowns then return end
					Notifications:EventOccurred(prefix.." Break Early",timer.spell,target.target)				
				elseif reason == "finished" then
					local targetname = target.target
					if module == Cooldowns and timer.english == "Soulstone" then targetname = timer.rank end
					Notifications:EventOccurred(prefix.." Full Duration",timer.spell,targetname)
				end
			end
		end)
		self:Hook(DoTimer,"AddTimer","pre",function(self,t,d,suppress,module)
			if (not (d and d.type)) or d.timeadded then return end
			module = module or DoTimer
			if module:TimerIsReal(d.type) then
				local prefix
				if module == DoTimer then
					prefix = "DoT"
				elseif module == Cooldowns then
					prefix = "Cooldown"
				else
					return
				end
				if type(t) == "number" then t = DoTimer:GetTarget(t) end
				local target = t.target
				if module == Cooldowns and d.english == "Soulstone" then target = d.rank end
				Notifications:EventOccurred(prefix.." Begin Timer",d.spell,target)
			end
		end)
		self:Hook(DoTimer,"UpdateTimers","pre",function(self,elapsed)
			for i = 1,DoTimer:GetNumTargets() do
				for id = 1,DoTimer:GetNumTimers(i) do
					local timer = DoTimer:GetTimer(i,id)
					timer.prevdisp = timer.displayed
				end
			end
		end)
		self:Hook(DoTimer,"UpdateTimers","post",function(self,elapsed)
			for i = 1,DoTimer:GetNumTargets() do
				for id = 1,DoTimer:GetNumTimers(i) do
					local timer = DoTimer:GetTimer(i,id)
					if timer.module:TimerIsReal(timer) then
						local target = DoTimer:GetTarget(i)
						local disp = timer.displayed
						if disp and (not (disp == timer.prevdisp)) and math.floor(disp) == disp then
							local module = timer.module
							local prefix
							if module == DoTimer then
								prefix = "DoT"
							elseif module == Cooldowns then
								prefix = "Cooldown"
							else
								return
							end
							local targetname = target.target
							if module == Cooldowns and timer.english == "Soulstone" then targetname = timer.rank end
							Notifications:EventOccurred(prefix.." Time Remaining",timer.spell,targetname,disp + 1)
						end
					end
				end
			end		
		end)
	end
	if Cooldowns then
		self:Hook(Cooldowns,"RemoveTimer","pre",function(self,i,id,reason)
			local timer = Cooldowns:GetTimer(i,id)
			local target = Cooldowns:GetTarget(i)
			if timer.module:TimerIsReal(timer) then
				local module = timer.module
				if not (module == Cooldowns) then return end
				if reason == "finished" then
					local targetname = target.target
					if timer.english == "Soulstone" then targetname = timer.rank end
					Notifications:EventOccurred("Cooldown Full Duration",timer.spell,targetname)
				end
			end
		end)
		self:Hook(Cooldowns,"AddTimer","pre",function(self,t,d,suppress,module)
			if (not (d and d.type)) or d.timeadded then return end
			module = module or Cooldowns
			if module:TimerIsReal(d.type) then
				if not (module == Cooldowns) then return end
				if type(t) == "number" then t = module:GetTarget(t) end
				local target = t.target
				if d.english == "Soulstone" then target = d.rank end
				Notifications:EventOccurred("Cooldown Begin Timer",d.spell,target)
			end
		end)
		self:Hook(Cooldowns,"UpdateTimers","pre",function(self,elapsed)
			for i = 1,Cooldowns:GetNumTargets() do
				for id = 1,Cooldowns:GetNumTimers(i) do
					local timer = Cooldowns:GetTimer(i,id)
					timer.prevdisp = timer.displayed
				end
			end
		end)
		self:Hook(Cooldowns,"UpdateTimers","post",function(self,elapsed)
			for i = 1,Cooldowns:GetNumTargets() do
				for id = 1,Cooldowns:GetNumTimers(i) do
					local timer = Cooldowns:GetTimer(i,id)
					if timer.module:TimerIsReal(timer) then
						local target = Cooldowns:GetTarget(i)
						local disp = timer.displayed
						if disp and (not (disp == timer.prevdisp)) and math.floor(disp) == disp then
							local module = timer.module
							if not (module == Cooldowns) then return end
							local targetname = ""
							if timer.english == "Soulstone" then targetname = timer.rank end
							Notifications:EventOccurred("Cooldown Time Remaining",timer.spell,targetname,disp + 1)
						end
					end
				end
			end		
		end)
	end
	self:ToggleCombatRegX()
	NotificationsFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
end

function Notifications:CreateTimerTooltip(t,d,frame)
	if self:Get("tooltips") then
		GameTooltip:SetOwner(frame,"ANCHOR_RIGHT")
		GameTooltip:AddLine(d.spell,1,1,1)
		GameTooltip:AddLine(t.target,1,1,1)
		GameTooltip:AddLine("Right-click to remove.",1,1,1,1)
		GameTooltip:Show()
	end
end

function Notifications:ToggleCombatRegX()
	local regx = self:Get("combatregx")
	local locs = {
		CombatLogMenuChatTypeGroups,
		SpellLogMenuChatTypeGroups,
		SpellLogOtherMenuChatTypeGroups,
		PeriodicLogMenuChatTypeGroups,
	}
	for index,value in ipairs(locs) do
		for i2,v2 in ipairs(value) do
			if regx then
				NotificationsRegXFrame:RegisterEvent("CHAT_MSG_"..v2)
			else
				NotificationsRegXFrame:UnregisterEvent("CHAT_MSG_"..v2)
			end
		end
	end
end

function Notifications:OnCombatRegXEvent(event)
	if self:EventHasData("Combat Log") then
		local eventtable = self:Get("events","Combat Log")
		for index,value in pairs(eventtable) do
			local found,_,r1,r2,r3 = string.find(arg1,index)
			if found then self:SendEvents(value,"Combat Log",r1,r2,r3) end
		end
	end
end

function Notifications:Commands()
	self:ShowGUI()
end

function Notifications:ClearData()
	for index in pairs(currentinfo) do currentinfo[index] = nil end
	NotificationsMenuFrameInfo:SetText("")
	NotificationsDoneButton:Hide()
	NotificationsUsageSlider:Hide()
	NotificationsUsageSlider:SetValue(0)
	NotificationsTimeEditBox:Hide()
	NotificationsTimeEditBox:SetText("")
	NotificationsTriggerEditBox:Hide()
	NotificationsTriggerEditBox:SetText("")
	NotificationsFormatEditBox:Hide()
	NotificationsFormatEditBox:SetText("")
	NotificationsChatEditBox:Hide()
	NotificationsChatEditBox:SetText("")
	NotificationsSoundEditBox:Hide()
	NotificationsSoundEditBox:SetText("")
	NotificationsColorSwatch:Hide()
	NotificationsColorSwatchNormalTexture:SetVertexColor(1,1,1)
	NotificationsAlertLocSlider:Hide()
	NotificationsAlertLocSlider:SetValue(75)
	NotificationsStatEditBox:Hide()
	NotificationsStatEditBox:SetText("")
	NotificationsTimerEditBox:Hide()
	NotificationsTimerEditBox:SetText("")
	NotificationsPartialCheckButton:Hide()
	NotificationsPartialCheckButton:SetChecked(false)
end

function Notifications:OnEvent(event)
	if event == "PLAYER_ENTERING_WORLD" then self:Startup()
	elseif self:HasRegisteredSettings() and self:Get("status") then
		if event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
			local _,spell,target,damage
			--if crit, "Spell Crit Mob"
			--if resist/whatever, "Spell Failed on Mob"
			if self:EventHasData("Spell Crit Mob") or self:EventHasData("Spell Damage") then
				for index,value in pairs(critmsgs) do
					_,_,spell,target,damage = string.find(arg1,value)
					if spell and target then
						self:EventOccurred("Spell Crit Mob",spell,target,damage)
						self:EventOccurred("Spell Damage",spell,target,damage)
						return
					end
				end
				for index,value in pairs(hitmsgs) do
					_,_,spell,target,damage = string.find(arg1,value)
					if spell and target then
						self:EventOccurred("Spell Damage",spell,target,damage)
						return
					end
				end
			end
			if self:EventHasData("Spell Failed on Mob") then
				for index,value in pairs(failmsgs) do
					_,_,spell,target = string.find(arg1,value)
					if spell and target then
						self:EventOccurred("Spell Failed on Mob",spell,target,index)
						return
					end
				end
			end
		elseif event == "COMBAT_TEXT_UPDATE" then
			local event
			if arg1 == "AURA_START" then
				event = "Player Buff Gain"
			elseif arg1 == "AURA_START_HARMFUL" then
				event = "Player Debuff Gain"
				local type = GetPlayerBuffDispelType(arg2)
				if type then self:EventOccurred(event,type,UnitName("player")) end
			elseif arg1 == "AURA_END" then
				event = "Player Buff Fade"
			elseif arg1 == "AURA_END_HARMFUL" then
				event = "Player Debuff Fade"
			else
				return
			end
			self:EventOccurred(event,arg2,UnitName("player"))
		elseif event == "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS" then
			--"Enemy (Target) Buff Gain"
			local _,_,target,spell = string.find(arg1,enemygainsbuff)
			if spell then 
				local event
				if (target == UnitName("target") and UnitCanAttack("player","target")) then
					self:EventOccurred("Enemy Target Buff Gain",spell,target)
				end
				self:EventOccurred("Enemy Buff Gain",spell,target)
			end
		elseif event == "CHAT_MSG_SPELL_AURA_GONE_OTHER" then
			--"Enemy (Target) Buff/Debuff Fade"
			local _,_,spell,target = string.find(arg1,enemylosesbuff)
			if spell then 
				local event
				if (target == UnitName("target") and UnitCanAttack("player","target")) then
					self:EventOccurred("Enemy Target Buff/Debuff Fade",spell,target)
				end
				self:EventOccurred("Enemy Buff/Debuff Fade",spell,target)
			end
		elseif event == "CHAT_MSG_SPELL_SELF_BUFF" then
			--"Spell Crit Heal"
			if self:EventHasData("Spell Crit Heal") or self:EventHasData("Spell Heal") then
				local event
				local _,_,spell,target,damage = string.find(arg1,healcritother)
				if spell and target then
					self:EventOccurred("Spell Crit Heal",spell,target,damage)
					self:EventOccurred("Spell Heal",spell,target,damage)
					return
				end
				_,_,spell,damage = string.find(arg1,healcritself)
				if spell then
					self:EventOccurred("Spell Crit Heal",spell,UnitName("player"),damage)
					self:EventOccurred("Spell Heal",spell,target,damage)
					return
				end
				_,_,spell,target,damage = string.find(arg1,healhitother)
				if spell and target then
					self:EventOccurred("Spell Crit Heal",spell,target,damage)
					self:EventOccurred("Spell Heal",spell,target,damage)
					return
				end
				_,_,spell,damage = string.find(arg1,healhitself)
				if spell then
					self:EventOccurred("Spell Crit Heal",spell,UnitName("player"),damage)
					self:EventOccurred("Spell Heal",spell,UnitName("player"),damage)
					return
				end
			end
		elseif event == "CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE" or event == "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF" or event == "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE" then
			--"Enemy Begin Casting"
			if self:EventHasData("Enemy Begin Casting") then 
				local _,_,target,spell = string.find(arg1,spellcaststartother)
				if target and spell then
					self:EventOccurred("Enemy Begin Casting",spell,target)
				end
			end
		elseif event == "UNIT_SPELLCAST_START" and arg1 == "target" then
			if UnitCanAttack("player","target") then
				local spell = UnitCastingInfo("target")
				self:EventOccurred("Enemy Target Begin Casting",spell,UnitName("target"))
			end
		elseif event == "UNIT_HEALTH" and arg1 == "player" then
			local health = UnitHealth("player")
			prevhealth = prevhealth or UnitHealthMax("player")
			if self:EventHasData("Health") then
				local evententry = self:AcquireTable()
				local eventtable = self:Get("events","Health","all")
				local flag
				for index,value in ipairs(eventtable) do
					local stat = value["Stat Amount"]
					local dir = value["Stat Direction"]
					local ispercent = string.sub(dir,2,2)
					local dir = string.sub(dir,1,1)
					local actualhealth = health
					local actualprev = prevhealth
					if ispercent and not (ispercent == "") then
						local max = UnitHealthMax("player") / 100
						actualhealth = actualhealth / max
						actualprev = actualprev / max
					end
					if actualhealth < actualprev then
						if dir == "-" and (stat <= actualprev and stat >= actualhealth) then 
							table.insert(evententry,value) 
							flag = 1
						end
					elseif actualhealth > actualprev then
						if dir == "+" and (stat <= actualhealth and stat >= actualprev) then 
							table.insert(evententry,value) 
							flag = 1
						end
					end
				end
				prevhealth = health
				if flag then self:SendEvents(evententry,"Health","","",health) end
			end
			prevhealth = health
		elseif event == "UNIT_MANA" and arg1 == "player" then
			local mana = UnitMana("player")
			prevmana = prevmana or UnitManaMax("player")
			if self:EventHasData("Mana") then
				local evententry = self:AcquireTable()
				local eventtable = self:Get("events","Mana","all")
				local flag
				for index,value in ipairs(eventtable) do
					local stat = value["Stat Amount"]
					local dir = value["Stat Direction"]
					local ispercent = string.sub(dir,2,2)
					local dir = string.sub(dir,1,1)
					local actualmana = mana
					local actualprev = prevmana
					if ispercent and not (ispercent == "") then
						local max = UnitManaMax("player") / 100
						actualmana = actualmana / max
						actualprev = actualprev / max
					end
					if actualmana < actualprev then
						if dir == "-" and (stat <= actualprev and stat >= actualmana) then 
							table.insert(evententry,value) 
							flag = 1
						end
					elseif actualmana > actualprev then
						if dir == "+" and (stat <= actualmana and stat >= actualprev) then 
							table.insert(evententry,value) 
							flag = 1
						end
					end
				end
				prevmana = mana
				if flag then self:SendEvents(evententry,"Mana","","",mana) end
			end
			prevmana = mana
		elseif event == "PLAYER_TARGETS_CHANGED" then
			if UnitExists("targettarget") then
				prevstate = UnitIsUnit("player","targettarget")
			else
				prevstate = nil
			end
		else
			if not (arg1 == "player") then return end
			if string.find(event,"SENT") then
				spelltarget[arg2] = arg4
				if spelltarget[arg2] == "" then spelltarget[arg2] = UnitName("player") end
				if playerclass == "WARLOCK" and UnitExists("target") then
					local texture = self:FindSpellInfo(arg2,arg3,"spell")
					if texture == "Interface\\Icons\\Spell_Shadow_Twilight" then
						spelltarget[arg2] = UnitName("target")
					end
				end
			elseif string.find(event,"START") then
				--"Spell Begin Casting"
				local spell = UnitCastingInfo("player")
				self:EventOccurred("Spell Begin Casting",spell,spelltarget[spell] or UnitName("player"))
			elseif string.find(event,"SUCCEEDED") then
				--"Spell Cast/Item Use"
				local event
				local texture = self:FindSpellInfo(arg2,arg3,"spell")
				if texture then 
					event = "Spell Finish Casting"
				else
					texture = self:FindSpellInfo(arg2,arg3,"spell")
					if texture then 
						event = "Item Usage" 
					else 
						return 
					end
				end
				self:EventOccurred(event,arg2,spelltarget[arg2] or UnitName("player"))
			end
		end
	end
end

function Notifications:NewEvent(event,spell,usage,matching,type,info1,info2,info3,info4,info5,info6,info7,info8,info9,info10)
	if spell == "" then 
		self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid trigger)")
		return 
	end
	local evententry = {
		Type = type,
	}
	if type == "SCT" or type == "Echo" then
		if info1 == "" then 
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid message)")
			return 
		end
		evententry["Message"] = info1
		evententry["Color"] = info2
	elseif type == "Alert" then
		if info1 == "" then 
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid message)")
			return 
		end
		evententry["Message"] = info1
		evententry["Color"] = info2
		evententry["Offset"] = info5
	elseif type == "Sound" then
		if info3 == "" then 
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: no sound file specified)")
			return
		end
		evententry["Sound"] = info3
	elseif type == "Chat" then
		if info1 == "" then
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid message)")
			return
		end
		if info4 == "" then 
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: no chat specified)")
			return 
		end
		evententry["Message"] = info1
		evententry["Chat"] = info4
	elseif type == "Timer" then
		if info10 == "" then
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid timer info)")
			return
		end
		local target,spell,duration = self:ParseString(info10,"Target:%s?(.+) Spell:%s?(.+) Duration:%s?(.+)")
		if not( target and spell and duration) then
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: unable to parse timer info)")
			return
		end
		if target == "NONE" then target = "" end
		evententry["Target"] = target
		evententry["Spell"] = spell
		evententry["Duration"] = duration
	else
		self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid notification type)")
		return
	end
	evententry["Usage"] = usage
	if string.find(event,"Time Remaining") then 
		if not info6 then 
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid time)")
			return 
		end
		evententry["Time"] = info6 
	end
	if event == "Health" or event == "Mana" then
		if not info8 then 
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid stat amount)")
			return 
		end
		local dir = string.sub(info9,1,1)
		if not (dir == "+" or dir == "-") then 
			self:Print("|cff00ffffNotifications|r: New event failed to be created. (Reason: invalid stat direction)")
			return 
		end
		evententry["Stat Amount"] = info8
		evententry["Stat Direction"] = info9
	end
	if usage == "Random" then
		self:Set("events",event,spell,"Percent",info7)
	end
	if (not (spell == "all")) and (not (event == "Combat Log")) then
		self:Set("events",event,spell,"Matching",matching)
	end
	self:Set("events",event,spell,"+",evententry)
	self:Print("|cff00ffffNotifications|r: New event created successfully!")
	self:ClearData()
end

function Notifications:EventHasData(event)
	return self:Get("events",event) and true or false
end

function Notifications:EventOccurred(event,spell,target,damage)
	local evententry
	local eventtable = self:Get("events",event)
	if eventtable then
		for index,value in pairs(eventtable) do
			if not (index == "all") and ((not value.Matching) or value.Matching == "Exact") then
				if string.lower(index) == string.lower(spell) then
					evententry = value
				end
			end
		end
		if not evententry then
			for index,value in pairs(eventtable) do
				if not (index == "all") and value.Matching == "Partial" then
					if string.find(string.lower(spell),string.lower(index)) then 
						evententry = value
						break
					end
				end
			end
		end
		if not evententry then evententry = eventtable["all"] end
		if evententry then self:SendEvents(evententry,event,spell,target,damage) end
	end
end

function Notifications:SendEvents(evententry,event,spell,target,damage)
	if evententry then
		local randomentries = self:AcquireTable()
		for index,value in ipairs(evententry) do
			if (not string.find(event,"Time Remaining")) or (value["Time"] == damage) then
				if value["Usage"] == "All" then
					self:SendEvent(value,spell,target,damage)
				else
					table.insert(randomentries,value)
				end
			end
		end
		local numrandom = table.getn(randomentries)
		if numrandom > 0 then
			local percent = evententry["Percent"]
			if not percent then 
				percent = 100
				evententry["Percent"] = 100 
			end
			percent = percent / 100
			if math.random() > percent then return end
			local index = math.random(1,numrandom)
			self:SendEvent(randomentries[index],spell,target,damage)
		end
	end
end

function Notifications:SendEvent(event,spell,target,damage)
	if event.Type == "SCT" then
		local msg = self:SubInVars(event["Message"],spell,target,damage)
		if SCT then 
			SCT:DisplayText(msg,event["Color"],nil,nil,1) 
		elseif MikSBT then
			local color = event["Color"]
			MikSBT.DisplayMessage(msg,nil,nil,(color.r * 255),(color.g * 255),(color.b * 255))
		elseif IsAddOnLoaded("Blizzard_CombatText") then
			local color = event["Color"]
			CombatText_AddMessage(msg,COMBAT_TEXT_SCROLL_FUNCTION,color.r,color.g,color.b)
		end
	elseif event.Type == "Sound" then
		PlaySoundFile("Interface\\AddOns\\DoTimer_Package\\Ash_Core\\Files\\"..event["Sound"])
	elseif event.Type == "Alert" then
		local msg = self:SubInVars(event["Message"],spell,target,damage)
		local frame = NotificationsAlertFrame
		local anchor = NotificationsAnchorFrame
		local frametext = NotificationsAlertFrameText
		frame:Hide()
		frame:Show()
		anchor:ClearAllPoints()
		anchor:SetPoint("CENTER","UIParent","CENTER",0,event["Offset"])
		frametext:SetText(msg)
		frametext:SetTextColor(event["Color"].r,event["Color"].g,event["Color"].b)
	elseif event.Type == "Echo" then
		local msg = self:SubInVars(event["Message"],spell,target,damage)
		if DEFAULT_CHAT_FRAME then self:ColorPrint(event["Color"].r,event["Color"].g,event["Color"].b,msg) end
	elseif event.Type == "Chat" then
		local chat = event["Chat"]
		chat = string.lower(chat)
		local msg = self:SubInVars(event["Message"],spell,target,damage)
		if type(tonumber(chat)) == "number" then
			chat = tonumber(chat)
			local id,name = GetChannelName(chat)
			if id > 0 then
				SendChatMessage(msg,"CHANNEL",nil,id)
				return
			else
				chat = "auto"
			end
		end
		if chat == "auto" then
			if GetNumRaidMembers() > 0 then chat = "raid" elseif GetNumPartyMembers() > 0 then chat = "party" else return end
		end
		if chat == "whisper" then
			if target then SendChatMessage(msg,chat,nil,target) end
		else
			SendChatMessage(msg,chat)
		end
	elseif event.Type == "Timer" then
		local target = self:SubInVars(event["Target"],spell,target,damage)
		local timername = self:SubInVars(event["Spell"],spell,target,damage)
		local duration = self:TimeToNum(Notifications:SubInVars(event["Duration"],spell,target,damage))
		local targettable = {target = target, norepeat = 1}
		local timertable = {spell = timername, duration = duration}
		self:AddTimer(targettable,timertable)
	end
end

function Notifications:SubInVars(str,spell,target,damage)
	return string.gsub(str,"(%%%a)",function(a) if a == "%s" then return spell elseif a == "%t" then return target elseif a == "%d" then return damage else return a end end)
end

function Notifications:CheckTarget(elapsed)
	NotificationsTargetFrame.time = NotificationsTargetFrame.time - elapsed
	if NotificationsTargetFrame.time <= 0 then
		NotificationsTargetFrame.time = .5
		if UnitExists("targettarget") and UnitCanAttack("player","target") then
			if prevstate then
				if prevstate == "aggro" then 
					if not UnitIsUnit("player","targettarget") then --aggro loss
						self:EventOccurred("Aggro Loss","",UnitName("target"))
					end
				elseif prevstate == "no aggro" then
					if UnitIsUnit("player","targettarget") then --aggro gain
						self:EventOccurred("Aggro Gain","",UnitName("target"))
					end
				end
			end
			prevstate = UnitIsUnit("player","targettarget") and "aggro" or "no aggro"
		else
			prevstate = nil
		end
	end
end

function Notifications:DropDownManage()
	local info
	local DROPDOWNLIB_MENU_LEVEL = DropDownLib:MenuLevel()
	local DROPDOWNLIB_MENU_VALUE = DropDownLib:MenuValue()
	if DROPDOWNLIB_MENU_LEVEL == 6 then
		local types = self:AcquireTable()
		if DROPDOWNLIB_MENU_VALUE[1] == "Type" then
			table.insert(types,"SCT")
			table.insert(types,"Echo")
		elseif DROPDOWNLIB_MENU_VALUE[1] == "Usage" then
			table.insert(types,"All")
			table.insert(types,"Random")
		elseif DROPDOWNLIB_MENU_VALUE[1] == "Stat Direction" then
			table.insert(types,"+")
			table.insert(types,"-")
			table.insert(types,"+%")
			table.insert(types,"-%")
		end
		for index,value in ipairs(types) do
			info = DropDownLib:GetTable()
			info.text = value
			local checked
			if DROPDOWNLIB_MENU_VALUE[2] == value then checked = 1 end
			info.checked = checked
			info.arg1 = DROPDOWNLIB_MENU_VALUE[3]
			info.arg2 = DROPDOWNLIB_MENU_VALUE[1]
			info.func = function(arg1,arg2)
				Notifications:Set(arg1,arg2,value)
				DropDownLib:CloseDropDownMenus()
			end
			DropDownLib:AddButton(info,6)	
		end
	elseif DROPDOWNLIB_MENU_LEVEL == 5 then
		if DROPDOWNLIB_MENU_VALUE[1] then
			if type(DROPDOWNLIB_MENU_VALUE[2]) == "table" then
				local value = DROPDOWNLIB_MENU_VALUE[1]
				local currenttable = DROPDOWNLIB_MENU_VALUE[2]
				local newmatchings = {"Partial","Exact"}
				for index2,value2 in ipairs(newmatchings) do
					info = DropDownLib:GetTable()
					info.text = value2
					local checked
					if value == value2 then checked = 1 end
					info.checked = checked
					info.func = function()
						Notifications:Set(currenttable,"Matching",value2)
						DropDownLib:CloseDropDownMenus()
					end
					DropDownLib:AddButton(info,5)
				end
			else
				self:SetInfo("event",DROPDOWNLIB_MENU_VALUE[1])
				self:SetInfo("spell",DROPDOWNLIB_MENU_VALUE[2])
				self:SetInfo("matching",DROPDOWNLIB_MENU_VALUE[3])
				self:AddTypes(5)
			end
		else
			for index,value in pairs(DROPDOWNLIB_MENU_VALUE) do
				info = DropDownLib:GetTable()
				info.text = index
				info.isTitle = 1
				info.notCheckable = 1
				DropDownLib:AddButton(info,5)
				info = DropDownLib:GetTable()
				if index == "Type" then
					info = DropDownLib:GetTable()
					if (value == "Echo" or value == "SCT") then
						info.hasArrow = 1
						info.textR = .2
						info.textG = 1
						info.textB = 1
					else
						info.notClickable = 1
					end
					info.value = {index,value,DROPDOWNLIB_MENU_VALUE}
					info.notCheckable = 1
					info.text = value
				elseif index == "Color" then
					info.text = "Change me:"
					info.r = value.r
					info.g = value.g
					info.b = value.b
					info.value = value
					info.hasColorSwatch = 1
					info.notCheckable = 1
					info.func = function() DropDownLib:OpenColorPicker() end
					info.swatchFunc = function()
						local r,g,b = DropDownLibColorPicker:GetColorRGB()
						Notifications:Set(DROPDOWNLIB_MENU_VALUE,"r",r)
						Notifications:Set(DROPDOWNLIB_MENU_VALUE,"g",g)
						Notifications:Set(DROPDOWNLIB_MENU_VALUE,"b",b)
					end
					info.cancelFunc = function(prevValues)  
						Notifications:Set(DROPDOWNLIB_MENU_VALUE,"r",prevValues.r)
						Notifications:Set(DROPDOWNLIB_MENU_VALUE,"g",prevValues.g)
						Notifications:Set(DROPDOWNLIB_MENU_VALUE,"b",prevValues.b)
					end
				elseif index == "Usage" then
					info.text = value
					info.value = {index,value,DROPDOWNLIB_MENU_VALUE}
					info.notCheckable = 1
					info.hasArrow = 1
					info.textR = .2
					info.textG = 1
					info.textB = .2
				elseif index == "Stat Direction" then
					info.text = value
					info.value = {index,value,DROPDOWNLIB_MENU_VALUE}
					info.notCheckable = 1
					info.hasArrow = 1
					info.textR = 1
					info.textG = 1
					info.textB = .2
				elseif index == "Time" then
					info.text = self:NumToTime(value)
					info.notClickable = 1
					info.notCheckable = 1
				else
					info.text = value
					info.notClickable = 1
					info.notCheckable = 1
				end
				DropDownLib:AddButton(info,5)
			end
			info = DropDownLib:GetTable()
			info.text = ""
			info.disabled = 1
			DropDownLib:AddButton(info,5)
			info = DropDownLib:GetTable()
			info.text = "Remove This Entry"
			info.arg1 = DROPDOWNLIB_MENU_VALUE
			info.notCheckable = 1
			info.textR = 1
			info.textG = .3
			info.textB = .3
			info.func = function(arg1)
				for index,value in pairs(Notifications:Get("events")) do
					for index2,value2 in pairs(value) do
						for index3,value3 in ipairs(value2) do
							if value3 == arg1 then
								Notifications:Set("events",index,index2,"-",index3)
								if table.getn(value2) == 0 then
									Notifications:Set("events",index,index2,nil)
								end
								if not Notifications:EventHasData(index) then
									Notifications:Set("events",index,nil)
								end
								DropDownLib:CloseDropDownMenus()
								return
							end
						end
					end
				end
			end
			DropDownLib:AddButton(info,5)
		end
	elseif DROPDOWNLIB_MENU_LEVEL == 4 then
		for index,value in ipairs(DROPDOWNLIB_MENU_VALUE) do
			info = DropDownLib:GetTable()
			info.text = "Entry "..index
			info.value = value
			info.hasArrow = 1
			info.notCheckable = 1
			DropDownLib:AddButton(info,4)
		end	
		if DROPDOWNLIB_MENU_VALUE.Matching then
			info = DropDownLib:GetTable()
			info.text = "Matching"
			info.isTitle = 1
			info.notCheckable = 1
			DropDownLib:AddButton(info,4)
			info = DropDownLib:GetTable()
			info.text = DROPDOWNLIB_MENU_VALUE.Matching
			info.value = {DROPDOWNLIB_MENU_VALUE.Matching,DROPDOWNLIB_MENU_VALUE}
			info.notCheckable = 1
			info.hasArrow = 1
			info.textR = .2
			info.textG = 1
			info.textB = .2
			DropDownLib:AddButton(info,4)
		end
		if DROPDOWNLIB_MENU_VALUE.Percent then
			info = DropDownLib:GetTable()
			info.text = "Percent"
			info.isTitle = 1
			info.notCheckable = 1
			DropDownLib:AddButton(info,4)
			info = DropDownLib:GetTable()
			info.text = DROPDOWNLIB_MENU_VALUE.Percent
			info.notCheckable = 1
			info.notClickable = 1
			DropDownLib:AddButton(info,4)
		end
		info = DropDownLib:GetTable()
		info.text = ""
		info.disabled = 1
		DropDownLib:AddButton(info,4)
		info = DropDownLib:GetTable()
		info.text = "Add New Entry"
		local event,spell
		for index,value in pairs(self:Get("events")) do
			if type(value) == "table" then
				for index2,value2 in pairs(value) do
					if value2 == DROPDOWNLIB_MENU_VALUE then
						event = index
						spell = index2
					end
				end
			end
		end
		info.value = {event,spell,DROPDOWNLIB_MENU_VALUE["Matching"]}
		info.notCheckable = 1
		info.textR = .2
		info.textG = 1
		info.textB = 1
		info.hasArrow = 1
		DropDownLib:AddButton(info,4)
		info = DropDownLib:GetTable()
		info.text = "Remove These Entries"
		info.arg1 = DROPDOWNLIB_MENU_VALUE
		info.notCheckable = 1
		info.textR = 1
		info.textG = .3
		info.textB = .3
		info.func = function(arg1)
			for index,value in pairs(Notifications:Get("events")) do
				if type(value) == "table" then
					for index2,value2 in pairs(value) do
						if value2 == arg1 then
							Notifications:Set("events",index,index2,nil)
							DropDownLib:CloseDropDownMenus()
							if not Notifications:EventHasData(index) then
								Notifications:Set("events",index,nil)
							end
							return
						end
					end
				end
			end
		end
		DropDownLib:AddButton(info,4)
	elseif DROPDOWNLIB_MENU_LEVEL == 3 then
		for index,value in pairs(DROPDOWNLIB_MENU_VALUE) do
			info = DropDownLib:GetTable()
			info.text = index
			info.value = value
			info.hasArrow = 1
			info.notCheckable = 1
			DropDownLib:AddButton(info,3)
			info = DropDownLib:GetTable()
		end
		info = DropDownLib:GetTable()
		info.text = ""
		info.disabled = 1
		DropDownLib:AddButton(info,3)
		info = DropDownLib:GetTable()
		info.text = "Remove All Entries"
		info.arg1 = DROPDOWNLIB_MENU_VALUE
		info.notCheckable = 1
		info.textR = 1
		info.textG = .3
		info.textB = .3
		info.func = function(arg1)
			for index,value in pairs(Notifications:Get("events")) do
				if value == arg1 then
					Notifications:Set("events",index,nil)
					DropDownLib:CloseDropDownMenus()
					return
				end
			end
		end
		DropDownLib:AddButton(info,3)
	elseif DROPDOWNLIB_MENU_LEVEL == 2 then
		info = DropDownLib:GetTable()
		info.text = "List of Events:"
		info.isTitle = 1
		info.notCheckable = 1
		DropDownLib:AddButton(info,2)
		for _,subset in ipairs(orgeventlist) do
			for k,v in ipairs(subset) do
				local index = v
				local value = Notifications:Get("events",index)
				if value then
					if Notifications:EventHasData(index) then
						info = DropDownLib:GetTable()
						info.text = index
						info.value = value
						info.hasArrow = 1
						info.notCheckable = 1
						DropDownLib:AddButton(info,2)
					end
				end
			end
		end
		info = DropDownLib:GetTable()
		info.text = ""
		info.disabled = 1
		DropDownLib:AddButton(info,2)
		info = DropDownLib:GetTable()
		info.text = "Delete All Entries"
		info.notCheckable = 1
		info.textR = 1
		info.textG = .3
		info.textB = .3
		info.func = function()
			for index,value in pairs(Notifications:Get("events")) do
				Notifications:Set("events",index,nil)
			end
			DropDownLib:CloseDropDownMenus()
		end
		DropDownLib:AddButton(info,2)
	end
end

function Notifications:DropDownCreate()
	local info
	local DROPDOWNLIB_MENU_LEVEL = DropDownLib:MenuLevel()
	local DROPDOWNLIB_MENU_VALUE = DropDownLib:MenuValue()
	if DROPDOWNLIB_MENU_LEVEL == 7 then
		self:SetInfo("spell",DROPDOWNLIB_MENU_VALUE)
		self:AddTypes(7)
	elseif DROPDOWNLIB_MENU_LEVEL == 6 then
		local entries = self:AcquireTable()
		if string.sub(DROPDOWNLIB_MENU_VALUE,1,5) == "spell" then
			local tab = string.sub(DROPDOWNLIB_MENU_VALUE,6)
			for i = 1,GetNumSpellTabs() do
				local name,_,offset,numspells = GetSpellTabInfo(i)
				if name == tab then
					for id = offset + 1,offset + numspells do
						local spell = GetSpellName(id,BOOKTYPE_SPELL)
						entries[spell] = 1
					end
					break
				end
			end
		elseif string.sub(DROPDOWNLIB_MENU_VALUE,1,4) == "item" then
			local itemloc = string.sub(DROPDOWNLIB_MENU_VALUE,5)
			if itemloc == "Inventory" then
				for i = 1,19 do
					local name = GetItemInfo(GetInventoryItemLink("player",i) or "")
					if name then
						entries[name] = 1
					end
				end
			else
				local _,bagid
				if itemloc == "Backpack" then
					bagid = 0
				else
					_,_,bagid = string.find(itemloc,"(%d)")
				end
				for i = 1,GetContainerNumSlots(bagid) do
					local name = GetItemInfo(GetContainerItemLink(bagid,i) or "")
					if name then
						entries[name] = 1
					end	
				end
			end
		end
		entries = self:Sort(entries)
		for index,value in ipairs(entries) do
			info = DropDownLib:GetTable()
			info.hasArrow = 1
			info.value = value
			info.notCheckable = 1
			info.text = value	
			DropDownLib:AddButton(info,6)
		end
	elseif DROPDOWNLIB_MENU_LEVEL == 5 then
		if DROPDOWNLIB_MENU_VALUE == "all" then
			self:SetInfo("spell","all")
			self:AddTypes(5)
		elseif DROPDOWNLIB_MENU_VALUE == "other" then
			self:SetInfo("spell","other")
			self:AddTypes(5)
		else
			local nextentries
			if DROPDOWNLIB_MENU_VALUE == "spell" then
				nextentries = self:AcquireTable()
				for i = 1,GetNumSpellTabs() do
					local name = GetSpellTabInfo(i)
					table.insert(nextentries,name)
				end
			elseif DROPDOWNLIB_MENU_VALUE == "item" then
				nextentries = {"Inventory","Backpack","Bag 1","Bag 2","Bag 3","Bag 4"}
			end
			for index,value in ipairs(nextentries) do
				info = DropDownLib:GetTable()
				info.text = value
				info.value = DROPDOWNLIB_MENU_VALUE..value
				info.hasArrow = 1
				info.notCheckable = 1
				DropDownLib:AddButton(info,5)
			end
		end
	elseif DROPDOWNLIB_MENU_LEVEL == 4 then
		self:SetInfo("event",DROPDOWNLIB_MENU_VALUE)
		if specialevents[DROPDOWNLIB_MENU_VALUE] or miscevents[DROPDOWNLIB_MENU_VALUE] then
			self:AddTypes(4)
		else
			info = DropDownLib:GetTable()
			info.text = "Choose a Trigger:"
			info.isTitle = 1
			info.notCheckable = 1
			DropDownLib:AddButton(info,4)
			info = DropDownLib:GetTable()
			info.text = "all"
			info.value = "all"
			info.hasArrow = 1
			info.notCheckable = 1
			DropDownLib:AddButton(info,4)
			if not (string.sub(DROPDOWNLIB_MENU_VALUE,1,4) == "Item") then
				info = DropDownLib:GetTable()
				info.text = "Spell"
				info.value = "spell"
				info.hasArrow = 1
				info.notCheckable = 1
				DropDownLib:AddButton(info,4)
			end
			if not ((string.sub(DROPDOWNLIB_MENU_VALUE,1,3) == "DoT") or (string.sub(DROPDOWNLIB_MENU_VALUE,1,5) == "Spell")) then
				info = DropDownLib:GetTable()
				info.text = "Item"
				info.value = "item"
				info.hasArrow = 1
				info.notCheckable = 1
				DropDownLib:AddButton(info,4)
			end
			info = DropDownLib:GetTable()
			info.text = "Other..."
			info.value = "other"
			info.tooltipTitle = "Note"
			info.tooltipText = "Pick this option if you cannot find the trigger you want, or if you want to set a partial match."
			info.hasArrow = 1
			info.notCheckable = 1
			DropDownLib:AddButton(info,4)
		end
	elseif DROPDOWNLIB_MENU_LEVEL == 3 then
		info = DropDownLib:GetTable()
		info.text = "Choose an Event:"
		info.isTitle = 1
		info.notCheckable = 1
		DropDownLib:AddButton(info,3)
		for k,v in ipairs(orgeventlist[DROPDOWNLIB_MENU_VALUE]) do
			local index = v
			info = DropDownLib:GetTable()
			info.text = index
			info.value = index
			info.hasArrow = 1
			info.notCheckable = 1
			info.tooltipTitle = "Info"
			info.tooltipText = regevents[index] or specialevents[index] or miscevents[index]
			DropDownLib:AddButton(info,3)
		end
	elseif DROPDOWNLIB_MENU_LEVEL == 2 then
		info = DropDownLib:GetTable()
		info.text = "Pick a Subset:"
		info.isTitle = 1
		info.notCheckable = 1
		DropDownLib:AddButton(info,2)
		for k,v in ipairs(orgeventlist) do
			local index = v.name
			info = DropDownLib:GetTable()
			info.text = index
			info.value = k
			info.hasArrow = 1
			info.notCheckable = 1
			info.tooltipTitle = "Info"
			info.tooltipText = v.tooltip
			DropDownLib:AddButton(info,2)
		end
	end
end

local sorttable = {}
function Notifications:Sort(pretable)
	for index,value in pairs(sorttable) do sorttable[index] = nil end
	for index,value in pairs(pretable) do table.insert(sorttable,index) end
	table.sort(sorttable)
	return sorttable
end

function Notifications:AddTypes(level)
	local info
	info = DropDownLib:GetTable()
	info.text = "Choose a Type:"
	info.isTitle = 1
	info.notCheckable = 1
	DropDownLib:AddButton(info,level)
	local types = {
		["SCT"] = "Send a message through Scrolling Combat Text, or Mik's Scrolling Battle Text, or Blizzard Floating Combat Text (make sure you have it enabled in Interface Options!) if SCT and MikSBT are not installed.",
		["Echo"] = "Create a message in your chat box only you can see.",
		["Sound"] = "Play a sound file.",
		["Alert"] = "Create a large message in the middle of the screen.",
		["Chat"] = "Send a message to others.",
		["Timer"] = "Make a timer appear.",
	}
	for index,value in pairs(types) do
		info = DropDownLib:GetTable()
		info.text = index
		info.value = index
		info.notCheckable = 1
		info.arg1 = index
		info.tooltipTitle = index
		info.tooltipText = value
		info.func = function(arg1) Notifications:SetInfo("Type",arg1) DropDownLib:CloseDropDownMenus() end
		DropDownLib:AddButton(info,level)
	end
end

function Notifications:SetInfo(type,info)
	currentinfo[type] = info
	if type == "Type" then
		local msg = string.format("Current Config: \nEvent: |cff00ff00%s|r \nType: |cff00ff00%s|r",currentinfo.event,currentinfo.Type)
		if currentinfo.spell and (not (currentinfo.spell == "other")) then
			NotificationsTriggerEditBox:SetText(currentinfo.spell)
		end
		NotificationsTriggerEditBox:Show()
		if string.find(currentinfo.event,"Time Remaining") then NotificationsTimeEditBox:Show() end
		if miscevents[currentinfo.event] then
			NotificationsTriggerEditBox:SetText("all")
			NotificationsTriggerEditBox:Hide()
			currentinfo.spell = "all"
			if not string.find(currentinfo.event,"Aggro") then
				NotificationsStatEditBox:Show()
			end
		end
		if ((not currentinfo.spell) or (currentinfo.spell == "other")) and (not (currentinfo.event == "Combat Log")) then NotificationsPartialCheckButton:Show() else NotificationsPartialCheckButton:Hide() end
		NotificationsMenuFrameInfo:SetText(msg)
		NotificationsUsageSlider:Show()
		NotificationsDoneButton:Show()
		if currentinfo.matching == "Partial" then NotificationsPartialCheckButton:SetChecked(true) end
		if info == "SCT" or info == "Echo" then
			NotificationsFormatEditBox:Show()
			NotificationsColorSwatch:Show()
		elseif info == "Alert" then
			NotificationsAlertLocSlider:Show()
			NotificationsFormatEditBox:Show()
			NotificationsColorSwatch:Show()
		elseif info == "Sound" then
			NotificationsSoundEditBox:Show()
		elseif info == "Chat" then
			NotificationsFormatEditBox:Show()
			NotificationsChatEditBox:Show()
		elseif info == "Timer" then
			NotificationsTimerEditBox:Show()
		end
	end
end

function Notifications:ParseMenu()
	if currentinfo.Type then
		local event = currentinfo.event
		local spell = NotificationsTriggerEditBox:GetText()
		local type = currentinfo.Type
		local usage
		local value = NotificationsUsageSlider:GetValue()
		if value == 0 then usage = "All" else usage = "Random" end
		local formatmsg = NotificationsFormatEditBox:GetText()
		local r,g,b = NotificationsColorSwatchNormalTexture:GetVertexColor()
		local color = {r = r, g = g, b = b}
		local chat = NotificationsChatEditBox:GetText()
		local sound = NotificationsSoundEditBox:GetText()
		local matching = NotificationsPartialCheckButton:GetChecked() and "Partial" or "Exact"
		local offset = NotificationsAlertLocSlider:GetValue()
		local time = NotificationsTimeEditBox:GetText()
		time = Notifications:TimeToNum(time)
		local stat = NotificationsStatEditBox:GetText()
		local statamount = self:ParseString(stat,"(%d+)")
		local statdir = string.sub(stat,1,1)
		local percent = string.sub(stat,-1,-1)
		if percent == "%" then statdir = statdir..percent end
		local timerinfo = NotificationsTimerEditBox:GetText()
		self:NewEvent(event,spell,usage,matching,type,formatmsg,color,sound,chat,offset,time,value,statamount,statdir,timerinfo)
	end
end

function Notifications:GetCurrent(val)
	return currentinfo[val]
end

local protected = {}
local f = CreateFrame("Frame")
f.buffer = 0
f:SetScript("OnUpdate",function(self,elapsed)
	self.buffer = self.buffer + elapsed
	for i,v in pairs(protected) do
		protected[i] = protected[i] - elapsed
		if protected[i] <= 0 then protected[i] = nil end
	end
	if self.buffer >= .15 then
		self.buffer = 0
		local i = 1
		local buff = GetPlayerBuff(i,"HELPFUL")
		while buff > 0 do
			local name = GetPlayerBuffName(buff)
			local timeleft = GetPlayerBuffTimeLeft(buff)
			local floortime = math.floor(timeleft)
			if timeleft <= floortime + .1 then
				if not protected[buff] then
					protected[buff] = .15
					Notifications:EventOccurred("Player Buff Time Remaining",name,nil,floortime)
				end
			end
			i = i + 1
			buff = GetPlayerBuff(i,"HELPFUL")
		end
		i = 1
		local debuff = GetPlayerBuff(i,"HARMFUL")
		while debuff > 0 do
			local name = GetPlayerBuffName(debuff)
			local timeleft = GetPlayerBuffTimeLeft(debuff)
			local floortime = math.floor(timeleft)
			if timeleft <= floortime + .1 then
				if not protected[debuff] then
					protected[debuff] = .15
					Notifications:EventOccurred("Player Debuff Time Remaining",name,nil,floortime)
				end
			end
			i = i + 1
			debuff = GetPlayerBuff(i,"HARMFUL")
		end
	end
end)

defaultsettings = {
	status = true,
	combatregx = false,
	events = {},
	locked = true,
	hideall = false,
	hidden = {},
	raidicons = false,
	sorttarget = false,
	onlytarget = false,
	tooltips = true,
}
