function EventAlert_OnLoad(self)
	self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
    self:RegisterEvent("COMBAT_TEXT_UPDATE");
	self:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_SHOW");

    self:RegisterEvent("PLAYER_LOGIN");
    self:RegisterEvent("PLAYER_ENTERING_WORLD");
    self:RegisterEvent("PLAYER_DEAD");
    self:RegisterEvent("ADDON_LOADED");

    SlashCmdList["EVENTALERT"] = EventAlert_SlashHandler;
    SLASH_EVENTALERT1 = "/eventalert";
    SLASH_EVENTALERT2 = "/ea";
end


function EventAlert_OnEvent(self, event, ...)

	if (event == "ADDON_LOADED") then
        local arg1 = ...;
        if (arg1 == "EventAlert") then
	        EventAlert_LoadSpellArrays();
        	EventAlert_LoadVariables();
	        EventAlert_CreateOptionsPanels();

	       -- Create Actual Alert Frames
			EventAlert_CreateAnchorIcons();
	        EventAlert_CreateAlertIcons(EA_Items[EA_playerClass]);
	        EventAlert_CreateAlertIcons(EA_AltItems[EA_playerClass]);
			EventAlert_CreateAlertIcons(EA_StackingItems[EA_playerClass]);
	        EventAlert_CreateAlertIcons(EA_CustomItems[EA_playerClass]);
        end
    end
    -- This block has grown to be the main handler of fading debuffs, especially stackable buffs.
    if #EA_TempBuffsTable ~= 0 then
        for i,v in ipairs (EA_TempBuffsTable) do
				local check_name,_ = GetSpellInfo(v);

				_, _, _, stack, _, _, _, _, _, _, check_spellId = UnitBuff("player", check_name);

				if (check_spellId == nil) then
					_, _, _, stack, _, _, _, _, _, _, check_spellId = UnitDebuff("player", check_name);
				end
				
				if (stack ~= nil) then
					-- If a custom spell has stacks, converts it to a StackingItem.
					if (stack > 0 and EA_StackingItems[EA_playerClass][v] == nil and EA_CustomItems[EA_playerClass][v] == true) then
						EA_CustomItems[EA_playerClass][v] = nil;
						EA_StackingItems[EA_playerClass][v] = true;
						EA_StackingItemsCounts[EA_playerClass][v] = 1;
						print("The custom spell, "..check_name..", has been added to the list of stacking buffs. Reload UI to adjust stack size from the interface menu.");
					end
				end

				if (check_spellId == nil) then
					if (v ~= EA_powerAlert and not (EA_AltItems[EA_playerClass][v])) then
						local v2 = table.foreach(EA_TempBuffsTable, function(i2, v2) if v2==v then return v2 end end)
						if v2 then
							EA_removeBuffValue(v2);
						end
					end
				end			
		end
    end
	-- End Check

    -- Monitor Holy Power, Shadow Orbs, Warlock Powers, Monk Chi and Combo Points

	if (EA_playerClass == EA_CLASS_MONK or EA_playerClass == EA_CLASS_PALADIN or EA_playerClass == EA_CLASS_ROGUE or EA_playerClass == EA_CLASS_DRUID or EA_playerClass == EA_CLASS_PRIEST or EA_playerClass == EA_CLASS_WARLOCK) then

    	if EA_doPower == nil then EA_doPower = 0 end;

        if (EA_playerClass == EA_CLASS_PALADIN) then
	        EA_powerAlert = 85247;
			EA_powerValue = UnitPower("player", 9);
		elseif (EA_playerClass == EA_CLASS_PRIEST) then
			EA_powerAlert = 77487;
			EA_powerValue = UnitPower("player", 13);
		elseif (EA_playerClass == EA_CLASS_MONK) then
			EA_powerAlert = 97272;
			EA_powerValue = UnitPower("player", 12);
		-- Warlock class ressources.
		elseif (EA_playerClass == EA_CLASS_WARLOCK) then
			-- Default Values to avoid lua errors on startup.
			EA_powerAlert = 87388;
			EA_powerValue = UnitPower("player", 7);
			if (GetSpecialization() == 1) then
				EA_powerAlert = 87388;
				EA_powerValue = UnitPower("player", 7);
			elseif (GetSpecialization() == 2) then
				EA_powerAlert = 104314;
				EA_powerValue = UnitPower("player", 15);
			elseif (GetSpecialization() == 3) then
				EA_powerAlert = 108647;
				EA_powerValue = UnitPower("player", 14);	
			end
        else
	        EA_powerAlert = 64385;
            EA_powerValue = GetComboPoints("player", "target");
        end


        if (EA_StackingItems[EA_playerClass][EA_powerAlert]) then
        	if (EA_powerValue >= EA_StackingItemsCounts[EA_playerClass][EA_powerAlert] and EA_powerValue >= 0) then
		        if (EA_doPower == 0) then
			        EA_addBuffValue(EA_powerAlert);
		    	    EA_doPower = 1;
		        end
		    end
		end

	    if (EA_powerValue < EA_StackingItemsCounts[EA_playerClass][EA_powerAlert]) then
	    	if (EA_doPower == 1) then
	            EA_removeBuffValue(EA_powerAlert);
	    	    EA_doPower = 0;
	        end
	    end
    end


    if (event == "COMBAT_LOG_EVENT_UNFILTERED") then

		local EA_eventType = select(2, ...);
        local EA_arg9 = select(9, ...);
        local EA_arg12 = select(12, ...);
        local EA_arg13 = select(13, ...);
        local EA_arg16 = select(16, ...);

        if (EA_Config.Debug == true) then
            if (EA_arg9 == UnitName("player")) then
            	if (EA_arg13 ~= nil) then
	        		DEFAULT_CHAT_FRAME:AddMessage(""..EA_eventType.."  Name: "..EA_arg13.."  ID: "..EA_arg12);
	            end
           	end
        end

        if (EA_eventType == "SPELL_AURA_APPLIED" or EA_eventType == "SPELL_AURA_APPLIED_DOSE" or EA_eventType == "SPELL_AURA_REFRESH") then
        	if (EA_arg9 == UnitName("player")) then

				if (EA_Config.ShowSpellInfo) then
	        		DEFAULT_CHAT_FRAME:AddMessage("Spell Name: "..EA_arg13.."  --  Spell ID: "..EA_arg12);
	            end

				if (EA_Items[EA_playerClass][EA_arg12] or EA_CustomItems[EA_playerClass][EA_arg12]) then
		        	if #EA_TempBuffsTable ~= 0 then
                    	local v = table.foreach(EA_TempBuffsTable, function(i2, v2) if v2==EA_arg12 then return v2 end end)
		                if not v then
							EA_addBuffValue(EA_arg12);
						end
	                else
						EA_addBuffValue(EA_arg12);
	                end
                end

				if (EA_StackingItems[EA_playerClass][EA_arg12] and EA_arg12 ~= 64385) then
                    	local name, rank = GetSpellInfo(EA_arg12);

                       	_,_,_,EA_count,_,_,_,_,_,_,_ = UnitBuff("player", name);

						if (EA_count == nil) then
							_,_,_,EA_count,_,_,_,_,_,_,_ = UnitDebuff("player", name);
						end

						if (EA_count ~= nil) then
                        	if (EA_count >= EA_StackingItemsCounts[EA_playerClass][EA_arg12]) then
                                if #EA_TempBuffsTable ~= 0 then
    	                            local v = table.foreach(EA_TempBuffsTable, function(i2, v2) if v2==EA_arg12 then return v2 end end)
		                		 	if not v then
										EA_addBuffValue(EA_arg12);
									end
	                            else
									EA_addBuffValue(EA_arg12);
	                            end
                            end
                        end
                end

    	   	end
        end

        if (EA_eventType == "SPELL_AURA_REMOVED" or EA_eventType == "SPELL_AURA_REMOVED_DOSE") then
        	if (EA_arg9 == UnitName("player")) then
	            if (EA_Items[EA_playerClass][EA_arg12] or EA_CustomItems[EA_playerClass][EA_arg12]) then
                	local v = table.foreach(EA_TempBuffsTable, function(i, v) if v==EA_arg12 then return v end end)
					if v then
						EA_removeBuffValue(v);
					end
				end
            end
		end
    end

	if (event == "PLAYER_DEAD" or event == "PLAYER_ENTERING_WORLD") then
        local EA_arg12 = select(12, ...);

        local v = table.foreach(EA_TempBuffsTable, function(i, v) if v==EA_arg12 then return v end end)
			if v then
	        	local f = _G["EAFrame_"..v];
	            f:Hide();
				EA_TempBuffsTable = table.wipe(EA_TempBuffsTable);
			end


        -- I'm annoyed that this code has to be here and not above in the ADDON_LOADED event.  >-(
        if (EA_PreLoadComplete == 0) then

            for i,v in pairs(EA_AltItems[EA_playerClass]) do
                local name, rank = GetSpellInfo(i);
                local EA_link = GetSpellLink(i);

                if (EA_link ~= nil) then
                    local _, _, spellString = string.find(EA_link, "^|c%x+|Hspell:(.+)|h%[.*%]")

                    if (EA_PreLoadAlts[name] == nil) then
                        EA_PreLoadAlts[name] = spellString;
                    elseif (EA_PreLoadAlts[name] < spellString) then
                        EA_PreLoadAlts[name] = spellString;
                    elseif (EA_PreLoadAlts[name] >= spellString) then
                        -- Do Nothing
                    end
                end
            end
        EA_PreLoadComplete = 1;
        end
	end
	--Handles spells that become active when the scrolling combat text fires a warning for it.
	if (event == "COMBAT_TEXT_UPDATE") then
        local EA_arg1 = select(1, ...);
        local EA_arg2 = select(2, ...);

		if (EA_arg1 == "SPELL_ACTIVE") then
            local v = table.foreach(EA_PreLoadAlts, function(i, v) if i==EA_arg2 then return v end end)
            if v then
            	v = tonumber(v);
				
            	if (EA_AltItems[EA_playerClass][v]) then
                	local v2 = table.foreach(EA_TempBuffsTable, function(i2, v2) if v2==v then return v2 end end)
                    if (not v2) then
						EA_addBuffValue(v);
                    end
                end
            end
        end
	end

	--Handles spells that start "glowing" when they become active.
	if (event == "SPELL_ACTIVATION_OVERLAY_GLOW_SHOW") then
        local EA_arg1 = select(1, ...);
		
		if (EA_AltItems[EA_playerClass][EA_arg1]) then
			
			local EA_usable = IsUsableSpell(EA_arg1);

			if (EA_AltItems[EA_playerClass][EA_arg1]) then
				local v2 = table.foreach(EA_TempBuffsTable, function(i2, v2) if v2==EA_arg1 then return v2 end end)
				if ((not v2) and EA_usable ~= nil) then
					EA_addBuffValue(EA_arg1);
				end
			end
		end
	end
	
	-- Dirty Lightning Shield fix attempt to see what's going on. (Remove from next version.)
	if(EA_playerClass == EA_CLASS_SHAMAN and EA_StackingItems[EA_playerClass][324]) then
		_,_,_,EA_count,_,_,_,_,_,_,_ = UnitBuff("player", "Lightning Shield");
		if (EA_count ~= nil) then
			if (EA_StackingItemsCounts[EA_playerClass][324] <= EA_count) then
				local v2 = table.foreach(EA_TempBuffsTable, function(i2, v2) if v2==324 then return v2 end end)
				if (not v2) then
					EA_addBuffValue(324);
				end
			end
		end
	end

end

function EventAlert_OnUpdate()
    if #EA_TempBuffsTable ~= 0 then

        local timerFontSize = 0;
        for i,v in ipairs (EA_TempBuffsTable) do
            local eaf = _G["EAFrame_"..v];

            local name, rank = GetSpellInfo(v);

            if (EA_Config.ShowStacks) then
            	if (EA_StackingItems[EA_playerClass][v]) then
					if (v == EA_powerAlert) then
						EA_count = EA_powerValue;
					else
						_,_,_,EA_count,_,_,_,_,_,_,_ = UnitBuff("player", name);

						if (EA_count == nil) then
							_,_,_,EA_count,_,_,_,_,_,_,_ = UnitDebuff("player", name);
						end
					end

					if (EA_count ~= nil) then
						eaf.spellCount:ClearAllPoints();
						eaf.spellCount:SetPoint("BOTTOMRIGHT", 0, 0);

						eaf.spellCount:SetFont("Fonts\\\FRIZQT__.TTF", 22, "OUTLINE");
						eaf.spellCount:SetFormattedText("%s", EA_count);
					end
				end
            else
				eaf.spellCount:ClearAllPoints();
				eaf.spellCount:SetPoint("BOTTOMRIGHT", 0, 0);

				eaf.spellCount:SetFont("Fonts\\\FRIZQT__.TTF", 22, "OUTLINE");
				eaf.spellCount:SetFormattedText("%s", "");
            end

            if (v ~= EA_powerAlert) then
				if (EA_StackingItems[EA_playerClass][v]) then

	                _,_,_,EA_count,_,_,_,_,_,_,_ = UnitBuff("player", name);

					if (EA_count == nil) then
						_,_,_,EA_count,_,_,_,_,_,_,_ = UnitDebuff("player", name);
					end

	                local tempCount = EA_StackingItemsCounts[EA_playerClass][v];

	                if (tempCount ~= nil and EA_count ~= nil and EA_count < tempCount) then
						EA_removeBuffValue(v);
				    end
	            end
            end



            if (EA_AltItems[EA_playerClass][v]) then
				-- Lava Surge = 77762
                -- Lava Burst = 51505

				if (v == 77762) then
                	v = 51505;
                    local EA_start, EA_duration, EA_enabled = GetSpellCooldown(v);
		            if (EA_start > 0 and EA_duration > 1.5) then
                        v = 77762;
                        EA_removeBuffValue(v);
	                end

                    EA_affectingCombat = UnitAffectingCombat("player");
                    if (not EA_affectingCombat) then
                        v = 77762;
                        EA_removeBuffValue(v);
                    end
    			else
                	local EA_usable, _ = IsUsableSpell(v);
                    local EA_start, EA_duration, EA_enabled = GetSpellCooldown(v);
		            if (EA_start > 0 and EA_duration > 1.5) then
                        EA_removeBuffValue(v);
	                end

                    if (not EA_usable) then
    	            	EA_removeBuffValue(v);
	                end
                end
            end

            if (EA_Config.ShowTimer == true) then

                _,_,_,_,_,_,EA_expirationTime,_,_ = UnitBuff("player", name);

				if (EA_expirationTime == nil) then
					_,_,_,_,_,_,EA_expirationTime,_,_ = UnitDebuff("player", name);
				end

                if (EA_expirationTime ~= nil) then
                    local EA_time = 0;

                    EA_time = EA_time + EA_expirationTime;
                    EA_currentTime = GetTime();
                    EA_timeLeft = EA_expirationTime - EA_currentTime;

                    if (EA_timeLeft > 0 and EA_timeLeft < 30) then
                        if (EA_Config.ChangeTimer == true) then
                            timerFontSize = 28;
                            eaf.spellTimer:ClearAllPoints();
                            eaf.spellTimer:SetPoint("CENTER", 0, 0);
                        else
                            timerFontSize = 18;
                            eaf.spellTimer:ClearAllPoints();
                            eaf.spellTimer:SetPoint("TOP", 0, 20);
                        end

                        eaf.spellTimer:SetFont("Fonts\\\FRIZQT__.TTF", timerFontSize, "OUTLINE");
                        eaf.spellTimer:SetFormattedText("%d", EA_timeLeft);
                    end
                end
            else
            	eaf.spellTimer:SetText("");
            end
        end
    end
end


function EA_addBuffValue(EASpellID)
    table.insert(EA_TempBuffsTable, EASpellID);
	EventAlert_PositionFrames();
	EventAlert_DoAlert();

end

function EA_removeBuffValue(EASpellID)

	local f = _G["EAFrame_"..EASpellID];
	if (f ~= nil) then
		f:Hide();
	end

    for i,v in ipairs(EA_TempBuffsTable) do
		if (v == EASpellID) then
			table.remove(EA_TempBuffsTable, i);
		end
	end

	EventAlert_PositionFrames();
	f:SetScript("OnUpdate", nil);

end

function EventAlert_DoAlert()

	if (EA_Config.ShowFlash == true) then
	   UIFrameFadeIn(LowHealthFrame, 1, 0, 1);
	   UIFrameFadeOut(LowHealthFrame, 2, 1, 0);
	end

	if (EA_Config.DoAlertSound == true) then
	   PlaySoundFile(EA_Config.AlertSound);
	end
end

function EventAlert_PositionFrames(event)

	if (EA_Config.ShowFrame == true) then

    	EA_Main_Frame:ClearAllPoints();
   		EA_Main_Frame:SetPoint(EA_Position.Anchor, UIParent, EA_Position.relativePoint, EA_Position.xLoc, EA_Position.yLoc);

		local prevFrame = "EA_Main_Frame";


        for k,v in ipairs(EA_TempBuffsTable) do
            local eaf = _G["EAFrame_"..v];
			if (eaf ~= nil) then
				if (v == 85247) then
					_, _, gsiIcon, _, _, _, _, _, _ = GetSpellInfo(85247);
					gsiName, _, _, _, _, _, _, _, _ = GetSpellInfo(v);
				elseif (v == 64385) then
					_, _, gsiIcon, _, _, _, _, _, _ = GetSpellInfo(v);
					gsiName = "Combo Points";
				else
					gsiName, _, gsiIcon, _, _, _, _, _, _ = GetSpellInfo(v);
					if(v == 48107) then
						_, _, gsiIcon, _, _, _, _, _, _ = GetSpellInfo(108853);
					end
				end

				eaf:ClearAllPoints();

				if (prevFrame == "EA_Main_Frame") then
					eaf:SetPoint("CENTER", prevFrame, "CENTER", 0, 0);
				elseif (prevFrame == eaf) then
					prevFrame = "EA_Main_Frame";
					eaf:SetPoint("CENTER", prevFrame, "CENTER", 0, 0);
				else
					eaf:SetPoint("CENTER", prevFrame, "CENTER", 100+EA_Position.xOffset, 0+EA_Position.yOffset);
				end

				eaf:SetWidth(EA_Position.IconSize);
				eaf:SetHeight(EA_Position.IconSize);

				eaf:SetBackdrop({bgFile = gsiIcon});

				if (EA_Config.ShowName == true) then
					eaf.spellName:SetText(gsiName);
				else
					eaf.spellName:SetText("");
				end


				eaf:SetScript("OnUpdate", EventAlert_OnUpdate);
				prevFrame = eaf;
				eaf:Show();
			end
        end
	end
end


function EventAlert_SlashHandler(msg)

    msg = string.lower(msg);

	if (msg == "options" or msg == "opt") then
    	InterfaceOptionsFrame_OpenToCategory(EA_GeneralOptions_Panel);
	elseif (msg == "showframe" or msg == "showtest") then
		EventAlert_Options_ToggleAlertFrame();
	elseif (msg == "togglelock" or msg == "toggleframelock") then
		EA_Position.LockFrame = not(EA_Position.LockFrame);
		local EA_FrameLockMessage = EA_Position.LockFrame;
		DEFAULT_CHAT_FRAME:AddMessage("Frame locked: " .. tostring(EA_FrameLockMessage));
    elseif (msg == "version" or msg == "ver") then
        InterfaceOptionsFrame_OpenToCategory(EA_About_Panel);
    elseif (msg == "print") then
        EventAlert_PrintTable();
    elseif (msg == "printalts") then
        EventAlert_PrintAltsTable();
    elseif (msg == "debug") then
		if (EA_Config.Debug == true) then
			DEFAULT_CHAT_FRAME:AddMessage("Debugging off");
            EA_Config.Debug = false;
        elseif (EA_Config.Debug == false) then
			DEFAULT_CHAT_FRAME:AddMessage("Debugging on");
        	EA_Config.Debug = true;
        end
	elseif (msg == "clear") then
    	EventAlert_ClearTables();
    else
        DEFAULT_CHAT_FRAME:AddMessage("EventAlert commands (/eventalert or /ea):");
        DEFAULT_CHAT_FRAME:AddMessage("/ea options (/ea opt) - Toggle the options window on or off");
        DEFAULT_CHAT_FRAME:AddMessage("/ea version (/ea ver) - Shows the current version of EventAlert.");
		DEFAULT_CHAT_FRAME:AddMessage("/ea showframe (/ea showtest) - Shows/Hides the anchor frames.");
		DEFAULT_CHAT_FRAME:AddMessage("/ea toggleframelock (/ea togglelock) - Locs/Unlocks the anchor frames.");
    end

end


-- Just used for debugging.
function EventAlert_PrintTable()
	table.foreach(EA_TempBuffsTable, print)
end

-- Just used for debugging.
function EventAlert_PrintAltsTable()
	table.foreach(EA_PreLoadAlts, print)
end

function EventAlert_ClearTables()
    for i, v in ipairs(EA_TempBuffsTable) do
		local f = _G["EAFrame_"..i];
		f:Hide();
	end
	EA_TempBuffsTable = table.wipe(EA_TempBuffsTable);
end


function pairsByKeys (t, f)
	local a = {}
		for n in pairs(t) do table.insert(a, n) end
		table.sort(a, f)
		local i = 0      -- iterator variable
		local iter = function ()   -- iterator function
			i = i + 1
			if a[i] == nil then return nil
			else return a[i], t[a[i]]
			end
		end
	return iter
end

function EventAlert_CreateOptionsPanels()
	-- Create Options Panels inside the addons section of the Blizzard UI.
		EventAlert.panel = CreateFrame( "Frame", "EventAlertPanel", UIParent );
		EventAlert.panel.name = "EventAlert";
        EventAlert.panel.okay = EAOptionsPanelOK;
		InterfaceOptions_AddCategory(EventAlert.panel);

		EAOptionsPanel('EA_GeneralOptions_Panel', 'EventAlert', EA_TITLE_MAINOPTIONS, EA_SUBTEXT_MAINOPTIONS)
		EAOptionsPanel('EA_IconOptions_Panel', 'EventAlert', EA_TITLE_ICONOPTIONS, EA_SUBTEXT_ICONOPTIONS)
		EAOptionsPanel('EA_SoundOptions_Panel', 'EventAlert', EA_TITLE_SOUNDOPTIONS, EA_SUBTEXT_SOUNDOPTIONS)
		EAOptionsPanel('EA_AlertOptions_Panel', 'EventAlert', EA_TITLE_ALERTOPTIONS, EA_SUBTEXT_ALERTOPTIONS)
		EAOptionsPanel('EA_CustomAlertOptions_Panel', 'EventAlert', EA_TITLE_CUSTOMALERTOPTIONS, EA_SUBTEXT_CUSTOMALERTOPTIONS)
		EAOptionsPanel('EA_About_Panel', 'EventAlert', EA_TITLE_ABOUT, EA_SUBTEXT_ABOUT)

		EventAlert_CreateGeneralOptionsFrames();
		EventAlert_CreateIconOptionsFrames();
	    EventAlert_CreateSoundOptionsFrames();
        EventAlert_CreateAlertsOptionsFrames();
        EventAlert_CreateCustomAlertsOptionsFrames();
        EventAlert_CreateAboutFrames();
	-- End Options Panels Creation
end

function EventAlert_LoadSpellArrays()
	if EA_CustomItems == nil then EA_CustomItems = {} end;
	if EA_Items == nil then	EA_Items = {} end;
	if EA_AltItems == nil then EA_AltItems = {}	end;
	if EA_StackingItems == nil then EA_StackingItems = {} end;
	if EA_StackingItemsCounts == nil then EA_StackingItemsCounts = {} end;

	EventAlert_LoadAlerts_Deathknight();
	EventAlert_LoadAlerts_Druid();
	EventAlert_LoadAlerts_Hunter();
	EventAlert_LoadAlerts_Mage();
	EventAlert_LoadAlerts_Monk();
	EventAlert_LoadAlerts_Paladin();
	EventAlert_LoadAlerts_Priest();
	EventAlert_LoadAlerts_Rogue();
	EventAlert_LoadAlerts_Shaman();
	EventAlert_LoadAlerts_Warlock();
	EventAlert_LoadAlerts_Warrior();
end
--All credit goes to the original author, CurtisTheGreat
