local self = InvenRaidFrames
local SM = LibStub("LibSharedMedia-3.0")
local HealComm = LibStub:GetLibrary("LibHealComm-3.0", true)
local powerType = { [1] = "rage", [2] = "focus", [3] = "energy", [4] = "focus", [0] = "mana" }
local unitBackdrop = {
	bgFile = "Interface\\Addons\\InvenRaidFrames\\Texture\\Blink", tile = true, tileSize = 16,
	edgeFile = "Interface\\Addons\\InvenRaidFrames\\Texture\\Blink", edgeSize = 2,
	insets = { left = 1, right = 1, top = 1, bottom = 1 },
}
local debuffPos = { ["좌측"] = { "LEFT", 0, 0 }, ["중앙"] = { "CENTER", 0, 0 }, ["우측"] = { "RIGHT", 0, 0 }, ["상단"] = { "TOP", 0, 0 }, ["하단"] = { "BOTTOM", 0, 0 }, ["좌측 상단"] = { "TOPLEFT", 0, 0 }, ["좌측 하단"] = { "BOTTOMLEFT", 0, 0 }, ["우측 상단"] = { "TOPRIGHT", 0, 0 }, ["우측 하단"] = { "BOTTOMRIGHT", 0, 0 } }
local fontTypes = { ["외각선"] = "OUTLINE", ["굵은 외각선"] = "THICKOUTLINE", ["예리하게 + 그림자"] = "MONOCHROME", ["예리하게 + 외각선"] = "OUTLINE, MONOCHROME", ["예리하게 + 굵은 외각선"] = "THICKOUTLINE, MONOCHROME" }
local handlerRunner = {
	["UNIT_HEALTH"] = "UNIT_HEALTH", ["UNIT_MAXHEALTH"] = "UNIT_HEALTH", ["PLAYER_FLAGS_CHANGED"] = "UNIT_HEALTH",
	["UNIT_MANA"] = "UNIT_MANA", ["UNIT_MAXMANA"] = "UNIT_MANA", ["UNIT_RAGE"] = "UNIT_MANA", ["UNIT_MAXRAGE"] = "UNIT_MANA",
	["UNIT_ENERGY"] = "UNIT_MANA", ["UNIT_MAXENERGY"] = "UNIT_MANA", ["UNIT_FOCUS"] = "UNIT_MANA", ["UNIT_MAXFOCUS"] = "UNIT_MANA",
	["UNIT_DISPLAYPOWER"] = "UNIT_DISPLAYPOWER", ["UNIT_TARGET"] = "UNIT_TARGET",
	["UNIT_AURA"] = "UNIT_AURA", ["UNIT_NAME_UPDATE"] = "UNIT_NAME_UPDATE",	["UNIT_THREAT_SITUATION_UPDATE"] = "UNIT_THREAT_SITUATION_UPDATE",
}
local yourHeal = {}
local compunit = { "player", "party1", "party2", "party3", "party4" }
local ata, b, c, cid, color, count, dtype, fullName, g, h, heal, hp, ic, icon, id, incoming, index1, index2, ins, itype, left, length, losthp, n, name, now, oheal, p, prev, prev1, prev2, prev3, r, r, rDebuff, range, s, space, state, t, tail, targetFullName, unit, units, v, vis, w, yheal, frame, moveID, aggro, stopList

local _G = _G
local UnitIsConnected = _G.UnitIsConnected
local UnitIsAFK = _G.UnitIsAFK
local GetRaidTargetIndex = _G.GetRaidTargetIndex
local IsSpellInRange = _G.IsSpellInRange
local UnitIsDead = _G.UnitIsDead
local UnitIsGhost = _G.UnitIsGhost
local UnitPowerType = _G.UnitPowerType
local UnitBuff = _G.UnitBuff
local UnitDebuff = _G.UnitDebuff
local PlaySoundFile = _G.PlaySoundFile
local UnitThreatSituation = _G.UnitThreatSituation
local getglobal = _G.getglobal
local ceil = _G.ceil
local tonumber = _G.tonumber
local strmatch = _G.strmatch
local strfind = _G.strfind
local format = _G.format
local unpack = _G.unpack
local pairs = _G.pairs
local strsub = _G.strsub
local select = _G.select
local min = _G.min
local max = _G.max

function InvenRaidFrames:CreateUnit(f)
	w, h = self.db.profile.unitWidth, self.db.profile.unitHeight

	local p = f:GetParent()

	if not InCombatLockdown() then
		f:SetWidth(w)
		f:SetHeight(h)
	end

	f:RegisterForClicks("AnyUp")
	f:EnableMouse(true)
	f:RegisterForDrag("LeftButton")

	f:SetBackdrop(unitBackdrop)
	f:SetBackdropColor(unpack(self.db.profile.color.unitbg))
	f:SetBackdropBorderColor(0, 0, 0, 0)
	f:SetAlpha(self.db.profile.healthAlpha)

	f:SetScript("OnDragStop", self.FrameOnDragStop)
	f:SetScript("OnEnter", self.FrameOnEnter)
	f:SetScript("OnLeave", self.FrameOnLeave)

	local t = SM:Fetch("statusbar", self.db.profile.barTexture)

	local fb = CreateFrame("Frame", nil, f)
	fb:SetAllPoints(f)
	f.healthBar_BG = fb:CreateTexture(nil, "BACKGROUND")
	f.healthBar_BG:SetWidth(w - 4)
	f.healthBar_BG:SetPoint("TOP", fb, "TOP", 0, -1)
	f.healthBar_BG:SetTexture(t)
	f.healthBar_BG:SetVertexColor(unpack(self.db.profile.color.health))
	f.healthBar_BG:SetAlpha(self.db.profile.healthBGAlpha)

	f.manaBar_BG = p:CreateTexture(nil, "BACKGROUND")
	f.manaBar_BG:SetWidth(f.healthBar_BG:GetWidth())
	f.manaBar_BG:SetPoint("TOP", f.healthBar_BG, "BOTTOM", 0, 0)
	f.manaBar_BG:SetTexture(t)
	f.manaBar_BG:SetAlpha(self.db.profile.healthBGAlpha)

	self:SetManaPer(f)

	f.healBar = CreateFrame("StatusBar", nil, f)
	f.healBar:SetAllPoints(f.healthBar_BG)
	f.healBar:SetMinMaxValues(0, 100)
	f.healBar:SetValue(0)
	f.healBar:SetStatusBarTexture(t)
	f.healBar:SetStatusBarColor(unpack(self.db.profile.color.health))
	f.healBar:SetAlpha(self.db.profile.healAlpha)

	f.healthBar = CreateFrame("StatusBar", nil, f)
	f.healthBar:SetAllPoints(f.healthBar_BG)
	f.healthBar:SetMinMaxValues(0, 100)
	f.healthBar:SetValue(0)
	f.healthBar:SetStatusBarTexture(t)
	f.healthBar:SetStatusBarColor(unpack(self.db.profile.color.health))

	f.manaBar = CreateFrame("StatusBar", nil, p)
	f.manaBar:SetAllPoints(f.manaBar_BG)
	f.manaBar:SetStatusBarTexture(t)
	f.manaBar:SetMinMaxValues(0, 100)
	f.manaBar:SetValue(0)

	local c = CreateFrame("Frame", nil, p)
	c:SetAllPoints(f)
	c:SetFrameLevel(f.healthBar:GetFrameLevel() + 1)
	f.textparent = c

	f.raidIcon = c:CreateTexture(nil, "ARTWORK")
	f.raidIcon:SetWidth(self.db.profile.raidiconsize)
	f.raidIcon:SetHeight(self.db.profile.raidiconsize)
	f.raidIcon:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
	f.raidIcon:Hide()
	f.raidIconTarget = c:CreateTexture(nil, "ARTWORK")
	f.raidIconTarget:SetWidth(self.db.profile.raidiconsize)
	f.raidIconTarget:SetHeight(self.db.profile.raidiconsize)
	f.raidIconTarget:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
	f.raidIconTarget:Hide()
	self:ControlRaidIcon(f)

	local rd = c:CreateTexture(nil, "ARTWORK")
	rd:SetTexture("")
	rd:SetAlpha(self.db.profile.debuffAlpha)
	rd.count = c:CreateFontString(nil, "OVERLAY", "NumberFontNormalSmall")
	rd.count:SetPoint("TOPRIGHT", rd, "TOPRIGHT", 6, 0)
	rd.count:SetTextColor(1, 1, 1)
	rd.count:SetText("")
	f.raidDebuff = rd
	rd:Show()
	self:SetDebuffIconPoint(f)

	local hi = CreateFrame("Frame", nil, c)
	hi:SetWidth(10)
	hi:SetHeight(10)
	local hit = hi:CreateTexture(nil, "OVERLAY")
	hit:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
	hit:SetAllPoints(hi)
	hit:SetVertexColor(unpack(self.db.profile.color.healicon))
	hi:Hide()
	f.healIcon = hi
	f.healIconTexture = hit
	self:SetHealIconPoint(f)

	local sf = CreateFrame("Frame", nil, p)
	sf:SetAllPoints(f)
	sf:SetFrameLevel(c:GetFrameLevel() + 10)
	f.topparent = sf

	f.text = sf:CreateFontString(nil, "OVERLAY")
	f.text:SetPoint("CENTER", sf, "CENTER", 0, 3)
	self:SetFont(f)

	f.border = CreateFrame("Frame", nil, c)
	f.border:SetAllPoints(f)
	f.border:SetBackdrop(unitBackdrop)
	f.border:SetBackdropBorderColor(0, 0, 0, 0)
	f.border:SetBackdropColor(0, 0, 0, 0)

	f.menu = function() self:MenuToggle(f) end

	tinsert(self.vars.frames, f)
	self:SetClickHealFrame(f)
end

function InvenRaidFrames:CreateUnitFrame(f)
	self:CreateUnit(f)
	f:SetScript("OnDragStart", self.FrameOnDragStart)
end

function InvenRaidFrames:OnShowUnitFrame(f)
	f.textparent:Show()
	f.topparent:Show()
	f.manaBar_BG:Show()
	f.manaBar:Show()
	self:SendMessage("InvenRaidFrames_UnitShow", f)
end

function InvenRaidFrames:OnHideUnitFrame(f)
	if f.unit and self.vars.unit[f.unit] == f then
		self.vars.unit[f.unit] = nil
	end
	f.textparent:Hide()
	f.topparent:Hide()
	f.manaBar_BG:Hide()
	f.manaBar:Hide()
	f.raidIcon:Hide()
	f.raidIconTarget:Hide()
	f.healIcon:Hide()
	f.hasAggro = nil
	f.debuffed = nil
	f.debuffsound = nil
	f.unit = nil
	f.unitName = nil
	self:UnregisterUnitEvent(f)
	f:SetScript("OnUpdate", nil)
	self:SendMessage("InvenRaidFrames_UnitHide", f)
end

function InvenRaidFrames:OnAttributeChanged(frame, name, value)
	if name == "unit" and value then
		frame.unit = value
		self.vars.range[value] = nil
		self.vars.ata[value] = nil
		self.vars.incombat[value] = nil
		self:RegisterUnitEvent(frame)
		self:CallbackTimer("InitUnits", 0.1)
	end
end

function InvenRaidFrames.UnitEventHandler(frame, event, unit)
	if not self.vars.playerIsVisible then return end
	if handlerRunner[event] then
		if unit then
			if frame.unit == unit then
				self[handlerRunner[event]](self, event, unit, frame)
			end
		else
			self[handlerRunner[event]](self, event, nil, frame)
		end
	end
end

function InvenRaidFrames:RegisterUnitEvent(f)
	if not f:IsEventRegistered("UNIT_HEALTH") then
		for event in pairs(handlerRunner) do
			f:RegisterEvent(event)
		end
	end
end

function InvenRaidFrames:UnregisterUnitEvent(f)
	if f:IsEventRegistered("UNIT_HEALTH") then
		for event in pairs(handlerRunner) do
			f:UnregisterEvent(event)
		end
	end
end

function InvenRaidFrames:MenuToggle(f)
	HideDropDownMenu(1)
	GameTooltip:Hide()
	id = tonumber(strmatch(f.unit, "(%d+)"))
	frame = nil
	if f.unit == "player" then
		ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "cursor")
	elseif strfind(f.unit, "party") then
		ToggleDropDownMenu(1, nil, getglobal("PartyMemberFrame"..id.."DropDown"), "cursor")
	elseif strfind(f.unit, "raid") then
		this.id = id
		this.name = UnitName(f.unit)
		RaidGroupButton_ShowMenu()
	end
end

function InvenRaidFrames.FrameOnDragStart()
	if not self.db.profile.lock and not self.vars.group.m.isMove then
		self.vars.group.m.isMove = true
		self.vars.group.m:StartMoving()
		if InCombatLockdown() then
			self.vars.group.m:SetScript("OnUpdate", self.FrameSafetyOnDragStop)
		else
			self.vars.group.m:SetScript("OnUpdate", nil)
		end
	end
end

function InvenRaidFrames.FrameSafetyOnDragStop()
	if self.isMove then
		if not IsMouseButtonDown("LeftButton") then
			self.FrameOnDragStop()
		end
	else
		self.vars.group.m:SetScript("OnUpdate", nil)
	end
end

function InvenRaidFrames.FrameOnDragStop()
	self.vars.group.m:SetScript("OnUpdate", nil)
	self.vars.group.m:StopMovingOrSizing()
	if self.vars.group.m.isMove then
		self.vars.group.m.isMove = nil
	end
	if self:IsEnableModule("Pet") then
		IRF_Pet.vars.main:StopMovingOrSizing()
		if IRF_Pet.vars.main.isMove then
			IRF_Pet.vars.main.isMove = nil
		end
	end
	self:SavePosition()
end

function InvenRaidFrames.FrameOnUpdate()
	if self.enterFrame == this and this.unit then
		GameTooltip_SetDefaultAnchor(GameTooltip, this)
		GameTooltip:SetUnit(this.unit)
		GameTooltip:Show()
	end
end

function InvenRaidFrames.FrameOnEnter()
	self.enterFrame = this
	if self.db.profile.tooltip == "항상 표시" or (self.db.profile.tooltip == "비전투 중에만" and not InCombatLockdown()) then
		this:SetScript("OnUpdate", self.FrameOnUpdate)
	else
		this:SetScript("OnUpdate", nil)
		GameTooltip:Hide()
	end
	if self.db.profile.outline == "마우스 오버" then
		this.border:SetBackdropBorderColor(unpack(self.db.profile.color.outline))
	end
	self.highlightFrame:ClearAllPoints()
	self.highlightFrame:SetAllPoints(this)
	self.highlightFrame:Show()
end

function InvenRaidFrames.FrameOnLeave()
	self.enterFrame = nil
	this:SetScript("OnUpdate", nil)
	GameTooltip:Hide()
	if self.db.profile.outline == "마우스 오버" then
		this.border:SetBackdropBorderColor(0, 0, 0, 0)
	end
	self.highlightFrame:Hide()
end

function InvenRaidFrames:GetUnit(unit)
	if not self.vars.class then
		self:InitPlayerClassDB()
	end
	if not self.vars.classDB.importantDebuff then
		self:ZONE_CHANGED_NEW_AREA()
	end
	if self.vars.classDB.importantDebuff and self.vars.class then
		local f = self.vars.unit[unit]
		if UnitIsPlayer(unit) then
			if unit and self.vars.group.m:IsVisible() and f and f.unit == unit and UnitClass(unit) then
				return f
			else
				return nil
			end
		elseif unit and self.db.char.pet and self:IsEnableModule("Pet") and f and f.unit == unit then
			return f
		else
			return nil
		end
	end
end

do

local function updateUnit(frame, unit)
	if frame then
		self:UNIT_NAME_UPDATE(self, unit, frame)
		self:UNIT_DISPLAYPOWER(self, unit, frame)
		self:UNIT_AURA(self, unit, frame)
		self:SetRaidIcon(unit, frame)
		self:UpdateAggro(unit, frame)
		self:UpdateRange(unit, frame)
		self:UpdateAttackable(unit, frame)
		self:SendMessage("InvenRaidFrames_UpdateUnit", unit, frame)
	end
end

function InvenRaidFrames:UpdateUnit(unit)
	if not self.vars.playerIsVisible then return end
	local f = self:GetUnit(unit)
	if unit then
		updateUnit(f, unit)
	else
		for u, frame in pairs(self.vars.unit) do
			updateUnit(frame, u)
		end
	end
end

function InvenRaidFrames:SetBar(f, texture, r, g, b)
	if f then
		--c = { unpack(self.db.profile.color.health) }
		c = self.db.profile.color.health
		t = SM:Fetch("statusbar", texture or self.db.profile.barTexture)
		if r and g and b then
			c = { r, g, b }
		end
		f.healthBar_BG:SetTexture(t)
		f.healthBar_BG:SetVertexColor(unpack(c))
		f.healthBar_BG:SetAlpha(self.db.profile.healthBGAlpha)
		f.manaBar_BG:SetTexture(t)
		f.manaBar_BG:SetAlpha(self.db.profile.healthBGAlpha)
		f.manaBar:SetStatusBarTexture(t)
		f.healthBar:SetStatusBarTexture(t)
		f.healthBar:SetStatusBarColor(unpack(c))
		f.healBar:SetStatusBarTexture(t)
		f.healBar:SetStatusBarColor(unpack(c))
		f.healBar:SetAlpha(self.db.profile.healAlpha)
		f:SetAlpha(self.db.profile.healthAlpha)
		if f.unit then
			self:HealthBarColor(f.unit, f)
			self:UNIT_DISPLAYPOWER(nil, f.unit, f)
			self.vars.range[f.unit] = nil
		end
	else
		self.vars.range = {}
		for _, f in pairs(self.vars.frames) do
			self:SetBar(f)
		end
	end
end

function InvenRaidFrames:SetFont(f)
	if f then
		t = self.db.profile.fontAttribute
		f.text:SetFont(SM:Fetch("font", self.db.profile.font), self.db.profile.fontSize, fontTypes[t])
		f.text:SetShadowColor(0, 0, 0)
		if strfind(t, "그림자") then
			f.text:SetShadowOffset(1, -1)
		else
			f.text:SetShadowOffset(0, 0)
		end
	else
		for _, f in pairs(self.vars.frames) do
			self:SetFont(f)
		end
	end
end

function InvenRaidFrames:CheckRange(unit)
	if UnitExists(unit) then
		if UnitIsConnected(unit) then
			cid = CheckInteractDistance(unit, 1) and 1 or 0
			if UnitCanAttack("player", unit) or UnitCanAttack(unit, "player") then
				return cid
			elseif self.vars.classDB.range and GetSpellTexture(self.vars.classDB.range) then
				r = IsSpellInRange(self.vars.classDB.range, unit)
				if r == 1 then
					return 1
				elseif r == 0 then
					return 0
				else
					return cid
				end
			else
				return cid
			end
		else
			return 0
		end
	end
end

function InvenRaidFrames:UpdateRange(unit, frame)
	if unit then
		local f = frame or self:GetUnit(unit)
		if f then
			range = self:CheckRange(unit)
			if self.vars.range[unit] == nil or self.vars.range[unit] ~= range then
				self.vars.range[unit] = range
				self:UnitRangeUpdate(unit, frame, range)
			end
		end
	else
		for unit, frame in pairs(self.vars.unit) do
			self:UpdateRange(unit, frame)
		end
	end
end

function InvenRaidFrames:UnitRangeUpdate(unit, frame, inRange)
	local f = frame or self:GetUnit(unit)
	if f then
		if inRange == nil then
			inRange = self:CheckRange(unit)
			self.vars.range[unit] = inRange
		end
		c = self.db.profile.color[select(2, UnitClass(unit))] or { 1, 1, 1 }
		if not UnitIsPlayer(unit) then
			c = { 0, 1, 0 }
		end
		if inRange == 1 then
			if self.db.profile.classcolor then
				c = { 1, 1, 1 }
			end
			f:SetAlpha(self.db.profile.healthAlpha)
		else
			f:SetAlpha(self.db.profile.rangeAlpha)
		end
		if UnitIsConnected(unit) then
			if self.db.profile.classcolor and self.db.profile.rangeAlpha > 0.5 then
				c = { 1, 1, 1 }
			end
		else
			c = { 0.4, 0.4, 0.4 }
		end
		f.text:SetTextColor(unpack(c))
		f.text:SetAlpha(self.db.profile.textAlpha and (inRange == 1 and 1 or self.db.profile.rangeAlpha) or 1)
		f.manaBar:SetAlpha(self.db.profile.manaAlpha and (inRange == 1 and 1 or self.db.profile.rangeAlpha) or 1)
	end
end

function InvenRaidFrames:UNIT_THREAT_SITUATION_UPDATE(_, unit, frame)
	if unit then
		local f = frame or self:GetUnit(unit)
		if f then
			self:UpdateAggro(unit, frame)
		end
	end
end

function InvenRaidFrames:UpdateAggro(unit, frame)
	if unit then
		local f = frame or self:GetUnit(unit)
		if f then
			prev = f.hasAggro
			aggro = UnitThreatSituation(unit)
			if aggro and aggro > 1 then
				f.hasAggro = true
				if self.db.profile.outline == "어그로" then
					f.border:SetBackdropBorderColor(self.db.profile.color.aggro[1], self.db.profile.color.aggro[2], self.db.profile.color.aggro[3], 1)
				elseif self.db.profile.showaggro and not prev then
					self:UNIT_HEALTH(_, unit, f)
				end
				if UnitIsUnit(unit, "player") and not prev then
					PlaySoundFile(SM:Fetch("sound", InvenRaidFrames.db.profile.aggrogain))
				end
			else
				f.hasAggro = nil
				if self.db.profile.outline == "어그로" then
					f.border:SetBackdropBorderColor(0, 0, 0, 0)
				elseif self.db.profile.showaggro and prev then
					self:UNIT_HEALTH(_, unit, f)
				end
				if UnitIsUnit(unit, "player") and prev then
					PlaySoundFile(SM:Fetch("sound", InvenRaidFrames.db.profile.aggrolost))
				end
			end
		end
	else
		for unit, frame in pairs(self.vars.unit) do
			self:UpdateAggro(unit, frame)
		end
	end
end

function InvenRaidFrames:UpdateAttackable(unit, frame)
	local f = frame or self:GetUnit(unit)
	if f then
		ata = (UnitCanAttack("player", unit) or UnitCanAttack(unit, "player")) and 1 or 0
		if self.vars.ata[unit] == nil or self.vars.ata[unit] ~= ata then
			self.vars.ata[unit] = ata
			self:HealthBarColor(unit, frame)
		end
	end
end

function InvenRaidFrames:UpdateUnitInCombat(unit, frame)
	local f = frame or self:GetUnit(unit)
	if f then
		ic = UnitAffectingCombat(unit)
		if self.vars.incombat[unit] == nil or self.vars.incombat[unit] ~= ic then
			self.vars.incombat[unit] = ic
			if not ic and self.db.profile.outline == "체력 저하" then
				frame.border:SetBackdropBorderColor(0, 0, 0, 0)
			end
		end
	end
end

local function OnUpdateUnitFrame(unit, frame)
	self:UpdateRange(unit, frame)
	self:UpdateAggro(unit, frame)
	self:UpdateAttackable(unit, frame)
	self:UpdateUnitInCombat(unit, frame)
	if self.db.profile.outline == "대상" then
		if UnitIsUnit("target", unit) then
			frame.border:SetBackdropBorderColor(unpack(self.db.profile.color.outline))
		else
			frame.border:SetBackdropBorderColor(0, 0, 0, 0)
		end
	end
end

function InvenRaidFrames:OnUpdateUnitFrame()
	vis = UnitIsVisible("player")
	if self.vars.playerIsVisible and not vis then
		self.vars.playerIsVisible = false
	elseif self.vars.playerIsVisible == false and vis then
		self.vars.playerIsVisible = true
		self:UpdateUnit()
	end
	if self.vars.playerIsVisible then
		for unit, frame in pairs(self.vars.unit) do
			OnUpdateUnitFrame(unit, frame)
		end
	end
end

function InvenRaidFrames:UNIT_HEALTH(_, unit, frame)
	if not self.vars.playerIsVisible then return end
	if unit == "player" and UnitIsDeadOrGhost(unit) then
		self.vars.range = {}
	end
	local f = frame or self:GetUnit(unit)
	if f and f.healthBar and f.healthBar_BG then
		name = UnitName(unit)
		if self.vars.names[name] then
			hp, losthp = self:GetUnitHealthPercent(unit)
			state, color = "", ""
			if UnitIsConnected(unit) then
				if UnitIsDead(unit) then
					hp = 0
					losthp = 0
					state = "죽음"
					color = "|cffacacac"
					f.hasAggro = nil
					f.healBar:SetValue(0)
					f.manaBar:SetValue(0)
				elseif UnitIsGhost(unit) then
					hp = 0
					losthp = 0
					state = "유령"
					color = "|cffacacac"
					f.healBar:SetValue(0)
					f.manaBar:SetValue(0)
					f.hasAggro = nil
				elseif UnitIsAFK(unit) then
					losthp = 0
					state = "자리"
				else
					self:UpdateIncomingHeals(unit)
				end
			else
				hp = 0
				losthp = 0
				state = "오프"
				f.healBar:SetValue(0)
				if self:IsEnableModule("Buff") then
					IRF_Buff:Update(unit)
				end
			end
			if self.db.profile.outline == "체력 저하" then
				if UnitAffectingCombat(unit) and losthp > 0 and self.db.profile.lowhp >= hp then
					f.border:SetBackdropBorderColor(unpack(self.db.profile.color.outline))
				else
					f.border:SetBackdropBorderColor(0, 0, 0, 0)
				end
			end
			f.healthBar:SetValue(hp)
			if self.db.profile.redcolor then
				self:HealthBarColor(unit, f)
			end
			if self.db.profile.showaggro and f.hasAggro then
				color = self.db.profile.color.aggro2.."▶|r"
			end
			range = self:CheckRange(unit)
			if not(self.db.profile.losthp == "항상" or (self.db.profile.losthp == "사정거리 안" and range == 1) or (self.db.profile.losthp == "사정거리 밖" and range ~= 1)) then
				losthp = 0
			end
			if state ~= "" then
				losthp = state
			elseif self.db.profile.losthp3 and losthp > 0 then
				losthp = format("%.1f", losthp / 1000)
			end
			losthp = ""..losthp
			space = self.db.profile.losthp2 == "두줄 표시" and "\n" or ""
			if self.db.profile.losthp2 == "이름과 대체" then
				if f.ibuff then
					f.text:SetText(color..f.ibuff.."|r")
				elseif losthp and losthp ~= "0" then
					if self.db.profile.losthpcolor and losthp ~= state then
						losthp = self.db.profile.color.losthp2..losthp
					end
					f.text:SetText(color..losthp.."|r")
				else
					s = f.healthBar_BG:GetWidth() - 10
					length = min(self.vars.names[name].max or tonumber(self.db.profile.namelen), tonumber(self.db.profile.namelen))
					for i = length, 1, -1 do
						f.text:SetText(color..(self.vars.names[name][i] or "").."|r")
						if f.text:GetWidth() <= s then
							break
						end
					end
				end
			elseif self.db.profile.spspell and f.ibuff then
				tail = "|r"
				if losthp and losthp ~= "0" then
					if self.db.profile.losthpcolor and losthp ~= state then
						tail = self.db.profile.color.losthp2.."("..losthp..")|r"
					else
						tail = space.."("..losthp..")|r"
					end
				end
				f.text:SetText(color..f.ibuff..tail)
			elseif space == "\n" then
				tail = "|r"
				if losthp and losthp ~= "0" then
					if self.db.profile.losthpcolor and losthp ~= state then
						tail = self.db.profile.color.losthp2.."\n("..losthp..")|r"
					else
						tail = "\n("..losthp..")|r"
					end
				end
				s = f.healthBar_BG:GetWidth() - 5
				length = min(self.vars.names[name].max or tonumber(self.db.profile.namelen), tonumber(self.db.profile.namelen))
				for i = length, 0, -1 do
					f.text:SetText(color..(self.vars.names[name][i] or ""))
					if f.text:GetWidth() <= s then
						f.text:SetText(color..(self.vars.names[name][i] or "")..tail)
						break
					end
				end
			else
				local tail = "|r"
				if losthp and losthp ~= "0" then
					if self.db.profile.losthpcolor and losthp ~= state then
						tail = self.db.profile.color.losthp2.."("..losthp..")|r"
					else
						tail = "("..losthp..")|r"
					end
				end
				s = f.healthBar_BG:GetWidth() - 5
				length = min(self.vars.names[name].max or tonumber(self.db.profile.namelen), tonumber(self.db.profile.namelen))
				for i = length, 0, -1 do
					f.text:SetText(color..(self.vars.names[name][i] or "")..tail)
					if f.text:GetWidth() <= s then
						break
					end
				end
			end
		end
	end
end

function InvenRaidFrames:HealthBarColor(unit, frame)
	local f = frame or self:GetUnit(unit)
	if f then
		r, g, b = nil
		if UnitIsPlayer(unit) then
			if self.db.profile.attack and (UnitCanAttack("player", unit) or UnitCanAttack(unit, "player")) then
				r, g, b = 1, 0, 0
			elseif f.debuffed and self.db.profile.debuffcolor then
				r, g, b = unpack(self.db.profile.color[f.debuffed])
			elseif self.db.profile.classcolor and UnitClass(unit) then
				r, g, b = unpack(self.db.profile.color[select(2, UnitClass(unit))])
			elseif self.db.profile.redcolor then
				v = f.healthBar:GetValue() / 100
				c = self.db.profile.color.health
				if v > 0.5 then
					r, g, b = c[1] + (1 - v) * 2 * (1 - c[1]), c[2], c[3]
				else
					r, g, b = 1, c[2] - (0.5 - v) * 2 * c[2], c[3]
				end
			else
				r, g, b = unpack(self.db.profile.color.health)
			end
		else
			if f.debuffed and self.db.profile.debuffcolor then
				r, g, b = unpack(self.db.profile.color[f.debuffed])
			elseif self.db.profile.redcolor then
				v = f.healthBar:GetValue() / 100
				c = self.db.profile.color.health
				if v > 0.5 then
					r, g, b = c[1] + (1 - v) * 2 * (1 - c[1]), c[2], c[3]
				else
					r, g, b = 1, c[2] - (0.5 - v) * 2 * c[2], c[3]
				end
			else
				r, g, b = unpack(self.db.profile.color.health)
			end
		end
		f.healthBar_BG:SetVertexColor(r, g, b)
		f.healthBar:SetStatusBarColor(r, g, b)
		f.healBar:SetStatusBarColor(r, g, b)
		if self.db.profile.outline == "디버프" then
			if f.debuffed then
				r, g, b = unpack(self.db.profile.color[f.debuffed])
				f.border:SetBackdropBorderColor(r, g, b, 1)
			else
				f.border:SetBackdropBorderColor(0, 0, 0, 0)
			end
		end
	end
end

function InvenRaidFrames:UNIT_MANA(_, unit, frame)
	if not self.vars.playerIsVisible then return end
	local f = frame or self:GetUnit(unit)
	if f then
		if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then
			f.manaBar:SetValue(0)
		else
			f.manaBar:SetValue(self:GetUnitManaPercent(unit))
		end
	end
end

function InvenRaidFrames:UNIT_DISPLAYPOWER(_, unit, frame)
	if not self.vars.playerIsVisible then return end
	local f = frame or self:GetUnit(unit)
	if f then
		r, g, b = unpack(self.db.profile.color[powerType[UnitPowerType(unit)] or "mana"])
		if self.db.profile.dmanabar and f.debuffed then
			r, g, b = unpack(self.db.profile.color[f.debuffed])
		end
		f.manaBar:SetStatusBarColor(r, g, b)
		f.manaBar_BG:SetVertexColor(r, g, b)
		if self.db.profile.manaAlpha then
			if self:CheckRange(unit) == 1 then
				f.manaBar:SetAlpha(1)
			else
				f.manaBar:SetAlpha(self.db.profile.rangeAlpha)
			end
		end
		self:UNIT_MANA(_, unit, f)
	end
end

function InvenRaidFrames:UNIT_NAME_UPDATE(_, unit, frame)
	if not self.vars.playerIsVisible then return end
	local f = frame or self:GetUnit(unit)
	self:UnitRangeUpdate(unit, frame)
	name = f and UnitName(unit) or nil
	if f and name then
		name = UnitIsPlayer(unit) and name or gsub(name, " ", "")
		if not self.vars.names[name] then
			n = strsub(name, 1, 1)
			if n < "A" or n > "Z" then
				self.vars.names[name] = { strsub(name, 1, 3), strsub(name, 1, 6), strsub(name, 1, 9), strsub(name, 1, 12), strsub(name, 1, 15), strsub(name, 1, 18), strsub(name, 1, 21), strsub(name, 1, 24), [0] = "" }
			else
				self.vars.names[name] = { strsub(name, 1, 2), strsub(name, 1, 3), strsub(name, 1, 4), strsub(name, 1, 6), strsub(name, 1, 8), strsub(name, 1, 10), strsub(name, 1, 12), strsub(name, 1, 14), [0] = "" }
			end
			for i = 2, #(self.vars.names[name]) do
				if self.vars.names[name][i] == self.vars.names[name][i - 1] then
					self.vars.names[name].max = i - 1
					break
				end
			end
		end
		self:UNIT_HEALTH(_, unit, f)
	end
end

function InvenRaidFrames:UNIT_AURA(_, unit, frame)
	if not self.vars.playerIsVisible then return end
	local f = frame or self:GetUnit(unit)
	if f then
		if self.vars.classDB.spellTimer and #(self.vars.classDB.spellTimer) > 0 then
			if self:HasModule("SpellTimer") and not self:IsEnableModule("SpellTimer") then
				if (self.vars.class == "드루이드" or self.vars.class == "사제") then
					if self.db.char.spelltimer ~= "사용 안함" then
						self:EnableModule("SpellTimer")
					end
				else
					if self.db.char.spelltimer2 then
						self:EnableModule("SpellTimer")
					end
				end
			end
		end
		if self.db.profile.debuffnum ~= "표시안함" and self:HasModule("Debuff") and not self:IsEnableModule("Debuff") and UnitDebuff(unit, 1) and (InvenRaidFramesDispelDB.Normal or InvenRaidFramesDispelDB.Curse or InvenRaidFramesDispelDB.Magic or InvenRaidFramesDispelDB.Disease or InvenRaidFramesDispelDB.Poison) then
			self:EnableModule("Debuff")
			IRF_Debuff:Update(unit)
		end
		prev1, prev2, prev3 = f.debuffed, f.ibuff, f.debuffsound
		f.debuffed, f.ibuff, f.debuffsound = nil, nil, nil
		if self.db.profile.raiddebuff or self.db.profile.outline == "디버프" or self.db.profile.debuffcolor or self.db.char.debuffsound.use then
			id = 1
			rDebuff = false
			while true do
				name, _, icon, count, dtype, _, left = UnitDebuff(unit, id)
				if name then
					dtype = dtype or "Normal"
					if self.vars.classDB.importantDebuff[name] and self.db.profile.raiddebuff then
						rDebuff = true
						f.raidDebuff:SetTexture(icon)
						f.raidDebuff.count:SetText((count and count > 1) and count or "")
					end
					if not self.vars.skipdebuff[name] then
						if InvenRaidFramesDispelDB.outline[dtype] then
							f.debuffed = dtype
						end
						if self.db.char.debuffsound[dtype] then
							f.debuffsound = dtype
						end
					end
				else
					break
				end
				id = id + 1
			end
			if not rDebuff then
				f.raidDebuff:SetTexture("")
				f.raidDebuff.count:SetText("")
			end
		end
		if self.db.profile.spspell then
			id =  1
			while true do
				name = UnitBuff(unit, id)
				if not name then break end
				if self.vars.classDB.importantBuff[name] then
					if name == "분산" then
						if UnitIsUnit(unit, "player") then
							f.ibuff = self.vars.classDB.importantBuff[name]
							break
						end
					else
						f.ibuff = self.vars.classDB.importantBuff[name]
					end
					break
				end
				id = id + 1
			end
		end
		if prev1 ~= f.debuffed then
			self:HealthBarColor(unit, f)
			if self.db.profile.dmanabar then
				self:UNIT_DISPLAYPOWER(nil, unit, f)
			end
		end
		if prev2 ~= f.ibuff then
			self:UNIT_HEALTH(nil, unit, f)
		end
		if self.db.char.debuffsound.use and f.debuffsound and prev3 ~= f.debuffsound and self.db.char.debuffsound[f.debuffsound] then
			s = self.db.char.debuffsound
			ins, itype = IsInInstance()
			if (not ins and s.zone1) or (ins and (((itype == "party" or itype == "raid") and s.zone2) or (itype == "arena" and s.zone3) or (itype == "pvp" and s.zone4))) then
				r = self:CheckRange(unit)
				if s.range == "모두" or (s.range == "사정거리 안" and r == 1) or (s.range == "사정거리 밖" and r == 0) or (s.range == "자신만" and UnitIsUnit("player", unit)) then
					now = GetTime()
					if self.vars.playdebuff <= now then
						self.vars.playdebuff = now + (self.db.char.debuffsound.update == 0 and 0.1 or self.db.char.debuffsound.update)
						PlaySoundFile(SM:Fetch("sound", self.db.char.debuffsound.sound[f.debuffsound]))
					end
				end
			end
		end
	end
end

function InvenRaidFrames:RAID_TARGET_UPDATE()
	for unit, frame in pairs(self.vars.unit) do
		self:SetRaidIcon(unit, frame)
	end
end

function InvenRaidFrames:UNIT_TARGET(_, unit)
	self:SetRaidIcon(unit, self:GetUnit(unit))
end

function InvenRaidFrames:SetRaidIcon(unit, frame)
	local f = frame or self:GetUnit(unit)
	if f then
		index1 = GetRaidTargetIndex(unit)
		index2 = GetRaidTargetIndex(unit == "player" and "target" or (unit.."target"))
		if index1 and self.db.profile.raidicon then
			SetRaidTargetIconTexture(f.raidIcon, index1)
			f.raidIcon:Show()
		else
			f.raidIcon:Hide()
		end
		if index2 and self.db.profile.raidicontarget then
			SetRaidTargetIconTexture(f.raidIconTarget, index2)
			f.raidIconTarget:Show()
		else
			f.raidIconTarget:Hide()
		end
	elseif self.vars.unit[unit] then
		self.vars.unit[unit].raidIcon:Hide()
		self.vars.unit[unit].raidIconTarget:Hide()
	end
end

function InvenRaidFrames:ControlRaidIcon(f)
	if f then
		local p = debuffPos[self.db.profile.raidiconloc]
		if self.db.profile.raidicon and self.db.profile.raidicontarget then
			if strfind(self.db.profile.raidiconloc, "좌측") then
				f.raidIcon:ClearAllPoints()
				f.raidIcon:SetPoint(p[1], f, p[1], p[2], p[3])
				f.raidIconTarget:ClearAllPoints()
				f.raidIconTarget:SetPoint("LEFT", f.raidIcon, "RIGHT")
			elseif strfind(self.db.profile.raidiconloc, "우측") then
				f.raidIcon:ClearAllPoints()
				f.raidIcon:SetPoint(p[1], f, p[1], p[2], p[3])
				f.raidIconTarget:ClearAllPoints()
				f.raidIconTarget:SetPoint("RIGHT", f.raidIcon, "LEFT")
			elseif self.db.profile.raidiconloc == "상단" then
				f.raidIcon:ClearAllPoints()
				f.raidIcon:SetPoint("TOPRIGHT", f, "TOP")
				f.raidIconTarget:ClearAllPoints()
				f.raidIconTarget:SetPoint("TOPLEFT", f.textparent, "TOP")
			elseif self.db.profile.raidiconloc == "중앙" then
				f.raidIcon:ClearAllPoints()
				f.raidIcon:SetPoint("RIGHT", f, "CENTER")
				f.raidIconTarget:ClearAllPoints()
				f.raidIconTarget:SetPoint("LEFT", f, "CENTER")
			else
				f.raidIcon:ClearAllPoints()
				f.raidIcon:SetPoint("BOTTOMRIGHT", f, "BOTTOM")
				f.raidIconTarget:ClearAllPoints()
				f.raidIconTarget:SetPoint("BOTTOMLEFT", f, "BOTTOM")
			end
		elseif self.db.profile.raidicon then
			f.raidIcon:ClearAllPoints()
			f.raidIcon:SetPoint(p[1], f, p[1], p[2], p[3])
		elseif self.db.profile.raidicontarget then
			f.raidIconTarget:ClearAllPoints()
			f.raidIconTarget:SetPoint(p[1], f, p[1], p[2], p[3])
		end
	end
end

end

function InvenRaidFrames:HealComm_DirectHealStart(_, healerFullName, healSize, endTime, ...)
	self:HandleIncomingHeal(healerFullName, healSize, ...)
	if self.db.profile.yourHeal and healerFullName == self.vars.playerName then
		self:RegisterEvent("UNIT_SPELLCAST_STOP")
	end
end

function InvenRaidFrames:HealComm_DirectHealStop(_, healerFullName, healSize, succeeded, ...)
	self:HandleIncomingHeal(healerFullName, 0, ...)
end

function InvenRaidFrames:HealComm_DirectHealDelayed(_, healerFullName, healSize, endTime, ...)
	self:HandleIncomingHeal(healerFullName, healSize, ...)
end

function InvenRaidFrames:HealComm_HealModifierUpdate(_, unit, targetFullName, healModifier)
	self:UpdateIncomingHeals(targetFullName)
end

function InvenRaidFrames:UNIT_SPELLCAST_STOP(_, unit)
	if unit == "player" then
		for targetFullName in pairs(yourHeal) do
			yourHeal[targetFullName] = nil
			self:UpdateIncomingHeals(targetFullName)
		end
	end
end

function InvenRaidFrames:HandleIncomingHeal(healerFullName, healSize, ...)
	local targetFullName
	if healerFullName == self.vars.playerName then
		for i = 1, select("#", ...) do
			targetFullName = select(i, ...)
			yourHeal[targetFullName] = healSize > 0 and healSize or nil
			self:UpdateIncomingHeals(targetFullName)
		end
	else
		for i = 1, select("#", ...) do
			targetFullName = select(i, ...)
			self:UpdateIncomingHeals(targetFullName)
		end
	end
end

function InvenRaidFrames:UpdateIncomingHeals(fullName)
	unit = self.vars.name[fullName]
	if not unit then
		unit = fullName
		fullName = self:GetUnitFullName(unit)
	end
	local f = self:GetUnit(unit)
	if f then
		heal = HealComm:UnitIncomingHealGet(fullName, GetTime() + 100) or 0
		yheal = self.db.profile.yourHeal and (yourHeal[fullName] or 0) or 0
		incoming = (heal + yheal) * HealComm:UnitHealModifierGet(fullName)
		self:SetIncomingHeals(unit, incoming)
	end
end

function InvenRaidFrames:SetIncomingHeals(unit, heal)
	local f = self:GetUnit(unit)
	if f then
		f.healBar:SetValue(self:GetUnitHealthPercent(unit, heal))
		if self.db.profile.inheal or self.db.profile.inheal2 then
			fullName = self:GetUnitFullName(unit)
			oheal = HealComm:UnitIncomingHealGet(fullName, GetTime() + 100) or 0
			oheal = HealComm:UnitIncomingHealGet(fullName, GetTime()) or 0
			yheal = yourHeal[fullName] or 0
			if self.db.profile.inheal2 and yheal > 0 then
				f.healIconTexture:SetVertexColor(unpack(self.db.profile.color.healicon2))
				f.healIcon:Show()
			elseif self.db.profile.inheal and oheal > 0 then
				f.healIconTexture:SetVertexColor(unpack(self.db.profile.color.healicon))
				f.healIcon:Show()
			else
				f.healIcon:Hide()
			end
		else
			f.healIcon:Hide()
		end
		if strfind(unit, "raid") then
			for _, u in pairs(compunit) do
				if UnitIsUnit(unit, u) then
					self:SetIncomingHeals(u, heal)
					break
				end
			end
		end
	end
end

function InvenRaidFrames:ClearOutline()
	for _, f in pairs(self.vars.frames) do
		f.border:SetBackdropBorderColor(0, 0, 0, 0)
	end
end

function InvenRaidFrames:SetUnitForm()
	for _, f in pairs(self.vars.frames) do
		f:SetBackdropBorderColor(0, 0, 0, 0)
		f:SetBackdropColor(unpack(self.db.profile.color.unitbg))
		f.border:SetBackdropBorderColor(0, 0, 0, 0)
		f.healBar:SetAlpha(self.db.profile.healAlpha)
	end
end

function InvenRaidFrames:SetUnitSize()
	w = self.db.profile.unitWidth
	h = self.db.profile.unitHeight
	self.vars.group.m:SetWidth(w)
	self.vars.group.m:SetHeight(h)
	for i = 0, 9 do
		local f = self.vars.group[i]
		if f then
			f:SetWidth(w)
			f:SetHeight(h)
			f:SetAttribute("initial-width", w)
			f:SetAttribute("initial-height", h)
		end
		if self.vars.tag[i] then
			self.vars.tag[i]:SetWidth(w - 2)
			self.vars.tag[i]:SetHeight(12)
			self.vars.tag2[i]:SetWidth(12)
			self.vars.tag2[i]:SetHeight(h - 2)
		end
	end
	for _, f in pairs(self.vars.frames) do
		f:SetWidth(w)
		f.healthBar_BG:SetWidth(w - 4)
		f.manaBar_BG:SetWidth(w - 4)
		f:SetHeight(h)
		self:SetManaPer(f)
	end
	self:SendMessage("InvenRaidFrames_UnitSizeUpdate")
end

function InvenRaidFrames:SetManaPer(f)
	h = self.db.profile.unitHeight - 4
	if self.db.profile.manaper == 1 then
		f.healthBar_BG:SetHeight(0.1)
		f.manaBar_BG:SetHeight(h)
	elseif self.db.profile.manaper > 0 then
		local hm = h * self.db.profile.manaper
		f.healthBar_BG:SetHeight(h - hm)
		f.manaBar_BG:SetHeight(hm)
	else
		f.healthBar_BG:SetHeight(h)
		f.manaBar_BG:SetHeight(0.1)
	end
end

function InvenRaidFrames:SetDebuffIconPoint(f)
	p = debuffPos[self.db.profile.debuffloc]
	f.raidDebuff:SetPoint(p[1], f, p[1], p[2], p[3])
	f.raidDebuff:SetWidth(self.db.profile.debuffsize)
	f.raidDebuff:SetHeight(self.db.profile.debuffsize)
end

function InvenRaidFrames:SetHealIconPoint(f)
	p = debuffPos[self.db.profile.healloc]
	f.healIcon:SetPoint(p[1], f, p[1], p[2], p[3])
end

function InvenRaidFrames.updateAggroFunc(aggro, name, ...)
	if self.db.char.aggrosound == "항상" or (self.db.char.aggrosound == "파티" and (self.vars.member.party > 0 or self.vars.member.raid > 0)) or (self.db.char.aggrosound == "공격대" and self.vars.member.raid > 0) or (self.db.char.aggrosound == "소환수" and (UnitExists("pet") or self.vars.member.party > 0 or self.vars.member.raid > 0)) then
		units = { ... }
		for i = 1, #(units) do
			if units[i] == "player" then
				if aggro == 1 then
					PlaySoundFile(SM:Fetch("sound", self.db.profile.aggrogain))
				elseif InCombatLockdown() then
					PlaySoundFile(SM:Fetch("sound", self.db.profile.aggrolost))
				end
				break
			end
		end
		units = nil
	end
end

function InvenRaidFrames:PreCreateUnitFrame(index, num)
	for i = 1, num do
		local h = self.vars.group[index]
		if h and not h:GetAttribute("child"..i) then
			n = h:GetName().."UnitButton"..i
			local f = CreateFrame("Button", n, h, "InvenRaidFramesSecureTemplate")
			SetupUnitButtonConfiguration(h, f)
			h:SetAttribute("child"..i, f)
		end
	end
end