InvenRaidFrames = LibStub("AceAddon-3.0"):NewAddon("InvenRaidFrames", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0")
local self = InvenRaidFrames
self.titleText = "인벤 레이드 프레임"

local HealComm = LibStub("LibHealComm-3.0", true)
local QuickHealth = LibStub("LibQuickHealth-2.0", true)
local SM = LibStub("LibSharedMedia-3.0")
local MBB = LibStub("LibMMButton-1.1"):Embed(self)

SM:Register("statusbar", "Glaze", "Interface\\AddOns\\InvenRaidFrames\\Texture\\Glaze")
SM:Register("statusbar", "Smooth", "Interface\\AddOns\\InvenRaidFrames\\Texture\\Smooth")
SM:Register("statusbar", "Smooth v2", "Interface\\AddOns\\InvenRaidFrames\\Texture\\Smoothv2")
SM:Register("statusbar", "Steel", "Interface\\AddOns\\InvenRaidFrames\\Texture\\Steel")
SM:Register("statusbar", "BantoBar", "Interface\\AddOns\\InvenRaidFrames\\Texture\\BantoBar")
SM:Register("statusbar", "Glamour3", "Interface\\AddOns\\InvenRaidFrames\\Texture\\Glamour3")
SM:Register("sound", "IRF: 어그로 획득", "Interface\\AddOns\\InvenRaidFrames\\Sound\\IRFAggroGain.wav")
SM:Register("sound", "IRF: 어그로 손실", "Interface\\AddOns\\InvenRaidFrames\\Sound\\IRFAggroLost.wav")
SM:Register("sound", "IRF: 디버프", "Interface\\AddOns\\InvenRaidFrames\\Sound\\IRFDebuff.wav")

local initLogin = false
local initEvent = false
local first = true
local clear = true
local clearMemory = false
local firstPEW = true

local function dummyFunc() end

local _G = _G
local UnitExists = _G.UnitExists
local UnitName = _G.UnitName
local UnitClass = _G.UnitClass
local UnitHealth = _G.UnitHealth
local UnitHealthMax = _G.UnitHealthMax
local UnitMana = _G.UnitMana
local UnitManaMax = _G.UnitManaMax
local UnitIsPlayer = _G.UnitIsPlayer
local UnitIsFriend = _G.UnitIsFriend
local GetNumRaidMembers = _G.GetNumRaidMembers
local GetNumPartyMembers = _G.GetNumPartyMembers
local min = _G.min
local pairs = _G.pairs
local ipairs = _G.ipairs
local gsub = _G.gsub
local tonumber = _G.tonumber
local format = _G.format
local unpack = _G.unpack
local type = _G.type

self.title = "InvenRaidFrames"
self.version = GetAddOnMetadata("InvenRaidFrames", "Version")
self.website = GetAddOnMetadata("InvenRaidFrames", "X-Website")
self.icon = "Interface\\AddOns\\InvenRaidFrames\\Texture\\Icon"
self.vars = {
	modules = {}, frames = {}, unit = {}, name = {}, prev = {}, group = {}, frame = {}, classDB = {}, names = {},
	party = { 0, 0, 0, 0, 0, 0, 0, 0, [0] = 0 }, range = {}, tag = {}, tag2 = {}, eventHandler = {},
	playerGroup = 0, maxGroup = 0, member = { raid = 0, party = 0 }, ata = {}, dispel = {}, pet = {}, incombat = {},
	playerIsVisible = false, isForce = true, showMainFrame = false, init = false, buffcheck = {}, playdebuff = 0,
	skipdebuff = {
		["순간이동기 기능장애"] = 1, ["참을성"] = 1, ["약화된 영혼"] = 1, ["붕대 치료"] = 1, ["유령"] = 1, ["탈영병"] = 1, ["전투 불참"] = 1, ["죽은척하기"] = 1,
		["고뇌의 오라"] = 1, ["욕망의 오라"] = 1, ["격노의 오라"] = 1, ["변화의 오라"] = 1, ["영혼 분열: 악"] = 1, ["영혼 분열: 선"] = 1, ["비전 작렬"] = 1, ["최근 게임 참여"] = 1,
		["저체온증"] = 1, ["숙면"] = 1, ["최상급 숙면"] = 1, ["불안정한 고통"] = 1, ["광택낸 갑옷"] = 1, ["피의 격노"] = 1,
	}
}
if not BluePrint then function BluePrint() end end

BINDING_HEADER_INVENRAIDFRAMES = "인벤 레이드 프레임"
BINDING_NAME_INVENRAIDFRAMES_TOGGLE = "설정창 열기/닫기"
BINDING_NAME_INVENRAIDFRAMES_DOREADYCHECK = "전투 준비 상황 확인"
BINDING_NAME_INVENRAIDFRAMES_BUFF = "버프 확인 토글"

local consoleOptions = {
	name = "인벤 레이드 프레임",
	desc = "공격대 프레임",
	type = "group",
	args = {
		config = {
			type = "execute",
			name = "설정",
			desc = "설정창을 열고 닫습니다.",
			order = 10,
			func = function() self:OnMMButtonClick() end,
		},
		doreadycheck = {
			type = "execute",
			name = "전투 준비 확인",
			desc = "전투 준비 확인을 합니다. 파티장이나 공격대장 또는 승급자 이상의 권한이 필요합니다.",
			order = 20,
			func = function() DoReadyCheck() end,
			disabled = function() return not self:IsReadyCheckable() end,
		},
		button = {
			type = "toggle",
			name = "미니맵 버튼 보이기",
			desc = "미니맵 버튼을 보이고 숨깁니다.",
			order = 200,
			get = function() return self.db.profile.showMM end,
			set = function()
				self.db.profile.showMM = not self.db.profile.showMM
				if not IRF_FuBar then
					self:ToggleMinimapButton()
				end
			end,
			hidden = function() return FuBar and IRF_FuBar end,
		},
		buttonlock = {
			type = "toggle",
			name = "미니맵 버튼 잠그기",
			desc = "미니맵 버튼을 잠급니다.",
			order = 210,
			get = function() return not self.db.profile.LibMMButton.dragable end,
			set = function()
				self.db.profile.LibMMButton.dragable = not self.db.profile.LibMMButton.dragable
			end,
			hidden = function() return FuBar and IRF_FuBar end,
		},
	},
}

function InvenRaidFrames:OnInitialize()
	self.db = LibStub("AceDB-3.0"):New("InvenRaidFramesDB", {
		profile = {
			updateTime = 0.05, lock = false, anchor = "TOPLEFT",
			unitWidth = 100, unitHeight = 32, scale = 1.0, barTexture = "Smooth",
			use = "항상", outline = "디버프",
			rangeAlpha = 0, healthAlpha = 1, healthBGAlpha = 0, healAlpha = 0.35, borderAlpha = 1, textAlpha = false, manaAlpha = false,
			tooltip = "비전투 중에만", redcolor = true, font = SM:GetDefault("font"), fontSize = 12, fontAttribute = "그림자",
			pos = { "CENTER", 0, 0 },  top = true, showGroup = "자동", attack = true, spspell = true, dmanabar = false,
			raiddebuff = true, debufficon = false, debuffAlpha = 0.65, debuffloc = "우측 상단", debuffcolor = true, debuffsize = 18,
			usedebuff = true, debuffnum = "1", debuffsize2 = 18, debuffAlpha2 = 0.65, debuffloc2 = "우측 하단", debufftype = "디버프 아이콘", debuffcount = true,
			ordertype = "파티", memberorder = "세로", grouporder = "가로", groupnum = 4, memberorder2 = "세로", membernum = 10, hidetemp = true, tag = true,
			classcolor = false, textcolor = true, maxmember = 40, offset = 0, showaggro = true,
			losthp = "항상", losthp2 = "한줄 표시", losthp3 = false, losthpcolor = false,
			yourHeal = true, inheal = true, inheal2 = true, namelen = "5", showmana = true, manaper = 0.15,
			raidicon = true, raidicontarget = true, raidiconloc = "우측 하단", raidiconsize = 12, raidicontop = true,
			healloc = "좌측 하단", showMM = true, moalpha = 0.3, showbg = true, lowhp = 75,
			classorder = "WARRIOR,DRUID,PALADIN,PRIEST,SHAMAN,ROGUE,MAGE,WARLOCK,HUNTER,DEATHKNIGHT",
			classorders = { "전사", "드루이드", "성기사", "사제", "주술사", "도적", "마법사", "흑마법사", "사냥꾼", "죽음의 기사" },
			color = {
				unitbg = { 0, 0, 0, 0 }, bg = { 0, 0, 0, 0.2 }, border = { 0.3, 0.3, 0.3, 1 },
				myparty = { 0.8, 0.12, 0.28 }, outline = { 1, 1, 1, 1 },
				healicon = { 0, 1, 0 }, healicon2 = { 0, 0.8, 0 },
				health = { 0, 1, 0 }, mana = { 0, 0.34, 1 }, rage = { 1, 0.26, 0 }, energy = { 1, 1, 0 }, focus = { 0.8, 0.8, 0 }, runes = { 0.5, 0.5, 0.5 }, runic = { 0, 0.82, 1 },
				Curse = { 0.6, 0, 1 }, 	Magic = { 1, 1, 1 }, Disease = { 0.6, 0.4, 0 }, Poison = { 0, 0.25, 0 }, Normal = { 0.2, 0.2, 0.2 },
				WARRIOR = { 0.78, 0.61, 0.43 }, ROGUE = { 1, 0.96, 0.41 }, PRIEST = { 1, 1, 1 },
				MAGE = { 0.41, 0.8, 0.94 }, WARLOCK = { 0.58, 0.51, 0.79 }, HUNTER = { 0.67, 0.83, 0.45 },
				DRUID = { 1, 0.49, 0.04 }, SHAMAN = { 0.14, 0.35, 1 },	PALADIN = { 0.96, 0.55, 0.73 }, DEATHKNIGHT = { 0.77, 0.12, 0.23 },
				aggro = { 1, 0, 0 }, aggro2 = "|cffff0000", losthp = { 1, 0, 0 }, losthp2 = "|cffff0000",
			},
			LibMMButton = { dragable = true, angle = 0, radius = 80, rounding = 10 },
			aggrogain = "IRF: 어그로 획득", aggrolost = "IRF: 어그로 손실",
			readycheck = true, readycheckloc = "중앙", readycheckft1 = 10, readycheckft2 = 1.5, readychecksize = 25, readychecktop = true,
			petorder = "세로", petline = 5, pospet = { "CENTER", 0, 0 },
			usersound = {}, useQuickHealth = true,
		},
		char = {
			clickheal = {
				["BUTTON1"] = "대상 선택", ["ALT-BUTTON1"] = "대상 선택", ["CTRL-BUTTON1"] = "대상 선택", ["SHIFT-BUTTON1"] = "대상 선택", ["ALT-CTRL-BUTTON1"] = "대상 선택", ["ALT-SHIFT-BUTTON1"] = "대상 선택", ["CTRL-SHIFT-BUTTON1"] = "대상 선택",
				["BUTTON2"] = "메뉴",      ["ALT-BUTTON2"] = "메뉴",      ["CTRL-BUTTON2"] = "메뉴",      ["SHIFT-BUTTON2"] = "메뉴",	   ["ALT-CTRL-BUTTON1"] = "메뉴",      ["ALT-SHIFT-BUTTON2"] = "메뉴",      ["CTRL-SHIFT-BUTTON1"] = "메뉴",
				["BUTTON3"] = "없음",	   ["ALT-BUTTON3"] = "없음",	  ["CTRL-BUTTON3"] = "없음",	  ["SHIFT-BUTTON3"] = "없음",	   ["ALT-CTRL-BUTTON1"] = "없음",      ["ALT-SHIFT-BUTTON3"] = "없음",      ["CTRL-SHIFT-BUTTON1"] = "없음",
				["BUTTON4"] = "없음",	   ["ALT-BUTTON4"] = "없음",	  ["CTRL-BUTTON4"] = "없음",	  ["SHIFT-BUTTON4"] = "없음",	   ["ALT-CTRL-BUTTON4"] = "없음",      ["ALT-SHIFT-BUTTON4"] = "없음",      ["CTRL-SHIFT-BUTTON4"] = "없음",
				["BUTTON5"] = "없음",	   ["ALT-BUTTON5"] = "없음",	  ["CTRL-BUTTON5"] = "없음",	  ["SHIFT-BUTTON5"] = "없음",	   ["ALT-CTRL-BUTTON5"] = "없음",      ["ALT-SHIFT-BUTTON5"] = "없음",      ["CTRL-SHIFT-BUTTON5"] = "없음",
				["BUTTON6"] = "없음",	   ["ALT-BUTTON6"] = "없음",	  ["CTRL-BUTTON6"] = "없음",	  ["SHIFT-BUTTON6"] = "없음",	   ["ALT-CTRL-BUTTON6"] = "없음",      ["ALT-SHIFT-BUTTON6"] = "없음",      ["CTRL-SHIFT-BUTTON6"] = "없음",
				["BUTTON7"] = "없음",	   ["ALT-BUTTON7"] = "없음",	  ["CTRL-BUTTON7"] = "없음",	  ["SHIFT-BUTTON7"] = "없음",	   ["ALT-CTRL-BUTTON7"] = "없음",      ["ALT-SHIFT-BUTTON7"] = "없음",      ["CTRL-SHIFT-BUTTON7"] = "없음",
				["BUTTON8"] = "없음",	   ["ALT-BUTTON8"] = "없음",	  ["CTRL-BUTTON8"] = "없음",	  ["SHIFT-BUTTON8"] = "없음",	   ["ALT-CTRL-BUTTON8"] = "없음",      ["ALT-SHIFT-BUTTON8"] = "없음",      ["CTRL-SHIFT-BUTTON8"] = "없음",
				["BUTTON9"] = "없음",	   ["ALT-BUTTON9"] = "없음",	  ["CTRL-BUTTON9"] = "없음",	  ["SHIFT-BUTTON9"] = "없음",	   ["ALT-CTRL-BUTTON9"] = "없음",      ["ALT-SHIFT-BUTTON9"] = "없음",      ["CTRL-SHIFT-BUTTON9"] = "없음",
			},
			macro = {}, other = {}, showIRF = true,
			spelltimer = "아이콘", spelltimer2 = true, showSpell = { true, true, true }, showSpellTime = { true, true, true }, pmCount = true,
			aggrosound = "사용 안함", pet = false, petshow = "파티",
			checkbuff = { use = true, spring = true, combat = false, zone1 = true, zone2 = true, zone3 = true, zone4 = true, size = 15, alpha = 0.7, pos = "상단", pet = false, toggle = true, togglemode = false },
			debuffsound = { cc = false, use = false, range = "모두", update = 1, Curse = false, Magic = false, Disease = false, Poison = false, Normal = false, sound = { Curse = "IRF: 디버프", Magic = "IRF: 디버프", Disease = "IRF: 디버프", Poison = "IRF: 디버프", Normal = "IRF: 디버프", zone1 = true, zone2 = true, zone3 = true, zone4 = true } },
		},
	}, "Default")
	self.db.profile.classorder = gsub(self.db.profile.classorder, "흑MAGE", "WARLOCK")
	LibStub("AceConfig-3.0"):RegisterOptionsTable("InvenRaidFrames", consoleOptions, "irf", "invenraidframes")
	LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("InvenRaidFramesProfile", LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db))
	self.optFrame = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("InvenRaidFramesProfile", "인벤 레이드 프레임")
	self.db.RegisterCallback(self, "OnProfileChanged", "UpdateProfile")
	self.db.RegisterCallback(self, "OnProfileCopied", "UpdateProfile")
	self.db.RegisterCallback(self, "OnProfileReset", "UpdateProfile")
	self:CheckModule()
	self.vars.member.raid = GetNumRaidMembers()
	self.vars.member.party = GetNumPartyMembers()
	for p, v in pairs(UnitPopupMenus) do
		for i = 1, #v do
			if v[i] == "SET_FOCUS" then
				tremove(UnitPopupMenus[p], i)
				break
			end
		end
	end
	for i = 1, #UnitPopupMenus.FRIEND do
		if UnitPopupMenus.FRIEND[i] == "TARGET" then
			tremove(UnitPopupMenus.FRIEND, i)
			break
		end
	end
end

function InvenRaidFrames:CreateMinimapButton()
	local function addButton(level, text, ...)
		local info = UIDropDownMenu_CreateInfo()
		info.text = text
		local args = { ... }
		for i = 1, #(args), 2 do
			if args[i] == "tooltip" then
				info.tooltipTitle = text
				info.tooltipText = args[i + 1]
			else
				info[args[i]] = args[i + 1]
			end
		end
		UIDropDownMenu_AddButton(info, level)
	end
	function InvenRaidFrames.initDropDown(level)
		level = tonumber(level or 1) or 1
		if level == 1 then
			addButton(level, "인벤 레이드 프레임", "isTitle", 1)
			addButton(level, "사용", "func", function() self.db.char.showIRF = not self.db.char.showIRF self:RosterUpdate() end, "checked", function() return self.db.char.showIRF end, "tooltip", "IRF를 사용하거나 사용하지 않습니다.")
			addButton(level, "설정창 열기", "func", consoleOptions.args.config.func, "tooltip", consoleOptions.args.config.desc)
			addButton(level, "전투 준비 확인", "func", consoleOptions.args.doreadycheck.func, "tooltip", consoleOptions.args.doreadycheck.desc)
		end
	end
	self:CreateMMButton()
	self:SetMMButtonIcon(self.icon)
	self:SetMMButtonDropDownMenu(self.initDropDown)
	self:SetMinimapButtonText()
	self:ToggleMinimapButton()
end

function InvenRaidFrames:ToggleMinimapButton()
	if not self:IsEnableModule("FuBar") then
		if self.db.profile.showMM then
			self:ShowMMButton()
		else
			self:HideMMButton()
		end
	end
end

function InvenRaidFrames:SetMinimapButtonText()
	if not IRF_FuBar then
		local tt = "|cffffffff"..self.website.."\n|cffffff00클릭: 설정창 열기"
		if self.db.profile.readycheck and self:HasModule("ReadyCheck") then
			if self:IsReadyCheckable() then
				tt = tt.."\nCtrl + 클릭: 전투 준비 확인"
			else
				tt = tt.."\n|cff9f9f9fCtrl + 클릭: 전투 준비 확인"
			end
		end
		if self.db.char.checkbuff.togglemode then
			tt = tt.."\n|cffffff00Alt + 클릭: 버프 확인"
		end
		self:SetMMButtonTooltip(self.title.." v"..self.version, tt.."|r")
	end
end

function InvenRaidFrames:OnEnable()
	if not self.vars.init then
		self.vars.init = true
		if not self.vars.group.m then
			self:CreateMainFrame()
			for i = 0, 10 do
				self:CreateGroup(i)
			end
			if FuBar and self:HasModule("FuBar") then
				self:EnableModule("FuBar")
			else
				self:CreateMinimapButton()
			end
		end
		if self.db.profile.use == "항상" or (self.db.profile.use == "파티" and (self.vars.member.party > 0 or self.vars.member.raid > 0)) or (self.db.profile.use == "공격대" and self.vars.member.raid > 0) then
			self.vars.showMainFrame = true
		else
			self.vars.showMainFrame = false
			self:SendMessage("InvenRaidFrames_HideAll")
		end
		self:GroupSetPoint()
		self:PetModule()
		self:RosterUpdate()
		if IsLoggedIn() and not initLogin then
			self:PLAYER_LOGIN()
		else
			self:RegisterEvent("PLAYER_LOGIN")
		end
		self:SendMessage("InvenRaidFrames_Enabled")
	end
end

function InvenRaidFrames:OnDisable()
	if self.vars.init then
		self.vars.init = false
		initLogin = false
		self:UnregisterEvents()
		self:UnregisterAllEvents()
		self:PetModule()
		self:HideFrame()
		self:SendMessage("InvenRaidFrames_Disabled")
	end
end

function InvenRaidFrames:PLAYER_LOGIN()
	if initLogin then return end
	initLogin = true
	for sound, file in pairs(self.db.profile.usersound) do
		SM:Register("sound", sound, file)
	end
	self.vars.playerName = UnitName("player")
	self.vars.member.raid = GetNumRaidMembers()
	self.vars.member.party = GetNumPartyMembers()
	local c = UnitClass("player")
	if InvenRaidFramesDispelDB == nil then
		InvenRaidFramesDispelDB = {
			Curse = (c == "마법사" or c == "드루이드") and true or false,
			Magic = (c == "성기사" or c == "사제") and true or false,
			Disease = (c == "성기사" or c == "사제" or c == "주술사") and true or false,
			Poison = (c == "성기사" or c == "드루이드" or c == "주술사") and true or false,
			Normal = false,
		}
	end
	if not InvenRaidFramesDispelDB.outline then
		InvenRaidFramesDispelDB.outline = {
			Curse = (c == "마법사" or c == "드루이드") and true or false,
			Magic = (c == "성기사" or c == "사제") and true or false,
			Disease = (c == "성기사" or c == "사제" or c == "주술사") and true or false,
			Poison = (c == "성기사" or c == "드루이드" or c == "주술사") and true or false,
			Normal = false,
		}
	end
	if self.db.char.debuffsound.cc == false then
		self.db.char.debuffsound.cc = true
		self.db.char.debuffsound.Curse = (c == "마법사" or c == "드루이드") and true or false
		self.db.char.debuffsound.Magic = (c == "성기사" or c == "사제") and true or false
		self.db.char.debuffsound.Disease = (c == "성기사" or c == "사제" or c == "주술사") and true or false
		self.db.char.debuffsound.Poison = (c == "성기사" or c == "드루이드" or c == "주술사") and true or false
		self.db.char.debuffsound.Normal = false
	end
	if InvenRaidFramesCharDB and InvenRaidFramesCharDB.global then
		local db = InvenRaidFramesCharDB.global
		if db.macro then
			self.db.char.macro = db.macro
		end
		if db.clickheal then
			for p, v in pairs(db.clickheal) do
				if v then
					self.db.char.clickheal[p] = v
				end
			end
		end
		if db.other then
			self.db.char.other = db.other
		end
		if db.showSpell then
			self.db.char.showSpell = { db.showSpell[1] or true, db.showSpell[2] or true, db.showSpell[3] or true }
		end
		if db.showSpellTime then
			self.db.char.showSpellTime = { db.showSpellTime[1] or true, db.showSpellTime[2] or true, db.showSpellTime[3] or true }
		end
		if db.pmCount then
			self.db.char.pmCount = false
		end
		InvenRaidFramesCharDB = nil
	end
	self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
	self:RegisterEvent("RAID_ROSTER_UPDATE", "RosterChange")
	self:RegisterEvent("PARTY_MEMBERS_CHANGED", "RosterChange")
	self:RegisterEvent("LEARNED_SPELL_IN_TAB", "ScanSpell")
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:RegisterEvent("READY_CHECK")
	self:InitPlayerClassDB()
	self:ScanSpell()
	self:ZONE_CHANGED_NEW_AREA()
	if self.db.profile.useQuickHealth then
		self:SetQuickHealth()
	end
end

function InvenRaidFrames:CallbackTimer(callback, delay, ...)
	self:CancelCallbackTimer(callback)
	self.vars.eventHandler[callback] = self:ScheduleTimer(callback, delay, ...)
end

function InvenRaidFrames:RepeatCallbackTimer(callback, delay, arg)
	self:CancelCallbackTimer(callback)
	self.vars.eventHandler[callback] = self:ScheduleRepeatingTimer(callback, delay, arg)
end

function InvenRaidFrames:CancelCallbackTimer(callback)
	if self.vars.eventHandler[callback] then
		self:CancelTimer(self.vars.eventHandler[callback], true)
		self.vars.eventHandler[callback] = nil
	end
end

function InvenRaidFrames:SetUpdateTime(value)
	self:RepeatCallbackTimer("OnUpdateUnitFrame", value or self.db.profile.updateTime)
end

function InvenRaidFrames:RegisterEvents()
	if not initEvent then
		initEvent = true
		self:RegisterEvent("RAID_TARGET_UPDATE")
		if HealComm then
			HealComm.RegisterCallback(self, "HealComm_DirectHealStart")
			HealComm.RegisterCallback(self, "HealComm_DirectHealDelayed")
			HealComm.RegisterCallback(self, "HealComm_DirectHealStop")
			HealComm.RegisterCallback(self, "HealComm_HealModifierUpdate")
		end
		self:SetUpdateTime()
	end
end

function InvenRaidFrames:UnregisterEvents()
	if initEvent then
		initEvent = false
		self:UnregisterEvent("RAID_TARGET_UPDATE")
		if HealComm then
			HealComm.UnregisterCallback(self, "HealComm_DirectHealStart")
			HealComm.UnregisterCallback(self, "HealComm_DirectHealStop")
			HealComm.UnregisterCallback(self, "HealComm_DirectHealDelayed")
			HealComm.UnregisterCallback(self, "HealComm_HealModifierUpdate")
		end
		self:CancelCallbackTimer("OnUpdateUnitFrame")
	end
end

do

function InvenRaidFrames:InitUnits()
	self.vars.unit = {}
	self.vars.name = {}
	self.vars.range = {}
	self.vars.ata = {}
	self.vars.incombat = {}
	self.vars.pet = {}
	self.vars.maxGroup = 0
	for _, frame in pairs(self.vars.frames) do
		local unit = frame.unit
		if unit then
			local fullname = self:GetUnitFullName(unit)
			self.vars.unit[unit] = frame
			self.vars.name[fullname or "*"] = unit
			if UnitIsPlayer(unit) then
				if self.vars.member.raid > 0 then
					if strfind(unit, "raid") then
						local id = gsub(unit, "raid", "")
						if tonumber(id) then
							local group = select(3, GetRaidRosterInfo(tonumber(id)))
							self.vars.maxGroup = max(self.vars.maxGroup, group)
							if UnitIsUnit(unit, "player") then
								self.vars.playerGroup = group
								self.vars.tag[0].text:SetText("내 파티("..group..")")
								self.vars.tag2[0].text:SetText("P\n"..group)
							end
						end
					end
				end
			else
				self.vars.pet[unit] = frame
			end
			if frame.unitName == nil or frame.unitName ~= fullname then
				frame.unitName = fullname
				self:UpdateUnit(unit)
			end
		end
	end
	if self.vars.member.raid == 0 then
		self.vars.tag[0].text:SetText("내 파티")
		self.vars.tag2[0].text:SetText("P")
	end
	self:TagUpdate()
	self:UpdateBorder()
	self:BuffModule()
	self:SendMessage("InvenRaidFrames_InitUnits")
end

function InvenRaidFrames:RosterChange()
	self.vars.member.raid = GetNumRaidMembers()
	self.vars.member.party = GetNumPartyMembers()
	if self.vars.member.raid == 0 then
		self.vars.maxGroup = 0
		self.vars.playerGroup = 0
	end
	self.FrameOnDragStop()
	self:SetMinimapButtonText()
	self:SendMessage("InvenRaidFrames_RosterChange")
	self:CallbackTimer("RosterUpdate", 0.1)
end

function InvenRaidFrames:RosterUpdate()
	self.FrameOnDragStop()
	if self.db.char.showIRF and (self.db.profile.use == "항상" or (self.db.profile.use == "파티" and (self.vars.member.party > 0 or self.vars.member.raid > 0)) or (self.db.profile.use == "공격대" and self.vars.member.raid > 0)) then
		if not self.vars.showMainFrame then
			self:CallbackTimer("UpdateUnit", 0.9)
		end
		self.vars.showMainFrame = true
		self:RegisterEvents()
		for i = 1, self.vars.member.raid do
			local sg = select(3, GetRaidRosterInfo(i))
			self.vars.party[sg] = self.vars.party[sg] + 1
			if UnitIsUnit("player", "raid"..i) then
				self.vars.playerGroup = sg
			end
		end
		self:TagUpdate()
		self:UpdateGroupSetPoint()
		if clear and (self.vars.member.party >= self.db.profile.maxmember or self.vars.member.raid >= self.db.profile.maxmember) then
			clear = false
			self:ClearMemory()
		end
	else
		self.vars.showMainFrame = false
		self:UnregisterEvents()
		self.vars.unit = {}
		self.vars.name = {}
		self.vars.range = {}
		self:HideFrame()
	end
	if self.vars.member.party == 0 and self.vars.member.raid == 0 then
		first = true
		clear = true
		self.vars.names = {}
		self.vars.range = {}
		self:UNIT_NAME_UPDATE(self, "player")
		if self.db.char.pet and self:IsEnableModule("Pet") and UnitExists("pet") then
			self:UNIT_NAME_UPDATE(self, "pet")
		end
	end
	self:CallbackTimer("UpdateBorder", 0.1)
	self:SendMessage("InvenRaidFrames_RosterUpdate")
end

function InvenRaidFrames:GetUnitFullName(unit)
	if UnitExists(unit) then
		local name, realm = UnitName(unit)
		local isPet = UnitIsPlayer(unit) and "" or "!"
		return isPet..((realm and realm ~= "") and (name.."-"..realm) or name)
	else
		return nil
	end
end

function InvenRaidFrames:GetUnitHealthPercent(unit, hp)
	local maxhp = UnitHealthMax(unit) or 0
	local percent, losthp = 0, 0
	if maxhp > 1 then
		local uhp = UnitHealth(unit)
		percent = (hp and (uhp + hp) or uhp) / maxhp * 100
		losthp = maxhp - uhp
	end
	return percent < 100 and floor(percent) or 100, losthp
end

function InvenRaidFrames:GetUnitManaPercent(unit)
	local maxmp = UnitManaMax(unit) or 0
	local percent = 0
	if maxmp > 0 then
		percent = UnitMana(unit) / maxmp * 100
	end
	return percent < 100 and percent or 100
end

end

function InvenRaidFrames:InitPlayerClassDB()
	local bco
	self.vars.class = UnitClass("player")
	if self.vars.class == "전사" then
		self.vars.classDB = {
			clickheal = { ["가로막기"] = 1, ["경계"] = 1 },
		}
	elseif self.vars.class == "사제" then
		self.vars.classDB = {
			range = "하급 치유",
			buff = { ["신의 권능: 인내"] = 1, ["인내의 기원"] = 1, ["천상의 정신"] = 2, ["정신력의 기원"] = 2, ["어둠의 보호"] = 3, ["암흑 보호의 기원"] = 3, ["공포의 수호물"] = 3, ["고통 억제"] = 3 },
			spell = { ["소생"] = -1, ["회복의 기원"] = 2, ["약화된 영혼"] = 3 },
			spellTimer = { true, true },
			clickheal = { ["수호 영혼"] = 1, ["치유의 마법진"] = 1, ["고통 억제"] = 1, ["마력 주입"] = 1, ["마법 무효화"] = 1, ["신의 권능: 보호막"] = 1, ["결속의 치유"] = 1, ["부활"] = 1, ["상급 치유"] = 1, ["순간 치유"] = 1, ["질병 해제"] = 1, ["회개"] = 1, },
		}
		self.vars.dispel = { ["Magic"] = true, ["Disease"] = true }
		self.vars.buffcheck = { "인내의 기원", "정신력의 기원", "암흑 보호의 기원" }
		bco = { true, true, false }
	elseif self.vars.class == "마법사" then
		self.vars.classDB = {
			range = "저주 해제",
			buff = { ["신비한 지능"] = 1, ["신비한 총명함"] = 1, ["마법 증폭"] = 2, ["마법 감쇠"] = 2 },
			clickheal = { ["저주 해제"] = 1, ["변이"] = 1 },
		}
		self.vars.dispel = { ["Curse"] = true }
		self.vars.buffcheck = { "신비한 총명함", "마법 증폭", "마법 감쇠" }
		bco = { true, false, false }
	elseif self.vars.class == "흑마법사" then
		self.vars.classDB = {
			range = "투명체 감지",
			buff = { ["영혼석 부활"] = 1 },
			clickheal = { ["투명체 감지"] = 1, ["소환 의식"] = 1, ["영원의 숨결"] = 1 },
		}
		self.vars.buffcheck = { "영혼석 부활", "투명체 감지", "영원의 숨결" }
		bco = { true, false, false }
	elseif self.vars.class == "사냥꾼" then
		self.vars.classDB = {
			spell = { ["눈속임"] = -1 },
			spellTimer = { true },
		}
	elseif self.vars.class == "드루이드" then
		self.vars.classDB = {
			range = "치유의 손길",
			buff = { ["야생의 징표"] = 1, ["야생의 선물"] = 1, ["가시"] = 2 },
			spell = { ["피어나는 생명"] = -1, ["회복"] = -2, ["재생"] = -3 },
			spellTimer = { true, true, true },
			clickheal = { ["신속한 치유"] = 1, ["치유의 손길"] = 1, ["정신 자극"] = 1, ["환생"] = 1, ["독 해제"] = 1, ["저주 해제"] = 1, ["급속 성장"] = 1, ["되살리기"] = 1, ["육성"] = 1 },
		}
		self.vars.dispel = { ["Curse"] = true, ["Poison"] = true }
		self.vars.buffcheck = { "야생의 선물", "가시" }
		bco = { true, false }
	elseif self.vars.class == "주술사" then
		self.vars.classDB = {
			range = "치유의 물결",
			clickheal = { ["대지의 보호막"] = 1, ["물의 보호막"] = 1, ["고대의 영혼"] = 1, ["연쇄 치유"] = 1, ["질병 치료"] = 1, ["해독"] = 1, ["치유의 물결"] = 1, ["하급 치유의 물결"] = 1, ["수중 호흡"] = 1, ["수면 걷기"] = 1, ["정화"] = 1, ["영혼 정화"] = 1, ["정신의 고리"] = 1 },
			spell = { ["성난 해일"] = -2 },
		}
		self.vars.dispel = { ["Disease"] = true, ["Poison"] = true }
		self.vars.buffcheck = { "대지의 보호막", "물의 보호막" }
		bco = { true, true }
	elseif self.vars.class == "성기사" then
		self.vars.classDB = {
			range = "성스러운 빛",
			buff = {  ["힘의 축복"] = 1, ["상급 힘의 축복"] = 1, ["지혜의 축복"] = 1, ["상급 지혜의 축복"] = 1,
				 ["왕의 축복"] = 1, ["상급 왕의 축복"] = 1, ["성역의 축복"] = 1, ["상급 성역의 축복"] = 1,
			},
			spell = { ["보호의 손길"] = -1, ["자유의 손길"] = -2, ["빛의 봉화"] = -3 },
			spellTimer = { true, true, true },
			clickheal = { ["성스러운 보호막"] = 1, ["희생의 손길"] = 1, ["구원의 손길"] = 1, ["정화"] = 1, ["순화"] = 1, ["성스러운 중재"] = 1, ["빛의 섬광"] = 1, ["성스러운 빛"] = 1, ["신성 충격"] = 1, ["신의 축복"] = 1, ["구원"] = 1, ["정의의 방어"] = 1, ["빛의 봉화"] = 1 },
		}
		self.vars.dispel = { ["Magic"] = true, ["Disease"] = true, ["Poison"] = true }
		self.vars.buffcheck = { "사용 안함", "힘의 축복", "지혜의 축복", "왕의 축복", "성역의 축복" }
	end
	self.vars.classDB.importantBuff = {
		["방패의 벽"] = "<방벽>", ["최후의 저항"] = "<최저>",
		["회피"] = "<회피>", ["그림자 망토"] = "<그망>",
		["천상의 보호막"] = "<무적>", ["보호의 축복"] = "<보축>",
		["얼음 방패"] = "<얼방>", ["죽은척하기"] = "<죽척>",
		["성스러운 중재"] = "<중재>", ["구원의 영혼"] = "<구원>",
		["수호 영혼"] = "<수호>", ["분산"] = "<분산>",
		["생존 본능"] = "<최저>",
	}
	if not self.vars.classDB then self.vars.classDB = {} end
	if not self.vars.classDB.buff then self.vars.classDB.buff = {} end
	if not self.vars.classDB.clickheal then self.vars.classDB.clickheal = {} end
	if not self.vars.classDB.spell then self.vars.classDB.spell = {} end
	if not self.vars.classDB.spellTimer then self.vars.classDB.spellTimer = {} end
	if InvenRaidFramesBuffCheckDB == nil then
		InvenRaidFramesBuffCheckDB = {}
		if self.vars.class == "성기사" then
			local list = { "전사", "드루이드", "성기사", "사제", "주술사", "도적", "마법사", "흑마법사", "사냥꾼" }
			for i = 1, #(list) do
				InvenRaidFramesBuffCheckDB[list[i]] = "확인 안함"
			end
		elseif bco then
			for i = 1, #(self.vars.buffcheck) do
				InvenRaidFramesBuffCheckDB[self.vars.buffcheck[i]] = bco[i]
			end
			if self.vars.class == "흑마법사" or self.vars.class == "주술사" then
				self.db.char.checkbuff.spring = false
			end
		end
	end
end

function InvenRaidFrames:ZONE_CHANGED_NEW_AREA()
	local z = GetRealZoneText()
	if z == "강제 노역소" then
		self.vars.classDB.importantDebuff = { ["치명상"] = 1 }
	elseif z == "메카나르" then
		self.vars.classDB.importantDebuff = { ["양전하"] = 1, ["음전하"] = 1 }
	elseif z == "카라잔" then
		self.vars.classDB.importantDebuff = { ["목조르기"] = 1, ["신성한 불꽃"] = 1, ["참회"] = 1, ["빨간 두건"] = 1, ["희생"] = 1 }
	elseif z == "줄아만" then
		self.vars.classDB.importantDebuff = { ["치명상"] = 1, ["짓이기기"] = 1, ["전하 폭풍"] = 1, ["영혼 착취"] = 1, ["섬뜩한 마비"] = 1, ["광기의 발톱"] = 1, }
	elseif z == "불뱀 제단" then
		self.vars.classDB.importantDebuff = { ["정신 지배"] = 1, ["소용돌이"] = 1, ["음흉한 속삭임"] = 1, ["수중 무덤"] = 1, ["타락의 진흙"] = 1, ["전하 충전"] = 1 }
	elseif z == "폭풍우 요새" then
		self.vars.classDB.importantDebuff = { ["방어구 녹이기"] = 1, ["점성술사의 분노"] = 1, ["정신 지배"] = 1, ["원격조종 장난감"] = 1 }
	elseif z == "하이잘 정상" then
		self.vars.classDB.importantDebuff = { ["얼음 화살"] = 1, ["수면"] = 1, ["죽음의 부패"] = 1, ["흡혈박쥐 떼"] = 1, ["억제할 수 없는 불길"] = 1, ["아즈갈로의 울부짖음"] = 1, ["파멸"] = 1, ["파멸의 불"] = 1, ["군단의 손아귀"] = 1 }
	elseif z == "검은 사원" then
		self.vars.classDB.importantDebuff = { ["꿰뚫는 돌기"] = 1, ["소각"] = 1, ["죽음의 어둠"] = 1, ["마의 분노"] = 1, ["끓어오르는 피"] = 1, ["산성 상처"] = 1, ["지옥 산성 숨결"] = 1, ["치명적인 매력"] = 1, ["쇠약"] = 1, ["어둠의 흡혈마귀"] = 1, ["베어내기"] = 1, ["맹독"] = 1, ["영혼 흡수"] = 1, ["신성한 격노"] = 1, ["고뇌의 불꽃"] = 1, ["암흑의 보호막"] = 1 }
	elseif z == "태양샘 고원" then
		self.vars.classDB.importantDebuff = { ["정신 세계"] = 1, ["영혼의 피로"] = 1, ["불사르기"] = 1, ["가두기"] = 1, ["어둠"] = 1, ["발열"] = 1, ["유성 베기"] = 1, ["혼란의 강타"] = 1, ["거대한 불길"] = 1, ["불타는 화염"] = 1, ["화염의 손길"] = 1, ["화염 불꽃"] = 1, ["불꽃 화살"] = 1 }
	else
		self.vars.classDB.importantDebuff = {}
	end
	local zoneMember = {
		["알터랙 계곡"] = 40, ["아라시 분지"] = 15, ["전쟁노래 협곡"] = 10, ["폭풍의 눈"] = 20,
		["카라잔"] = 10, ["줄아만"] = 10, ["그룰의 둥지"] = 25, ["마그테리돈의 둥지"] = 25,
		["불뱀 제단"] = 25, ["폭풍우 요새"] = 25, ["하이잘 정상"] = 25, ["검은 사원"] = 25, ["태양샘 고원"] = 25,
		["화산심장부"] = 40, ["화산 심장부"] = 40, ["오닉시아의 둥지"] = 40, ["검은날개 둥지"] = 40, ["줄구룹"] = 20,
		["안퀴라즈 폐허"] = 20, ["안퀴라즈 사원"] = 40, ["낙스라마스"] = 40,
	}
	local prevmember = self.db.profile.maxmember
	if IsInInstance() then
		self.db.profile.maxmember = zoneMember[z] or 5
	else
		self.db.profile.maxmember = 40
	end
	if prevmember ~= self.db.profile.maxmember then
		self:RosterUpdate()
	end
end

function InvenRaidFrames:OnMMButtonClick()
	if IsControlKeyDown() and self:HasModule("ReadyCheck") then
		if self:IsReadyCheckable() and self:EnableModule("ReadyCheck") then
			DoReadyCheck()
		end
	elseif IsAltKeyDown() and self.db.char.checkbuff.togglemode and self:IsEnableModule("Buff") then
		IRF_Buff:ToggleBuff()
	elseif self:EnableModule("Options") then
		IRF_Options:ToggleMenu()
	end
end

function InvenRaidFrames:IsReadyCheckable()
	local instype = select(2, IsInInstance())
	return self.vars.modules["ReadyCheck"] and self.db.profile.readycheck and (self.vars.member.party > 0 or self.vars.member.raid > 0) and (IsPartyLeader() or IsRaidLeader() or IsRaidOfficer()) and instype ~= "arena" and instype ~= "pvp"
end

function InvenRaidFrames:READY_CHECK(_, name)
	if self:IsReadyCheckable() and self:EnableModule("ReadyCheck") then
		self:UnregisterEvent("READY_CHECK")
		IRF_ReadyCheck:READY_CHECK(_, name)
	end
end

local RunLeaveCombatDB = {}
local RunLeaveCombatArgs = {}

function InvenRaidFrames:PLAYER_REGEN_ENABLED()
	if self.updateLeaveCombat then
		self.updateLeaveCombat = nil
		for name, func in pairs(RunLeaveCombatDB) do
			if type(func) == "string" then
				self[func](unpack(RunLeaveCombatArgs[name]))
			else
				func(unpack(RunLeaveCombatArgs[name]))
			end
		end
		RunLeaveCombatDB = {}
		RunLeaveCombatArgs = {}
	end
	if self.updateRoster then
		self.updateRoster = nil
		self:RosterUpdate()
	end
	if self.updateGroupSetPoint then
		self.updateGroupSetPoint = nil
		self:GroupSetPoint()
	end
	if self.updateHideFrame then
		self.updateHideFrame = nil
		self:HideFrame_NoCombat()
	end
	if self.updatePetModule then
		self.updatePetModule = nil
		if self:EnableModule("Pet") then
			IRF_Pet:CheckStatus()
		end
	end
	if self.updateProfile then
		self.updateProfile = nil
		self:UpdateProfile()
	end
end

function InvenRaidFrames:ClearMemory()
	self:RunLeaveCombat("ClearMemory", collectgarbage)
end

function InvenRaidFrames:RunLeaveCombat(name, func, method, ...)
	if name and func and type(name) == "string" then
		if type(func) == "table" and type(method) == "string" and type(func[method]) == "function" then
			RunLeaveCombatDB[name] = func[method]
			RunLeaveCombatArgs[name] = { func, ... }
		elseif type(func) == "function" then
			RunLeaveCombatDB[name] = func
			RunLeaveCombatArgs[name] = { method, ... }
		end
		if InCombatLockdown() then
			self.updateLeaveCombat = true
		else
			RunLeaveCombatDB[name](unpack(RunLeaveCombatArgs[name]))
			RunLeaveCombatDB[name] = nil
			RunLeaveCombatArgs[name] = nil
		end
	end
end

function InvenRaidFrames:PLAYER_ENTERING_WORLD()
	self.vars.range = {}
	self:SetMinimapButtonText()
	self:SetAllClickHealFrames()
	if firstPEW then
		firstPEW = nil
	else
		self:InitUnits()
		self:RosterChange()
		self:UpdateUnit()
		self:BuffModule()
		if self:IsEnableModule("Debuff") then
			IRF_Debuff:Update()
		end
		self:ClearMemory()
	end
end

function InvenRaidFrames:HideFrame()
	self:UnregisterEvents()
	self:RunLeaveCombat("Hide", self, "HideFrame_NoCombat")
end

function InvenRaidFrames:HideFrame_NoCombat()
	if self.db.char.showIRF and (self.db.profile.use == "항상" or (self.db.profile.use == "파티" and (self.vars.member.party > 0 or self.vars.member.raid > 0)) or (self.db.profile.use == "공격대" and self.vars.member.raid > 0)) then
		self:RosterChange()
	else
		for i = 0, 9 do
			if self.vars.tag[i] then
				self.vars.tag[i]:Hide()
				self.vars.tag2[i]:Hide()
			end
			if self.vars.group[i] then
				self.vars.group[i]:Hide()
			end
		end
		self.vars.group.m.border:Hide()
		self:PetModule()
		self:SendMessage("InvenRaidFrames_HideAll")
		self:ClearMemory()
	end
end

function InvenRaidFrames:SetQuickHealth()
	if QuickHealth then
		QuickHealth.RegisterCallback(self, "HealthUpdated", function(event, GUID, newHealth)
			for unit, frame in pairs(self.vars.unit) do
				if GUID == UnitGUID(unit) then
					self:UNIT_HEALTH(_, unit, frame)
				end
			end
		end)
		local proxyEnv = {
			UnitHealth = function(...) return QuickHealth.UnitHealth(QuickHealth, ...) end,
		}
		local _G = getfenv(0)
		setmetatable(proxyEnv, {
			__index    = _G,
			__newindex = function (t, k, v) _G[k] = v end,
		})
		setfenv(self.UNIT_HEALTH, proxyEnv)
	end
end

function InvenRaidFrames:UpdateProfile()
	if InCombatLockdown() then
		self.updateProfile = true
	else
		if IRFOption then
			IRFOption:CreateSpellTimerOption()
			IRFOption:CreateClickHealOption()
		end
		self:SetUpdateTime()
		self.vars.group.m:SetScale(self.db.profile.scale)
		self.vars.group.m.border:SetScale(self.db.profile.scale)
		self.vars.group.m.border:SetBackdropColor(unpack(self.db.profile.color.bg))
		self.vars.group.m.border:SetAlpha(self.db.profile.borderAlpha)
		local s = self.vars.group.m:GetEffectiveScale()
		self.vars.group.m:ClearAllPoints()
		self.vars.group.m:SetPoint(self.db.profile.pos[1], UIParent, self.db.profile.pos[1], self.db.profile.pos[2] / s, self.db.profile.pos[3] / s)
		self.highlightFrame:SetAlpha(self.db.profile.moalpha)
		for _, f in pairs(self.vars.frames) do
			f.raidDebuff:SetAlpha(self.db.profile.debuffAlpha)
			f.raidDebuff:ClearAllPoints()
			self:SetDebuffIconPoint(f)
			self:ControlRaidIcon(f)
			f.raidIcon:SetWidth(self.db.profile.raidiconsize)
			f.raidIcon:SetHeight(self.db.profile.raidiconsize)
			f.raidIconTarget:SetWidth(self.db.profile.raidiconsize)
			f.raidIconTarget:SetHeight(self.db.profile.raidiconsize)
			f.healIconTexture:SetVertexColor(unpack(self.db.profile.color.healicon))
			f.healIcon:ClearAllPoints()
			self:SetHealIconPoint(f)
		end
		if IRF_ReadyCheck then
			IRF_ReadyCheck:SetScale()
		end
		if IRF_SpellTimer then
			IRF_SpellTimer:SetScale()
		end
		self:SetFont()
		self:SetBar()
		self:SetUnitSize()
		self:PetModule()
		if IRF_Pet then
			IRF_Pet:UnitSizeUpdate()
			IRF_Pet:SetBorder()
		end
		self:RosterUpdate()
		self:UpdateGroupSetPoint()
		self:UpdateUnit()
	end
end

function InvenRaidFrames:PetModule()
	if self.vars.init then
		if self.db.char.pet then
			if self:IsEnableModule("Pet") then
				IRF_Pet:CheckStatus()
			else
				self:EnableModule("Pet")
			end
		elseif  self:IsEnableModule("Pet") then
			IRF_Pet:CheckStatus()
		end
	elseif self:IsEnableModule("Pet") then
		IRF_Pet:CheckStatus()
	end
end

function InvenRaidFrames:BuffModule()
	if not self.vars.buffcheck or (self.vars.buffcheck and #(self.vars.buffcheck) == 0) then return end
	if self.db.char.checkbuff.use and self:HasModule("Buff") and not self:IsEnableModule("Buff") then
		local ins, itype = IsInInstance()
		if ins then
			if (((itype == "party" or itype == "raid") and self.db.char.checkbuff.zone2) or (itype == "arena" and self.db.char.checkbuff.zone3) or (itype == "pvp" and self.db.char.checkbuff.zone4)) then
				self:EnableModule("Buff")
				IRF_Buff:Update()
			end
		elseif self.db.char.checkbuff.zone1 then
			self:EnableModule("Buff")
			IRF_Buff:Update()
		end
	elseif not self.db.char.checkbuff.use and self:IsEnableModule("Buff") then
		IRF_Buff:Update()
	end
end

function InvenRaidFrames:CheckModule()
	local numAddons = GetNumAddOns()
	for i = 1, numAddons do
		local name, _, _, enabled = GetAddOnInfo(i)
		if name and enabled and IsAddOnLoadOnDemand(i) then
			local meta = GetAddOnMetadata(i, "X-InvenRaidFrames-Module")
			if meta then
				self.vars.modules[meta] = name
			end
		end
	end
end

function InvenRaidFrames:HasModule(module)
	if module and self.vars.modules[module] then
		return true
	else
		return false
	end
end

function InvenRaidFrames:EnableModule(module)
	if module and self.vars.modules[module] then
		if IsAddOnLoaded(self.vars.modules[module]) then
			return true
		else
			local loaded = LoadAddOn(self.vars.modules[module])
			if loaded then
				return true
			else
				return false
			end
		end
	else
		return false
	end
end

function InvenRaidFrames:IsEnableModule(module)
	if module and self.vars.modules[module] then
		if IsAddOnLoaded(self.vars.modules[module]) then
			return true
		else
			return false
		end
	else
		return false
	end
end