EA_Config = { DoAlertSound, AlertSound, AlertSoundValue, LockFrame, ShowFrame, ShowName, ShowFlash, ShowTimer, TimerFontSize, StackFontSize, SNameFontSize, ChangeTimer, Version, AllowESC, AllowAltAlerts, Target_MyDebuff };
EA_Position = { Anchor, relativePoint, xLoc, yLoc, xOffset, yOffset, RedDebuff, GreenDebuff, Tar_NewLine, Tar_xOffset, Tar_yOffset };
EA_Pos = {};

EA_SPELLINFO_SELF = { };
EA_SPELLINFO_TARGET = { };

local EA_DEBUGFLAG1 = false;
local EA_DEBUGFLAG2 = false;
local EA_DEBUGFLAG3 = false;
local EA_DEBUGFLAG4 = false;
local EA_LISTSEC_SELF = 0;
local EA_LISTSEC_TARGET = 0;
local EA_SPEC_expirationTime1 = 0;
local EA_SPEC_expirationTime2 = 0;

local EA_CurrentBuffs = { };
local EA_TarCurrentBuffs = { };
local EA_PreLoadAlts = { };
local EA_PreLoadComplete = 0;

-- The first event of this UI
function EventAlert_OnLoad(self)
	self:RegisterEvent("COMBAT_TEXT_UPDATE");
	self:RegisterEvent("UNIT_AURA");
	self:RegisterEvent("PLAYER_TARGET_CHANGED");

	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";

	EA_SPELLINFO_SELF = { };
	EA_SPELLINFO_TARGET = { };

	EA_CurrentBuffs = { };
	EA_TarCurrentBuffs = { };
	EA_PreLoadAlts = { };
	EA_PreLoadComplete = 0;
end

-- The procedures of events
function EventAlert_OnEvent(event)
	if (event == "ADDON_LOADED") then
		if (arg1 == "EventAlert") then

			EventAlert_VersionCheck();
			if EA_Config.AlertSound == nil then EA_Config.AlertSound = "Sound\\Spells\\ShaysBell.wav" end;
			if EA_Config.AlertSoundValue == nil then EA_Config.AlertSoundValue = 1 end;
			if EA_Config.DoAlertSound == nil then EA_Config.DoAlertSound = true end;
			if EA_Config.LockFrame == nil then EA_Config.LockFrame = true end;
			if EA_Config.ShowFrame == nil then EA_Config.ShowFrame = true end;
			if EA_Config.ShowName == nil then EA_Config.ShowName = true end;
			if EA_Config.ShowFlash == nil then EA_Config.ShowFlash = false end;
			if EA_Config.ShowTimer == nil then EA_Config.ShowTimer = true end;
			if EA_Config.IconSize == nil then EA_Config.IconSize = 60 end;
			if EA_Config.TimerFontSize == nil then EA_Config.TimerFontSize = 28 end;
			if EA_Config.StackFontSize == nil then EA_Config.StackFontSize = 18 end;
			if EA_Config.SNameFontSize == nil then EA_Config.SNameFontSize = 14 end;
			if EA_Config.ChangeTimer == nil then EA_Config.ChangeTimer = false end;
			if EA_Config.AllowESC == nil then EA_Config.AllowESC = false end;
			if EA_Config.AllowAltAlerts == nil then EA_Config.AllowAltAlerts = false end;
			if EA_Config.Target_MyDebuff == nil then EA_Config.Target_MyDebuff = false end;

			if EA_Position.Anchor == nil then EA_Position.Anchor = "CENTER" end;
			if EA_Position.relativePoint == nil then EA_Position.relativePoint = "CENTER" end;
			if EA_Position.xLoc == nil then EA_Position.xLoc = 0 end;
			if EA_Position.yLoc == nil then EA_Position.yLoc = 0 end;
			if EA_Position.xOffset == nil then EA_Position.xOffset = 0 end;
			if EA_Position.yOffset == nil then EA_Position.yOffset = 0 end;
			if EA_Position.RedDebuff == nil then EA_Position.RedDebuff = 0.5 end;
			if EA_Position.GreenDebuff == nil then EA_Position.GreenDebuff = 0.5 end;
			if EA_Position.Tar_NewLine == nil then EA_Position.Tar_NewLine = false end;
			if EA_Position.Tar_xOffset == nil then EA_Position.Tar_xOffset = 0 end;
			if EA_Position.Tar_yOffset == nil then EA_Position.Tar_yOffset = -80 end;

			-- if EA_Pos[EA_CLASS_DK] == nil then EA_Pos[EA_CLASS_DK] = EA_Position end;
			-- if EA_Pos[EA_CLASS_DRUID] == nil then EA_Pos[EA_CLASS_DRUID] = EA_Position end;
			-- if EA_Pos[EA_CLASS_HUNTER] == nil then EA_Pos[EA_CLASS_HUNTER] = EA_Position end;
			-- if EA_Pos[EA_CLASS_MAGE] == nil then EA_Pos[EA_CLASS_MAGE] = EA_Position end;
			-- if EA_Pos[EA_CLASS_PALADIN] == nil then EA_Pos[EA_CLASS_PALADIN] = EA_Position end;
			-- if EA_Pos[EA_CLASS_PRIEST] == nil then EA_Pos[EA_CLASS_PRIEST] = EA_Position end;
			-- if EA_Pos[EA_CLASS_ROGUE] == nil then EA_Pos[EA_CLASS_ROGUE] = EA_Position end;
			-- if EA_Pos[EA_CLASS_SHAMAN] == nil then EA_Pos[EA_CLASS_SHAMAN] = EA_Position end;
			-- if EA_Pos[EA_CLASS_WARLOCK] == nil then EA_Pos[EA_CLASS_WARLOCK] = EA_Position end;
			-- if EA_Pos[EA_CLASS_WARRIOR] == nil then EA_Pos[EA_CLASS_WARRIOR] = EA_Position end;

			if EA_SacredShield == nil then EA_SacredShield = {} end;
			if EA_SacredShield.ceArg7 == nil then EA_SacredShield.ceArg7 = "noPlayerActive" end;
			if EA_SacredShield.spellActive == nil then EA_SacredShield.spellActive = false end;
			if EA_SacredShield.expire == nil then EA_SacredShield.expire = 0 end;
			if EA_SacredShield.timer == nil then EA_SacredShield.timer = 0 end;

			_, EA_playerClass = UnitClass("player");
			-- EA_playerClass = EA_CLASS_PALADIN;
			-- EA_playerClass = EA_CLASS_DRUID;
			-- EventAlert_LoadTextArray();
			EventAlert_LoadSpellArray();
			EventAlert_RemoveOldSpells();
			EventAlert_Options_Init();
			EventAlert_Class_Events_Frame_Init();
			EventAlert_Icon_Options_Frame_Init();
			EventAlert_Other_Events_Frame_Init();
			EventAlert_Target_Events_Frame_Init();
			EventAlert_CreateFrames();

			-- if (EA_playerClass == EA_CLASS_WARRIOR) then
			-- 	EA_Alt_Alerts_Frame:SetWidth(325);
			-- 	EA_Alt_Alerts_Frame:SetHeight(675);
			-- else
			-- 	EA_Alt_Alerts_Frame:SetWidth(325);
			-- 	EA_Alt_Alerts_Frame:SetHeight(500);
			-- end

			-- Set up Sacred Shield stuff
			EA_SacredShield.ceArg7 = "noPlayerActive";
			EA_SacredShield.expire = 0;
			EA_SacredShield.spellActive = false;

			if (EA_playerClass == EA_CLASS_PALADIN) then
				EA_nameTalent, _, _, _, EA_talentCurrentRank, _, _, _ = GetTalentInfo(2, 9);

				if (EA_talentCurrentRank == 0) then
					EA_SacredShield.timer = 6;
				elseif (EA_talentCurrentRank == 1) then
					EA_SacredShield.timer = 9;
				elseif (EA_talentCurrentRank == 2) then
					EA_SacredShield.timer = 12;
				end
			end
		end
	end

	if (event == "PLAYER_TARGET_CHANGED") then
		EventAlert_TarChange_ClearFrame();
		if UnitName("player") ~= UnitName("target") then
			EventAlert_TarBuffs_Update();
		end;
	end

	if (event == "UNIT_AURA") then
		EventAlert_Unit_Aura(arg1);
	end

	if (event == "COMBAT_TEXT_UPDATE" and arg1 == "SPELL_ACTIVE") then
		EventAlert_COMBAT_TEXT_SPELL_ACTIVE(arg2);
	end

	if (event == "PLAYER_DEAD" or event == "PLAYER_ENTERING_WORLD") then
		local v = table.foreach(EA_CurrentBuffs, function(i, v) if v==arg9 then return v end end)
		if v then
			local f = _G["EAFrame_"..v];
			f:Hide();
			EA_CurrentBuffs = table.wipe(EA_CurrentBuffs);
		end
		EA_SacredShield.ceArg7 = "noPlayerActive";
		EA_SacredShield.spellActive = false;

		-- 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(name, "");
				-- 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
end


function EventAlert_Unit_Aura(unit)
	if unit == "player" then
		EventAlert_Buffs_Update();
	end
	if unit == "target" then
		EventAlert_TarBuffs_Update();
	end
end


function EventAlert_Buffs_Update()
	local buffsCurrent = {};
	local buffsToDelete = {};
	local ifAdd_buffCur = false;
	-- DEFAULT_CHAT_FRAME:AddMessage("EventAlert_Buffs_Update");
	if (EA_DEBUGFLAG1) then
		DEFAULT_CHAT_FRAME:AddMessage("----"..EA_XCMD_SELFLIST.."----");
	end

	if (EA_DEBUGFLAG3 or EA_DEBUGFLAG4) then
		EventAlert_Class_Events_Frame_ClearPrimarySpellList();
	end

	for i=1,40 do
		local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId = UnitBuff("player", i)
		if (not spellId) then
			break;
		end

		if (spellId == 71601) then EA_SPEC_expirationTime1 = expirationTime end;
		if (spellId == 71644) then EA_SPEC_expirationTime2 = expirationTime end;

		if (EA_DEBUGFLAG1) then
			if (EA_LISTSEC_SELF == 0 or (0 < duration and duration <= EA_LISTSEC_SELF)) then
				DEFAULT_CHAT_FRAME:AddMessage("["..i.."]\124cffFFFF00"..EA_XCMD_DEBUG_P1.."\124r:"..name..
					" /\124cffFFFF00"..EA_XCMD_DEBUG_P2.."\124r:"..spellId..
					" /\124cffFFFF00"..EA_XCMD_DEBUG_P3.."\124r:"..count..
					" /\124cffFFFF00"..EA_XCMD_DEBUG_P4.."\124r:"..duration);
			end
		end

		ifAdd_buffCur = false;
		if (EA_Items[EA_playerClass][spellId] or EA_Items[EA_CLASS_OTHER][spellId]) then
			ifAdd_buffCur = true;
		elseif ((EA_Items[EA_playerClass][spellId] == false) or (EA_Items[EA_CLASS_OTHER][spellId] == false)) then
			ifAdd_buffCur = false;
		elseif (EA_DEBUGFLAG3 or EA_DEBUGFLAG4) then
			if (EA_LISTSEC_SELF == 0 or (0 < duration and duration <= EA_LISTSEC_SELF)) then
				-- DEFAULT_CHAT_FRAME:AddMessage("spellId="..spellId.." /unitCaster="..unitCaster);
				if EA_DEBUGFLAG3 or (EA_DEBUGFLAG4 and (not (UnitInRaid(unitCaster) or UnitInParty(unitCaster)))) then
					if EA_Items[EA_playerClass][spellId] == nil then EA_Items[EA_playerClass][spellId] = true end;
					CreateFrames_CreateSpellFrame(spellId, false);
					ifAdd_buffCur = true;
				end
			end
		end

		if (ifAdd_buffCur) then
			-- if EA_SPELLINFO_SELF[spellId] == nil then EA_SPELLINFO_SELF[spellId] = {name, rank, icon, count, duration, expirationTime, unitCaster, isDebuff} end;
			-- EA_SPELLINFO_SELF[spellId].name = name;
			-- EA_SPELLINFO_SELF[spellId].rank = rank;
			-- EA_SPELLINFO_SELF[spellId].icon = icon;
			EA_SPELLINFO_SELF[spellId].count = count;
			EA_SPELLINFO_SELF[spellId].duration = duration;
			EA_SPELLINFO_SELF[spellId].expirationTime = expirationTime;
			EA_SPELLINFO_SELF[spellId].unitCaster = unitCaster;
			EA_SPELLINFO_SELF[spellId].isDebuff = false;
			-- 추가 시작
			-- Buff is a relevant Event (
			if (spellId == 53817) then
				--주술사: 소용돌이치는 무기
				if(count == 5) then
					table.insert(buffsCurrent, spellId);
				end
			elseif (spellId == 63731 or spellId == 63734 or spellId == 63735) then
				--사제: Serendipity (holy)
				if(count == 3) then
					table.insert(buffsCurrent, spellId);
				end
			elseif (spellId == 71216) then
				--주술사: 눈사태의 토템 효과 : 격노
				if(count == 3) then
					table.insert(buffsCurrent, spellId);
				end
			else
				table.insert(buffsCurrent, spellId);
			end
			-- 추가 끝
--			table.insert(buffsCurrent, spellId);
		end
	end

	for i=41,80 do
		name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId = UnitDebuff("player", i-40)
		if (not spellId) then
			break;
		end

		if (EA_DEBUGFLAG1) then
			if (EA_LISTSEC_SELF == 0 or (0 < duration and duration <= EA_LISTSEC_SELF)) then
				DEFAULT_CHAT_FRAME:AddMessage("["..i.."]\124cffFFFF00"..EA_XCMD_DEBUG_P1.."\124r:"..name..
					" /\124cffFFFF00"..EA_XCMD_DEBUG_P2.."\124r:"..spellId..
					" /\124cffFFFF00"..EA_XCMD_DEBUG_P3.."\124r:"..count..
					" /\124cffFFFF00"..EA_XCMD_DEBUG_P4.."\124r:"..duration);
			end
		end

		ifAdd_buffCur = false;
		if (EA_Items[EA_playerClass][spellId] or EA_Items[EA_CLASS_OTHER][spellId]) then
			ifAdd_buffCur = true;
		elseif ((EA_Items[EA_playerClass][spellId] == false) or (EA_Items[EA_CLASS_OTHER][spellId] == false)) then
			ifAdd_buffCur = false;
		elseif (EA_DEBUGFLAG3 or EA_DEBUGFLAG4) then
			if (EA_LISTSEC_SELF == 0 or (0 < duration and duration <= EA_LISTSEC_SELF)) then
				-- DEFAULT_CHAT_FRAME:AddMessage("spellId="..spellId.." /unitCaster="..unitCaster);
				if EA_DEBUGFLAG3 or (EA_DEBUGFLAG4 and (not (UnitInRaid(unitCaster) or UnitInParty(unitCaster)))) then
					if EA_Items[EA_playerClass][spellId] == nil then EA_Items[EA_playerClass][spellId] = true end;
					CreateFrames_CreateSpellFrame(spellId, false);
					ifAdd_buffCur = true;
				end
			end
		end

		if (ifAdd_buffCur) then
			-- if EA_SPELLINFO_SELF[spellId] == nil then EA_SPELLINFO_SELF[spellId] = {name, rank, icon, count, duration, expirationTime, unitCaster, isDebuff} end;
			-- EA_SPELLINFO_SELF[spellId].name = name;
			-- EA_SPELLINFO_SELF[spellId].rank = rank;
			-- EA_SPELLINFO_SELF[spellId].icon = icon;
			EA_SPELLINFO_SELF[spellId].count = count;
			EA_SPELLINFO_SELF[spellId].duration = duration;
			EA_SPELLINFO_SELF[spellId].expirationTime = expirationTime;
			EA_SPELLINFO_SELF[spellId].unitCaster = unitCaster;
			EA_SPELLINFO_SELF[spellId].isDebuff = true;
			-- 추가 시작
			-- Buff is a relevant Event (
			if (spellId == 53817) then
				--주술사: 소용돌이치는 무기
				if(count == 5) then
					table.insert(buffsCurrent, spellId);
				end
			elseif (spellId == 63731 or spellId == 63734 or spellId == 63735) then
				--사제: Serendipity (holy)
				if(count == 3) then
					table.insert(buffsCurrent, spellId);
				end
			elseif (spellId == 71216) then
				--주술사: 눈사태의 토템 효과 : 격노
				if(count == 3) then
					table.insert(buffsCurrent, spellId);
				end
			else
				table.insert(buffsCurrent, spellId);
			end
			-- 추가 끝
--			table.insert(buffsCurrent, spellId);
		end
	end

	-- Check: Buff dropped
	local v1 = table.foreach(EA_CurrentBuffs,
		function(i, v1)
			-- DEFAULT_CHAT_FRAME:AddMessage("buff-check: "..i.." id: "..v1);
			if(not EA_AltItems[EA_playerClass][v1]) then
				local v2 = table.foreach(buffsCurrent,
					function(k, v2)
						if (v1==v2) then
							return v2;
						end
					end
				)
				if(not v2) then
					-- Buff dropped
					table.insert(buffsToDelete, v1);
				end
			end
		end
	)

	-- Drop Buffs
	table.foreach(buffsToDelete,
		function(i, v)
			-- DEFAULT_CHAT_FRAME:AddMessage("buff-dropped: id: "..v);
			EventAlert_Buff_Dropped(v);
		end
	)

	-- Check: Buff applied
	local v1 = table.foreach(buffsCurrent,
		function(i, v1)
			local v2 = table.foreach(EA_CurrentBuffs,
				function(k, v2)
					if (v1==v2) then
					return v2;
					end
				end
			)
			if(not v2) then
				-- Buff applied
				EventAlert_Buff_Applied(v1);
			end
		end
	)

	if (EA_DEBUGFLAG3 or EA_DEBUGFLAG4) then
		CreateFrames_RefreshPrimarySpellList();
	end
end


function EventAlert_TarBuffs_Update()
	local buffsCurrent = {};
	local buffsToDelete = {};
	local ComfirmToShow = false;
	-- DEFAULT_CHAT_FRAME:AddMessage("EventAlert_Buffs_Update");
	if (EA_DEBUGFLAG2) then
		DEFAULT_CHAT_FRAME:AddMessage("--------"..EA_XCMD_TARGETLIST.."--------");
	end

	for i=1,40 do
		name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId = UnitDebuff("target", i)
		if (not spellId) then
			break;
		end

		ComfirmToShow = false;
		if EA_Config.Target_MyDebuff then
			if unitCaster == "player" then
				ComfirmToShow = true;
			end
		else
			ComfirmToShow = true;
		end

		if (EA_DEBUGFLAG2) then
			if ComfirmToShow then
				if (EA_LISTSEC_TARGET == 0 or (0 < duration and duration <= EA_LISTSEC_TARGET)) then
					DEFAULT_CHAT_FRAME:AddMessage("["..i.."]\124cffFFFF00"..EA_XCMD_DEBUG_P1.."\124r:"..name..
						" /\124cffFFFF00"..EA_XCMD_DEBUG_P2.."\124r:"..spellId..
						" /\124cffFFFF00"..EA_XCMD_DEBUG_P3.."\124r:"..count..
						" /\124cffFFFF00"..EA_XCMD_DEBUG_P4.."\124r:"..duration);
				end
			end
		end

		if (EA_TarItems[EA_playerClass][spellId]) then
			if ComfirmToShow then
				-- if EA_SPELLINFO_TARGET[spellId] == nil then EA_SPELLINFO_TARGET[spellId] = {name, rank, icon, count, duration, expirationTime, unitCaster, isDebuff} end;
				-- EA_SPELLINFO_TARGET[spellId].name = name;
				-- EA_SPELLINFO_TARGET[spellId].rank = rank;
				-- EA_SPELLINFO_TARGET[spellId].icon = icon;
				EA_SPELLINFO_TARGET[spellId].count = count;
				EA_SPELLINFO_TARGET[spellId].duration = duration;
				EA_SPELLINFO_TARGET[spellId].expirationTime = expirationTime;
				EA_SPELLINFO_TARGET[spellId].unitCaster = unitCaster;
				EA_SPELLINFO_TARGET[spellId].isDebuff = true;
				table.insert(buffsCurrent, spellId);
			end
		end
	end

	-- Check: Buff dropped
	local v1 = table.foreach(EA_TarCurrentBuffs,
		function(i, v1)
			-- DEFAULT_CHAT_FRAME:AddMessage("buff-check: "..i.." id: "..v1);
			-- DEFAULT_CHAT_FRAME:AddMessage("===============\n=== buff-check: "..i.." /v1 id: "..v1);
			local v2 = table.foreach(buffsCurrent,
				function(k, v2)
					-- DEFAULT_CHAT_FRAME:AddMessage("=== buff-check: "..i.." /v2 id: "..v1);
					if (v1==v2) then
						return v2;
					end
				end
			)
			if(not v2) then
				-- Buff dropped
				-- DEFAULT_CHAT_FRAME:AddMessage("=== add to Delete /v1 id: "..v1);
				table.insert(buffsToDelete, v1);
			end
		end
	)

	-- Drop Buffs
	table.foreach(buffsToDelete,
		function(i, v)
			-- DEFAULT_CHAT_FRAME:AddMessage("buff-dropped: id: "..v);
			EventAlert_TarBuff_Dropped(v);
		end
	)

	-- Check: Buff applied
	local v1 = table.foreach(buffsCurrent,
		function(i, v1)
			local v2 = table.foreach(EA_TarCurrentBuffs,
				function(k, v2)
					if (v1==v2) then
					return v2;
					end
				end
			)
			if(not v2) then
				-- Buff applied
				-- DEFAULT_CHAT_FRAME:AddMessage("EventAlert_Buff_Applied("..v1..")");
				EventAlert_TarBuff_Applied(v1);
			end
		end
	)
end


function EventAlert_TarChange_ClearFrame()
	local ibuff = #EA_TarCurrentBuffs;
	for i=1,ibuff do
		EventAlert_TarBuff_Dropped(EA_TarCurrentBuffs[1]);
	end
end


function EventAlert_Buff_Dropped(spellId)
	-- DEFAULT_CHAT_FRAME:AddMessage("buff-dropping: id: "..spellId);
	local f = _G["EAFrame_"..spellId];
	f:Hide();
	removeBuffValue(EA_CurrentBuffs, spellId);
	EventAlert_PositionFrames();
	f:SetScript("OnUpdate", nil);
end
function EventAlert_Buff_Applied(spellId)
	-- DEFAULT_CHAT_FRAME:AddMessage("buff-applying: id: "..spellId);
	table.insert(EA_CurrentBuffs, spellId);
	EventAlert_PositionFrames();
	EventAlert_DoAlert();
end
function EventAlert_TarBuff_Dropped(spellId)
	-- DEFAULT_CHAT_FRAME:AddMessage("buff-dropping: id: "..spellId);
	local f = _G["EAFrame_"..spellId];
	f:Hide();
	removeBuffValue(EA_TarCurrentBuffs, spellId);
	EventAlert_TarPositionFrames();
	f:SetScript("OnUpdate", nil);
end
function EventAlert_TarBuff_Applied(spellId)
	-- DEFAULT_CHAT_FRAME:AddMessage("buff-applying: id: "..spellId);
	table.insert(EA_TarCurrentBuffs, spellId);
	EventAlert_TarPositionFrames();
end


function EventAlert_COMBAT_TEXT_SPELL_ACTIVE(spellName)
	if (EA_Config.AllowAltAlerts==true) then
		-- DEFAULT_CHAT_FRAME:AddMessage("spell-active: "..spellName);
		-- searching for the spell-id, because we only get the name of the spell
		local spellId = table.foreach(EA_PreLoadAlts, function(i, spellId)
			-- DEFAULT_CHAT_FRAME:AddMessage("EA_PreLoadAlts("..spellId..")");
			if i==spellName then
				return spellId
			end
		end)

		if spellId then
			spellId = tonumber(spellId);
			if (EA_AltItems[EA_playerClass][spellId]) then
				local v2 = table.foreach(EA_CurrentBuffs, function(i2, v2)
					if v2==spellId then
						return v2
					end
				end)

				if (not v2) then
					-- DEFAULT_CHAT_FRAME:AddMessage("EventAlert_Buff_Applied("..spellId..")");
					EventAlert_Buff_Applied(spellId);
				end
			end
		end
	end
end


function EventAlert_OnUpdate()
	if #EA_CurrentBuffs ~= 0 then

		local timerFontSize = 0;
		for i,v in ipairs (EA_CurrentBuffs) do
			local eaf = _G["EAFrame_"..v];
			-- local name, rank = GetSpellInfo(v);
			local spellId = tonumber(v);
			local name = EA_SPELLINFO_SELF[spellId].name;
			local rank = EA_SPELLINFO_SELF[spellId].rank;

			if (EA_Config.AllowAltAlerts == true) then
				if (EA_AltItems[EA_playerClass][v]) then
					local EA_usable, EA_nomana = IsUsableSpell(name);

					if (EA_usable ~= 1) then
						EventAlert_Buff_Dropped(v);
					else
						local _,_,_,EAA_count,_,_,EAA_expirationTime,_,_ = UnitAura("player", name, rank);
						EA_SPELLINFO_SELF[spellId].count = EAA_count;
						EA_SPELLINFO_SELF[spellId].expirationTime = EAA_expirationTime;
						EA_SPELLINFO_SELF[spellId].isDebuff = false;
					end
				end
			end

			if (EA_Config.ShowTimer == true) then
				-- local _,_,_,_,_,_,EA_expirationTime,_,_ = UnitAura("player", name, rank);
				-- local EA_Name,_,_,EA_count,_,_,EA_expirationTime,_,_ = UnitAura("player", name, rank);
				local EA_Name = EA_SPELLINFO_SELF[spellId].name;
				local EA_count = EA_SPELLINFO_SELF[spellId].count;
				local EA_expirationTime = EA_SPELLINFO_SELF[spellId].expirationTime;
				local IfIsDebuff = EA_SPELLINFO_SELF[spellId].isDebuff;
				local EA_currentTime = 0;
				local EA_timeLeft = 0;

				if (spellId == 58597) then
					-- I realize this is a nasty hack. But for some damned reason it keeps pulling the time of the full
					-- sacred shield buff and not the procced buff. So until I figure it out, this is how it's getting done!
					EA_expirationTime = EA_SacredShield.expire;
				end
				if (spellId == 71600 or spellId == 71601) then EA_expirationTime = EA_SPEC_expirationTime1 end;
				if (spellId == 71643 or spellId == 71644) then EA_expirationTime = EA_SPEC_expirationTime2 end;

				if (EA_expirationTime ~= nil) then
					EA_currentTime = GetTime();
					EA_timeLeft = 0 + EA_expirationTime - EA_currentTime;

					if EA_timeLeft > 0 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:SetFont("Fonts\\\FRIZQT__.TTF", EA_Config.TimerFontSize, "OUTLINE");
						eaf.spellTimer:SetFormattedText("%d", EA_timeLeft);

						eaf.spellStack:ClearAllPoints();
						if (EA_count > 1) then
							eaf.spellStack:SetPoint("BOTTOMRIGHT", 0, 0);
							eaf.spellStack:SetFont("Fonts\\\FRIZQT__.TTF", EA_Config.StackFontSize, "OUTLINE");
							eaf.spellStack:SetFormattedText("%d", EA_count);
						else
							eaf.spellStack:SetFormattedText("");
						end
					end
				end
			end
		end
	end
end


function EventAlert_OnTarUpdate()
	if #EA_TarCurrentBuffs ~= 0 then

		for i,v in ipairs (EA_TarCurrentBuffs) do
			local eaf = _G["EAFrame_"..v];
			-- local name, rank = GetSpellInfo(v);
			local spellId = tonumber(v);

			if (EA_Config.ShowTimer == true) then
				-- local EA_Name,_,_,EA_count,_,_,EA_expirationTime,_,_ = UnitDebuff("target", name, rank);
				local EA_Name = EA_SPELLINFO_TARGET[spellId].name;
				local EA_count = EA_SPELLINFO_TARGET[spellId].count;
				local EA_expirationTime = EA_SPELLINFO_TARGET[spellId].expirationTime;
				local IfIsDebuff = EA_SPELLINFO_TARGET[spellId].isDebuff;
				local EA_currentTime = 0;
				local EA_timeLeft = 0;

				if (EA_expirationTime ~= nil) then
					EA_currentTime = GetTime();
					EA_timeLeft = 0 + EA_expirationTime - EA_currentTime;

					if EA_timeLeft > 0 then
						if (EA_Config.ChangeTimer == true) then
							eaf.spellTimer:ClearAllPoints();
							eaf.spellTimer:SetPoint("CENTER", 0, 0);
						else
							eaf.spellTimer:ClearAllPoints();
							eaf.spellTimer:SetPoint("TOP", 0, 20);
						end
						eaf.spellTimer:SetFont("Fonts\\\FRIZQT__.TTF", EA_Config.TimerFontSize, "OUTLINE");
						eaf.spellTimer:SetFormattedText("%d", EA_timeLeft);

						eaf.spellStack:ClearAllPoints();
						if (EA_count > 1) then
							eaf.spellStack:SetPoint("BOTTOMRIGHT", 0, 0);
							eaf.spellStack:SetFont("Fonts\\\FRIZQT__.TTF", EA_Config.StackFontSize, "OUTLINE");
							eaf.spellStack:SetFormattedText("%d", EA_count);
						else
							eaf.spellStack:SetFormattedText("");
						end
					end
				end
			end
		end
	end
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";
		local prevFrame2 = "EA_Main_Frame";
		local xOffset = 100 + EA_Position.xOffset;
		local yOffset = 0 + EA_Position.yOffset;

		for k,v in ipairs(EA_CurrentBuffs) do
			local eaf = _G["EAFrame_"..v];
			local spellId = tonumber(v);
			local gsiName = EA_SPELLINFO_SELF[spellId].name;
			local gsiIcon = EA_SPELLINFO_SELF[spellId].icon;
			local gsiIsDebuff = EA_SPELLINFO_SELF[spellId].isDebuff;

			eaf:ClearAllPoints();
			if EA_Position.Tar_NewLine then
				if gsiIsDebuff then
					if (prevFrame2 == "EA_Main_Frame" or prevFrame2 == eaf) then
						prevFrame2 = "EA_Main_Frame";
						eaf:SetPoint(EA_Position.Anchor, prevFrame2, EA_Position.Anchor, -1 * xOffset, -1 * yOffset);
					else
						eaf:SetPoint("CENTER", prevFrame2, "CENTER", -1 * xOffset, -1 * yOffset);
					end
					prevFrame2 = eaf;
				else
					if (prevFrame == "EA_Main_Frame" or prevFrame == eaf) then
						prevFrame = "EA_Main_Frame";
						eaf:SetPoint(EA_Position.Anchor, prevFrame, EA_Position.Anchor, 0, 0);
					else
						eaf:SetPoint("CENTER", prevFrame, "CENTER", xOffset, yOffset);
					end
					prevFrame = eaf;
				end
			else
				if (prevFrame == "EA_Main_Frame" or prevFrame == eaf) then
					prevFrame = "EA_Main_Frame";
					eaf:SetPoint(EA_Position.Anchor, prevFrame, EA_Position.Anchor, 0, 0);
				else
					eaf:SetPoint("CENTER", prevFrame, "CENTER", xOffset, yOffset);
				end
				prevFrame = eaf;
			end;

			eaf:SetWidth(EA_Config.IconSize);
			eaf:SetHeight(EA_Config.IconSize);
			eaf:SetBackdrop({bgFile = gsiIcon});
			if gsiIsDebuff then eaf:SetBackdropColor(1.0, EA_Position.RedDebuff, EA_Position.RedDebuff) end;
			if (EA_Config.ShowName == true) then
				eaf.spellName:SetText(gsiName);
				local SfontName, SfontSize = eaf.spellName:GetFont();
	            eaf.spellName:SetFont(SfontName, EA_Config.SNameFontSize);
			else
				eaf.spellName:SetText("");
			end
			eaf:SetScript("OnUpdate", EventAlert_OnUpdate);
			eaf:Show();
		end
	end
end


function EventAlert_TarPositionFrames(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";
		local xOffset = 100 + EA_Position.xOffset;
		local yOffset = 0 + EA_Position.yOffset;

		for k,v in ipairs(EA_TarCurrentBuffs) do
			local eaf = _G["EAFrame_"..v];
			local spellId = tonumber(v);
			local gsiName = EA_SPELLINFO_TARGET[spellId].name;
			local gsiIcon = EA_SPELLINFO_TARGET[spellId].icon;
			-- local gsiIsDebuff = EA_SPELLINFO_TARGET[spellId].isDebuff;

			eaf:ClearAllPoints();
			if EA_Position.Tar_NewLine then
				if (prevFrame == "EA_Main_Frame" or prevFrame == eaf) then
					prevFrame = "EA_Main_Frame";
					eaf:SetPoint(EA_Position.Anchor, prevFrame, EA_Position.Anchor, EA_Position.Tar_xOffset, EA_Position.Tar_yOffset);
				else
					eaf:SetPoint("CENTER", prevFrame, "CENTER", xOffset, yOffset);
				end
			else
				if (prevFrame == "EA_Main_Frame" or prevFrame == eaf) then
					prevFrame = "EA_Main_Frame";
					eaf:SetPoint(EA_Position.Anchor, prevFrame, EA_Position.Anchor, -1 * xOffset, -1 * yOffset);
				else
					eaf:SetPoint("CENTER", prevFrame, "CENTER", -1 * xOffset, -1 * yOffset);
				end
			end

			eaf:SetWidth(EA_Config.IconSize);
			eaf:SetHeight(EA_Config.IconSize);
			eaf:SetBackdrop({bgFile = gsiIcon});
			eaf:SetBackdropColor(EA_Position.GreenDebuff, 1.0, EA_Position.GreenDebuff);
			if (EA_Config.ShowName == true) then
				eaf.spellName:SetText(gsiName);
				local SfontName, SfontSize = eaf.spellName:GetFont();
	            eaf.spellName:SetFont(SfontName, EA_Config.SNameFontSize);
			else
				eaf.spellName:SetText("");
			end
			eaf:SetScript("OnUpdate", EventAlert_OnTarUpdate);
			prevFrame = eaf;
			eaf:Show();
		end
	end
end


-- The command parser
function EventAlert_SlashHandler(msg)
	local F_EA = "\124cffFFFF00EventAlert2\124r";
	local F_ON = "\124cffFF0000".."[켬]".."\124r";
	local F_OFF = "\124cff00FFFF".."[끔]".."\124r";
	local RtnMsg = "";
	local MoreHelp = false;

	msg = string.lower(msg);
	local cmdtype, para1 = strsplit(" ", msg)
	local listSec = 0;
	if para1 ~= nil then
		listSec = tonumber(para1);
	end

	if (cmdtype == "options" or cmdtype == "opt") then
		if not EA_Options_Frame:IsVisible() then
			ShowUIPanel(EA_Options_Frame);
		else
			HideUIPanel(EA_Options_Frame);
		end

	-- elseif (cmdtype == "version" or cmdtype == "ver") then
	-- 	DEFAULT_CHAT_FRAME:AddMessage(F_EA..EA_XCMD_VER..EA_Config.Version);

	elseif (cmdtype == "show") then
		EA_DEBUGFLAG3 = false;
		EA_DEBUGFLAG4 = false;
		EA_LISTSEC_SELF = 0;
		if (EA_DEBUGFLAG1) then
			EA_DEBUGFLAG1 = false;
			RtnMsg = F_EA..EA_XCMD_SELFLIST..F_OFF;
		else
			EA_DEBUGFLAG1 = true;
			EA_LISTSEC_SELF = listSec;
			RtnMsg = F_EA..EA_XCMD_SELFLIST..F_ON;
			if EA_LISTSEC_SELF > 0 then RtnMsg = RtnMsg.." ("..EA_LISTSEC_SELF.." 초)" end;
		end
		DEFAULT_CHAT_FRAME:AddMessage(RtnMsg);

	elseif (cmdtype == "showtarget" or cmdtype == "showt") then
		EA_DEBUGFLAG3 = false;
		EA_DEBUGFLAG4 = false;
		EA_LISTSEC_TARGET = 0;
		if (EA_DEBUGFLAG2) then
			EA_DEBUGFLAG2 = false;
			RtnMsg = F_EA..EA_XCMD_TARGETLIST..F_OFF;
		else
			EA_DEBUGFLAG2 = true;
			EA_LISTSEC_TARGET = listSec;
			RtnMsg = F_EA..EA_XCMD_TARGETLIST..F_ON;
			if EA_LISTSEC_TARGET > 0 then RtnMsg = RtnMsg.." ("..EA_LISTSEC_TARGET.." 초)" end;
		end
		DEFAULT_CHAT_FRAME:AddMessage(RtnMsg);

	elseif (cmdtype == "showautoadd" or cmdtype == "showa") then
		EA_DEBUGFLAG1 = false;
		EA_DEBUGFLAG2 = false;
		EA_DEBUGFLAG4 = false;
		EA_LISTSEC_SELF = 60;
		if (EA_DEBUGFLAG3) then
			EA_DEBUGFLAG3 = false;
			RtnMsg = F_EA..EA_XCMD_AUTOADD_SELFLIST..F_OFF;
		else
			EA_DEBUGFLAG3 = true;
			RtnMsg = F_EA..EA_XCMD_AUTOADD_SELFLIST..F_ON;
			if listSec > 0 then	EA_LISTSEC_SELF = listSec end;
			if EA_LISTSEC_SELF > 0 then RtnMsg = RtnMsg.." ("..EA_LISTSEC_SELF.." 초)" end;
		end
		DEFAULT_CHAT_FRAME:AddMessage(RtnMsg);

	elseif (cmdtype == "showenvadd" or cmdtype == "showe") then
		EA_DEBUGFLAG1 = false;
		EA_DEBUGFLAG2 = false;
		EA_DEBUGFLAG3 = false;
		EA_LISTSEC_SELF = 60;
		if (EA_DEBUGFLAG4) then
			EA_DEBUGFLAG4 = false;
			RtnMsg = F_EA..EA_XCMD_ENVADD_SELFLIST..F_OFF;
		else
			EA_DEBUGFLAG4 = true;
			RtnMsg = F_EA..EA_XCMD_ENVADD_SELFLIST..F_ON;
			if listSec > 0 then	EA_LISTSEC_SELF = listSec end;
			if EA_LISTSEC_SELF > 0 then RtnMsg = RtnMsg.." ("..EA_LISTSEC_SELF.." 초)" end;
		end
		DEFAULT_CHAT_FRAME:AddMessage(RtnMsg);

	elseif (cmdtype == "print") then
		EventAlert_PrintTable();

	else
		if cmdtype == "help" then MoreHelp = true end;
		DEFAULT_CHAT_FRAME:AddMessage(F_EA..EA_XCMD_VER..EA_Config.Version);
		DEFAULT_CHAT_FRAME:AddMessage(EA_XCMD_CMDHELP.TITLE);
		DEFAULT_CHAT_FRAME:AddMessage(EA_XCMD_CMDHELP.OPT);
		DEFAULT_CHAT_FRAME:AddMessage(EA_XCMD_CMDHELP.HELP);

		for i, v in ipairs(EA_XCMD_CMDHELP["SHOW"]) do
			if i == 1 then
				if EA_DEBUGFLAG1 then v = v..EA_XCMD_SELFLIST..F_ON else v = v..EA_XCMD_SELFLIST..F_OFF end;
				DEFAULT_CHAT_FRAME:AddMessage(v);
			elseif MoreHelp then
				DEFAULT_CHAT_FRAME:AddMessage(v)
			end

		end
		for i, v in ipairs(EA_XCMD_CMDHELP["SHOWT"]) do
			if i == 1 then
				if EA_DEBUGFLAG2 then v = v..EA_XCMD_TARGETLIST..F_ON else v = v..EA_XCMD_TARGETLIST..F_OFF end;
				DEFAULT_CHAT_FRAME:AddMessage(v);
			elseif MoreHelp then
				DEFAULT_CHAT_FRAME:AddMessage(v)
			end
		end
		for i, v in ipairs(EA_XCMD_CMDHELP["SHOWA"]) do
			if i == 1 then
				if EA_DEBUGFLAG3 then v = v..EA_XCMD_AUTOADD_SELFLIST..F_ON else v = v..EA_XCMD_AUTOADD_SELFLIST..F_OFF end;
				DEFAULT_CHAT_FRAME:AddMessage(v);
			elseif MoreHelp then
				DEFAULT_CHAT_FRAME:AddMessage(v)
			end
		end
		for i, v in ipairs(EA_XCMD_CMDHELP["SHOWE"]) do
			if i == 1 then
				if EA_DEBUGFLAG4 then v = v..EA_XCMD_ENVADD_SELFLIST..F_ON else v = v..EA_XCMD_ENVADD_SELFLIST..F_OFF end;
				DEFAULT_CHAT_FRAME:AddMessage(v);
			elseif MoreHelp then
				DEFAULT_CHAT_FRAME:AddMessage(v)
			end
		end
	end
end


-- The URLs of update
function EventAlert_ShowVerURL(SiteIndex)
	local VerUrl = "";
	VerUrl = EA_XOPT_VERURL1;
	if SiteIndex ~= 1 then VerUrl = EA_XOPT_VERURL2; end

	ChatFrame1EditBox:SetText(VerUrl)
	if not ChatFrame1EditBox:IsShown() then ChatFrame1EditBox:Show();	end
	ChatFrame1EditBox:HighlightText()
end


function EventAlert_VersionCheck()
	local EA_tempVer = GetAddOnMetadata("EventAlert", "Version");

	if (EA_Config.Version == EA_tempVer) then
		-- Do Nothing
	elseif (EA_Config.Version ~= EA_tempVer and EA_Config.Version ~= nil) then
		EA_Config.Version = EA_tempVer;
		-- EA_Version_Frame_EditBox:SetFontObject(ChatFontNormal);
		-- EA_Version_Frame_EditBox:SetText("EventAlert new version detected!\n\n\n\n- EventAlert can now track abilities that don't create a buff on the player.\n ** Please note that these are disabled by default. **\n\nType: /ea opt to view the options if you wish to change them.\n\n\nAlso note, that I will be cleaning up the sorting of the events that are listed in the options, so they aren't so confusing. I wanted to get this update out to you all, since it's working, rather than delaying a few more days just to make something you won't look at very often anyhow, a bit more pretty. :P\n\n\n\n\nEventAlert version "..EA_Config.Version.." loaded.")
		-- EA_Version_Frame:Show();
	elseif (EA_Config.Version == nil) then
		EA_Config.Version = EA_tempVer;
		EA_Version_Frame_EditBox:SetFontObject(ChatFontNormal);
		EA_Version_Frame_EditBox:SetText("- EventAlert first load detected.\n- EventAlert is setting all settings to default.\n\nKnown Bugs:\n * Anchor button has to be pressed twice for it to show.\n\n\nEventAlert version "..EA_Config.Version.." loaded.")
		EA_Version_Frame:Show();
		-- EventAlert_FunctionOfDoom();
		EA_Config = nil;
		EA_Config = { DoAlertSound, AlertSound, AlertSoundValue, LockFrame, ShowFrame, ShowName, ShowFlash, ShowTimer, TimerFontSize, StackFontSize, SNameFontSize, ChangeTimer, Version, AllowESC, AllowAltAlerts, Target_MyDebuff };
		EA_Position = nil;
		EA_Position = { Anchor, relativePoint, xLoc, yLoc, xOffset, yOffset, RedDebuff, GreenDebuff, Tar_NewLine, Tar_xOffset, Tar_yOffset };
		EA_Pos = nil;
		EA_Items = nil;
		EA_Config.Version = EA_tempVer;
	end

	-- After confirm the version, set the VersionText in the EA_Options_Frame.
    EA_Options_Frame_VersionText:SetText("Ver:\124cffFFFFFF"..EA_Config.Version.."\124r");
end


-- Just used for debugging.
function EventAlert_PrintTable()
	-- table.foreach(EA_PreLoadAlts, print)
	-- DEFAULT_CHAT_FRAME:AddMessage(EA_PreLoadComplete);
	-- table.foreach(EA_TarCurrentBuffs,
	-- 	function(i, v)
	-- 		DEFAULT_CHAT_FRAME:AddMessage("EA_TarCurrentBuffs["..i.."] = "..v);
	-- 	end
	-- )
	-- DEFAULT_CHAT_FRAME:AddMessage("----EventAlert_PrintTable----");
	-- table.foreach(EA_SPELLINFO_SELF,
	-- function(i, v)
	-- 	DEFAULT_CHAT_FRAME:AddMessage("["..i.."]\124cffFFFF00"..EA_XCMD_DEBUG_P1.."\124r:"..EA_SPELLINFO_SELF[i].name..
	-- 		" /\124cffFFFF00"..EA_XCMD_DEBUG_P2.."\124r:"..i..
	-- 		" /\124cffFFFF00"..EA_XCMD_DEBUG_P3.."\124r:"..EA_SPELLINFO_SELF[i].count..
	-- 		" /\124cffFFFF00"..EA_XCMD_DEBUG_P4.."\124r:"..EA_SPELLINFO_SELF[i].duration);
	-- 	end
	-- )
	-- table.foreach(EA_SPELLINFO_TARGET,
	-- function(i, v)
	-- 	DEFAULT_CHAT_FRAME:AddMessage("["..i.."]\124cffFFFF00"..EA_XCMD_DEBUG_P1.."\124r:"..EA_SPELLINFO_TARGET[i].name..
	-- 		" /\124cffFFFF00"..EA_XCMD_DEBUG_P2.."\124r:"..i..
	-- 		" /\124cffFFFF00"..EA_XCMD_DEBUG_P3.."\124r:"..EA_SPELLINFO_TARGET[i].count..
	-- 		" /\124cffFFFF00"..EA_XCMD_DEBUG_P4.."\124r:"..EA_SPELLINFO_TARGET[i].duration);
	-- 	end
	-- )
	-- table.foreach(EA_PreLoadAlts,
	-- function(i, v)
	-- 	DEFAULT_CHAT_FRAME:AddMessage("["..i.."]EA_PreLoadAlts["..i.."]="..EA_PreLoadAlts[i]);
	-- end
	-- )
end

function removeBuffValue(tab, value)
	for pos, name in ipairs(tab) do
		if (name == value) then
			table.remove(tab, pos)
		end
	end
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
