--------------------------------------------
--
-- SMART - BUFF/DEBUFF
--
--------------------------------------------
SMART_BUFFDEBUFF_ENABLE = true
SMART_BUFF_ChkNum = {target=24,party=24,pet=16,partypet=16}
SMART_BUFF_MaxNum = {target=24,party=24,pet=16,partypet=16}
SMART_DEBUFF_ChkNum = {target=40,party=8,pet=6,partypet=6}
SMART_DEBUFF_MaxNum = {target=40,party=16,pet=16,partypet=16}

SmartBuffDebuffFrame = CreateFrame("Frame")
SmartBuffDebuffFrame:Hide()
SmartBuffDebuffFrame:RegisterEvent("VARIABLES_LOADED")

SmartBuffDebuffFrame:SetScript("OnEvent", function() SmartBuffDebuff_Initialize() end)

local initialized = false

local _TargetDebuffButton_Update
local _TargetFrame_UpdateBuffAnchor
local _TargetFrame_UpdateDebuffAnchor
local _RefreshBuffs
local _PartyMemberFrame_RefreshPetBuffs

-- Call from VARIABLES_LOADED
function SmartBuffDebuff_Initialize()
	local i, j

	if not initialized then
		initialized = true

		SmartTarget_BuffDebuffCreation()
		SmartParty_BuffDebuffCreation()
		SmartPet_BuffDebuffCreation()

		_TargetDebuffButton_Update = TargetDebuffButton_Update
		_TargetFrame_UpdateBuffAnchor = TargetFrame_UpdateBuffAnchor
		_TargetFrame_UpdateDebuffAnchor = TargetFrame_UpdateDebuffAnchor
		_RefreshBuffs = RefreshBuffs
		_PartyMemberFrame_RefreshPetBuffs = PartyMemberFrame_RefreshPetBuffs

		TargetDebuffButton_Update = SmartBuffDebuff_TargetDebuffButton_Update
		TargetFrame_UpdateBuffAnchor = SmartBuffDebuff_TargetFrame_UpdateBuffAnchor
		TargetFrame_UpdateDebuffAnchor = SmartBuffDebuff_TargetFrame_UpdateDebuffAnchor
		RefreshBuffs = SmartBuffDebuff_RefreshBuffs
		PartyMemberFrame_RefreshPetBuffs = SmartBuffDebuff_PartyMemberFrame_RefreshPetBuffs
	end

	-- Target
	if SMART_BUFF_ChkNum.target < SMART_BUFF_MaxNum.target then
		for i=(SMART_BUFF_ChkNum.target+1),SMART_BUFF_MaxNum.target do
			getglobal("TargetFrameBuff"..i):Hide()
		end
	end

	if SMART_DEBUFF_ChkNum.target < SMART_DEBUFF_MaxNum.target then
		for i = (SMART_DEBUFF_ChkNum.target+1), SMART_DEBUFF_MaxNum.target do
			getglobal("TargetFrameDebuff"..i):Hide()
		end
	end

	-- Party
	if SMART_BUFF_ChkNum.party < SMART_BUFF_MaxNum.party then
		for j=1, MAX_PARTY_MEMBERS do
			for i=(SMART_BUFF_ChkNum.party+1),SMART_BUFF_MaxNum.party do
				getglobal("SmartPartyFrame"..j.."Buff"..i):Hide()
			end
		end
	end

	if SMART_DEBUFF_ChkNum.party < SMART_DEBUFF_MaxNum.party then
		for j=1, MAX_PARTY_MEMBERS do
			for i=(SMART_DEBUFF_ChkNum.party+1), SMART_DEBUFF_MaxNum.party do
				getglobal("SmartPartyFrame"..j.."Debuff"..i):Hide()
			end
		end
	end

	-- Party Pets
	if SMART_BUFF_ChkNum.partypet < SMART_BUFF_MaxNum.partypet then
		for j=1, MAX_PARTY_MEMBERS do
			for i=(SMART_BUFF_ChkNum.partypet+1),SMART_BUFF_MaxNum.partypet do
				getglobal("SmartPartyFrame"..j.."PetFrameBuff"..i):Hide()
			end
		end
	end

	if SMART_DEBUFF_ChkNum.partypet < SMART_DEBUFF_MaxNum.partypet then
		for j=1, MAX_PARTY_MEMBERS do
			for i=(SMART_DEBUFF_ChkNum.partypet+1),SMART_DEBUFF_MaxNum.partypet do
				getglobal("SmartPartyFrame"..j.."PetFrameDebuff"..i):Hide()
			end
		end
	end

	-- Pet
	if SMART_BUFF_ChkNum.pet < SMART_BUFF_MaxNum.pet then
		for i = (SMART_BUFF_ChkNum.pet+1), SMART_BUFF_MaxNum.pet do
			getglobal("SmartPetFrameBuff"..i):Hide()
		end
	end

	if SMART_DEBUFF_ChkNum.pet < SMART_DEBUFF_MaxNum.pet then
		for i=(SMART_DEBUFF_ChkNum.pet+1),SMART_DEBUFF_MaxNum.pet do
			getglobal("SmartPetFrameDebuff"..i):Hide()
		end
	end

	-- Hide Blizzard Icons
	for i=1, 4 do
		getglobal("PetFrameDebuff"..i):Hide()

		for j=1, 4 do
			getglobal("PartyMemberFrame"..j.."Debuff"..i):Hide()
			getglobal("PartyMemberFrame"..j.."PetFrameDebuff"..i):Hide()
		end
	end

	SmartBuffDebuff_TargetBorderCheck()
	SmartBuffDebuff_PartyPosition()
end

function SmartTarget_BuffDebuffCreation()
	local button, i

	for i=1, SMART_BUFF_MaxNum.target do
		button = getglobal("TargetFrameBuff"..i)

		if (not button) then
			button = CreateFrame("Button", "TargetFrameBuff"..i, TargetFrame, "TargetBuffButtonTemplate")
		end

		button:Hide()
		button:SetFrameStrata("MEDIUM")

		local border = button:CreateTexture(button:GetName().."Border", "OVERLAY")
		local textlayer = CreateFrame("Frame", button:GetName().."TextLayer", button)
		local count = getglobal(button:GetName().."Count")
		local cooldown = getglobal(button:GetName().."Cooldown")

		textlayer:SetPoint("TOPLEFT", button, "TOPLEFT")
		textlayer:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT")

		border:SetTexture("Interface/Buttons/UI-Debuff-Overlays")
		border:SetPoint("CENTER",button,"CENTER",0,0)
		border:SetWidth(button:GetWidth()+2)
		border:SetHeight(button:GetHeight()+2)
		border:SetTexCoord(0.296875,0.5703125,0,0.515625)
		border:SetVertexColor(0,1,0)
		count:SetFontObject("SmartStatusBarText")
		count:ClearAllPoints()
		count:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT",1,0)
		count:SetJustifyH("RIGHT")
		count:SetParent(getglobal(button:GetName().."TextLayer"))
		cooldown:SetPoint("CENTER",button,"CENTER",0,2)

		RaiseFrameLevel(cooldown)
		RaiseFrameLevel(textlayer)
	end

	for i=1, SMART_DEBUFF_MaxNum.target do
		button = getglobal("TargetFrameDebuff"..i)

		if (not button) then
			button = CreateFrame("Button", "TargetFrameDebuff"..i, TargetFrame, "TargetDebuffButtonTemplate")
		end

		button:Hide()
		button:SetFrameStrata("MEDIUM")

		local textlayer = CreateFrame("Frame", button:GetName().."TextLayer", button)
		local count = getglobal(button:GetName().."Count")
		local cooldown = getglobal(button:GetName().."Cooldown")

		textlayer:SetPoint("TOPLEFT",button,"TOPLEFT")
		textlayer:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT")

		count:SetFontObject("SmartStatusBarText")
		count:ClearAllPoints()
		count:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT",1,0)
		count:SetJustifyH("RIGHT")
		count:SetParent(getglobal(button:GetName().."TextLayer"))
		cooldown:SetPoint("CENTER",button,"CENTER",0,2)

		RaiseFrameLevel(cooldown)
		RaiseFrameLevel(textlayer)
	end
end

function SmartParty_BuffDebuffCreation()
	local button
	local textlayer, count

	-- Party buff button creation
	for i=1, MAX_PARTY_MEMBERS do
		for j=1, SMART_BUFF_MaxNum.party do
			local button = CreateFrame("Button", "SmartPartyFrame"..i.."Buff"..j, getglobal("PartyMemberFrame"..i), "SmartPartyBuffButtonTemplate")
			if j > 1 then
				button:SetPoint("LEFT", getglobal("SmartPartyFrame"..i.."Buff"..(j-1)), "RIGHT", 2, 0)
			else
				button:SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i), "TOPLEFT", 48, -33)
			end

			button:SetID(j)
			button.id = j
			button:SetFrameStrata("MEDIUM")

			textlayer = CreateFrame("Frame", button:GetName().."TextLayer", button)
			textlayer:SetPoint("TOPLEFT",button,"TOPLEFT")
			textlayer:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT")

			count = getglobal(button:GetName().."Count")
			count:ClearAllPoints()
			count:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT",1,0)
			count:SetJustifyH("RIGHT")
			count:SetParent(textlayer)

			RaiseFrameLevel(getglobal(button:GetName().."Cooldown"))
			RaiseFrameLevel(textlayer)
		end

		for j=1, SMART_BUFF_MaxNum.partypet do
			button = CreateFrame("Button", "SmartPartyFrame"..i.."PetFrameBuff"..j, getglobal("PartyMemberFrame"..i.."PetFrame"), "SmartPartyPetBuffButtonTemplate")
			if j > 1 then
				button:SetPoint("LEFT", getglobal("SmartPartyFrame"..i.."PetFrameBuff"..(j-1)), "RIGHT", 2, 0)
			else
				button:SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i.."PetFrame"), "TOPLEFT", 25, -20)
			end
			button:SetID(j)
			button.id = j
			button:SetFrameStrata("MEDIUM")
			RaiseFrameLevel(button)
		end

		for j=1, SMART_DEBUFF_MaxNum.party do
			button = CreateFrame("Button", "SmartPartyFrame"..i.."Debuff"..j, getglobal("PartyMemberFrame"..i), "SmartPartyDebuffButtonTemplate")
			if j > 1 then
				-- 한줄에 4개씩
				if mod(j, 4) == 1 then
					button:SetPoint("TOPLEFT", getglobal("SmartPartyFrame"..i.."Debuff"..(j-4)), "BOTTOMLEFT", 0, -2)
				else
					button:SetPoint("LEFT", getglobal("SmartPartyFrame"..i.."Debuff"..(j-1)), "RIGHT", 2, 0)
				end
			else
				if SMART_PARTY_Config.statusbartext then
					button:SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i), "TOPLEFT", 198, -13)
				else
					button:SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i), "TOPLEFT", 124, -13)
				end
			end

			button:SetID(j)
			button.id = j
			button:SetFrameStrata("MEDIUM")

			textlayer = CreateFrame("Frame", button:GetName().."TextLayer", button)
			textlayer:SetPoint("TOPLEFT",button,"TOPLEFT")
			textlayer:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT")

			count = getglobal(button:GetName().."Count")
			count:ClearAllPoints()
			count:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT",1,0)
			count:SetJustifyH("RIGHT")
			count:SetParent(textlayer)

			RaiseFrameLevel(getglobal(button:GetName().."Cooldown"))
			RaiseFrameLevel(textlayer)
		end

		for j=1, SMART_DEBUFF_MaxNum.partypet do
			button = CreateFrame("Button", "SmartPartyFrame"..i.."PetFrameDebuff"..j, getglobal("PartyMemberFrame"..i.."PetFrame"), "SmartPartyPetDebuffButtonTemplate")

			if j > 1 then
				button:SetPoint("LEFT", getglobal("SmartPartyFrame"..i.."PetFrameDebuff"..(j-1)), "RIGHT", 2, 0)
			else
				button:SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i.."PetFrame"), "TOPLEFT", 136, -4)
			end

			button:SetID(j)
			button.id = j
			button:SetFrameStrata("MEDIUM")
			RaiseFrameLevel(button)
		end

		getglobal("PartyMemberFrame"..i).numBuffs = 0
		getglobal("PartyMemberFrame"..i).numDebuffs = 0
		getglobal("PartyMemberFrame"..i).buffRows = 0 

		getglobal("PartyMemberFrame"..i.."PetFrame").numBuffs = 0
		getglobal("PartyMemberFrame"..i.."PetFrame").numDebuffs = 0
	end
end

function SmartPet_BuffDebuffCreation()
	local button, i
	local textlayer, count, cooldown

	for i=1, SMART_DEBUFF_MaxNum.pet do
		button = CreateFrame("Button", "SmartPetFrameBuff"..i, PetFrame, "SmartPetBuffButtonTemplate")

		if i > 1 then
			button:SetPoint("LEFT", getglobal("SmartPetFrameBuff"..(i-1)), "RIGHT", 2, 0)
		else
			button:SetPoint("TOPLEFT", PetFrame, "TOPLEFT", 48, -42)
		end

		button:SetID(i)
		button.id = i
		button:SetFrameStrata("MEDIUM")

		textlayer = CreateFrame("Frame", button:GetName().."TextLayer", button)
		textlayer:SetPoint("TOPLEFT",button,"TOPLEFT")
		textlayer:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT")
		count = getglobal(button:GetName().."Count")
		count:ClearAllPoints()
		count:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT",1,0)
		count:SetJustifyH("RIGHT")
		count:SetParent(textlayer)
		cooldown = getglobal(button:GetName().."Cooldown")
		cooldown:SetPoint("CENTER",button,"CENTER",0,2)

		RaiseFrameLevel(cooldown)
		RaiseFrameLevel(textlayer)
	end

	for i=1, SMART_DEBUFF_MaxNum.pet do
		button = CreateFrame("Button","SmartPetFrameDebuff"..i, PetFrame, "SmartPetDebuffButtonTemplate")
		if i > 1 then
			button:SetPoint("LEFT", getglobal("SmartPetFrameDebuff"..(i-1)), "RIGHT", 2, 0)
		else
			button:SetPoint("TOPLEFT", PetFrame, "TOPLEFT", 124, -25)
		end
		button:SetID(i)
		button.id = i
		button:SetFrameStrata("MEDIUM")

		textlayer = CreateFrame("Frame", button:GetName().."TextLayer", button)
		textlayer:SetPoint("TOPLEFT",button,"TOPLEFT")
		textlayer:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT")
		count = getglobal(button:GetName().."Count")
		count:ClearAllPoints()
		count:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT",1,0)
		count:SetJustifyH("RIGHT")
		count:SetParent(textlayer)
		cooldown = getglobal(button:GetName().."Cooldown")
		cooldown:SetPoint("CENTER",button,"CENTER",0,2)

		RaiseFrameLevel(cooldown)
		RaiseFrameLevel(textlayer)
	end

	PetFrame.numBuffs = 0
	PetFrame.numDebuffs = 0
end

function SmartBuffDebuff_PartyPosition()
	local i, frame, yDelta

	for i=1, MAX_PARTY_MEMBERS do
		frame = getglobal("PartyMemberFrame"..i)
		yDelta = math.max(0, (frame.buffRows - 1) * 0.5)

		if SMART_PARTY_Config.statusbartext then
			getglobal("SmartPartyFrame"..i.."Debuff1"):SetPoint("TOPLEFT", frame, "TOPLEFT", 198, -13+yDelta*15)
		else
			getglobal("SmartPartyFrame"..i.."Debuff1"):SetPoint("TOPLEFT", frame, "TOPLEFT", 124, -13+yDelta*15)
		end
	end
end

function SmartBuffDebuff_TargetBorderCheck()
	local i

	for i=1, SMART_BUFF_MaxNum.target do
		if SMART_TARGET_Config.buffborder then
			getglobal("TargetFrameBuff"..i.."Border"):Show()
		else
			getglobal("TargetFrameBuff"..i.."Border"):Hide()
		end
	end
end

function SmartBuffDebuff_TargetDebuffButton_Update()
	local button, i
	local name, rank, icon, count, duration, timeLeft
	local buffCount
	local numBuffs = 0
	local largeBuffList = {}
	local playerIsTarget = UnitIsUnit("player", "target")
	local cooldown, startCooldownTime

	for i=1, SMART_BUFF_ChkNum.target do
		--[[
		-- test code
		if i <= 16 then
		name, rank, icon, count, duration, timeLeft = "얼음 갑옷", "5 레벨", "Interface\\Icons\\Spell_Frost_FrostArmor02", 0, 1800, 1800
		else
		name, rank, icon, count, duration, timeLeft = "얼음 갑옷", "5 레벨", "Interface\\Icons\\Spell_Frost_FrostArmor02", 0, 0, 0
		end
		]]
		name, rank, icon, count, duration, timeLeft = UnitBuff("target", i)
		button = getglobal("TargetFrameBuff"..i)

		if ( not button ) then
			if ( not icon ) then
				break
			else
				button = CreateFrame("Button", "TargetFrameBuff"..i, TargetFrame, "TargetBuffButtonTemplate")
			end
		end
		
		if ( icon ) then
			getglobal("TargetFrameBuff"..i.."Icon"):SetTexture(icon)
			buffCount = getglobal("TargetFrameBuff"..i.."Count")
			button:Show()
			if ( count > 1 ) then
				buffCount:SetText(count)
				buffCount:Show()
			else
				buffCount:Hide()
			end
			
			-- Handle cooldowns
			cooldown = getglobal("TargetFrameBuff"..i.."Cooldown")
			if ( duration ) then
				if ( duration > 0 ) then
					cooldown:Show()
					startCooldownTime = GetTime()-(duration-timeLeft)
					CooldownFrame_SetTimer(cooldown, startCooldownTime, duration, 1)
				else
					cooldown:Hide()
				end
				
				-- Set the buff to be big if the buff is cast by the player and the target is not the player
				if ( not playerIsTarget ) then
					largeBuffList[i] = 1
				end
			else
				cooldown:Hide()
			end

			button.id = i
			numBuffs = numBuffs + 1 
			button:ClearAllPoints()
		else
			button:Hide()
		end
	end
	
	local debuffType, color
	local debuffCount
	local numDebuffs = 0
	local largeDebuffList = {}
	for i=1, SMART_DEBUFF_ChkNum.target do
		local debuffBorder = getglobal("TargetFrameDebuff"..i.."Border")
		--[[
		-- test code
		if i <= 16 then
		name, rank, icon, count, debuffType, duration, timeLeft =
		"얼음 화살", "13 레벨", "Interface\\Icons\\Spell_Frost_FrostBolt02", 0, "Magic", 9, 9
		else
		name, rank, icon, count, debuffType, duration, timeLeft =
		"얼음 화살", "13 레벨", "Interface\\Icons\\Spell_Frost_FrostBolt02", 0, "Magic", 0, 0
		end
		]]
		name, rank, icon, count, debuffType, duration, timeLeft = UnitDebuff("target", i)
		button = getglobal("TargetFrameDebuff"..i)
		if ( not button ) then
			if ( not icon ) then
				break
			else
				button = CreateFrame("Button", "TargetFrameDebuff"..i, TargetFrame, "TargetDebuffButtonTemplate")
				debuffBorder = getglobal("TargetFrameDebuff"..i.."Border")
			end
		end
		if ( icon ) then
			getglobal("TargetFrameDebuff"..i.."Icon"):SetTexture(icon)
			debuffCount = getglobal("TargetFrameDebuff"..i.."Count")
			if ( debuffType ) then
				color = DebuffTypeColor[debuffType]
			else
				color = DebuffTypeColor["none"]
			end
			if ( count > 1 ) then
				debuffCount:SetText(count)
				debuffCount:Show()
			else
				debuffCount:Hide()
			end

			-- Handle cooldowns
			cooldown = getglobal("TargetFrameDebuff"..i.."Cooldown")
			if ( duration  ) then
				if ( duration > 0 ) then
					cooldown:Show()
					startCooldownTime = GetTime()-(duration-timeLeft)
					CooldownFrame_SetTimer(cooldown, startCooldownTime, duration, 1)
				else
					cooldown:Hide()
				end
				-- Set the buff to be big if the buff is cast by the player
				largeDebuffList[i] = 1
			else
				cooldown:Hide()
			end
			
			debuffBorder:SetVertexColor(color.r, color.g, color.b)
			button:Show()
			numDebuffs = numDebuffs + 1
			button:ClearAllPoints()
		else
			button:Hide()
		end
		button.id = i
	end

	local isToTShown = SMART_IsToTShown() 

	-- Figure out general information that affects buff sizing and positioning
	local numFirstRowBuffs
	local buffSize = LARGE_BUFF_SIZE
	local buffFrameSize = LARGE_BUFF_FRAME_SIZE
	local buffWrap

	if (isToTShown)  then
		numFirstRowBuffs = 5
	else
		numFirstRowBuffs = 6
	end

	if (getn(largeBuffList) > 0 or getn(largeDebuffList) > 0) then
		numFirstRowBuffs = numFirstRowBuffs - 1
	end

	-- Shrink the buffs if there are too many of them
	if ( (numBuffs >= numFirstRowBuffs) or (numDebuffs >= numFirstRowBuffs) ) then
		buffSize = SMALL_BUFF_SIZE
		buffFrameSize = SMALL_BUFF_FRAME_SIZE
	end

	-- Reset number of buff rows
	TargetFrame.buffRows = 0

	local size
	local previousWasPlayerCast
	local offset

	if ( UnitIsFriend("player", "target") ) then
		-- Position buffs
		previousWasPlayerCast = nil
		for i=1, numBuffs do
			if ( largeBuffList[i] ) then
				size = LARGE_BUFF_SIZE
				offset = 3
				previousWasPlayerCast = 1
			else
				size = buffSize
				offset = 3
				if ( previousWasPlayerCast ) then
					offset = 6
					previousWasPlayerCast = nil
				end
			end
			TargetFrame_UpdateBuffAnchor("TargetFrameBuff", i, numFirstRowBuffs, numDebuffs, size, offset, isToTShown)
		end

		-- Position debuffs
		previousWasPlayerCast = nil
		for i=1, numDebuffs do
			if ( largeDebuffList[i] ) then
				size = LARGE_BUFF_SIZE
				offset = 4
				previousWasPlayerCast = 1
			else
				size = buffSize
				offset = 4
				if ( previousWasPlayerCast ) then
					offset = 6
					previousWasPlayerCast = nil
				end
			end

			TargetFrame_UpdateDebuffAnchor("TargetFrameDebuff", i, numFirstRowBuffs, numBuffs, size, offset, isToTShown)
		end
	else
		-- Position debuffs
		previousWasPlayerCast = nil
		for i=1, numDebuffs do
			if ( largeDebuffList[i] ) then
				size = LARGE_BUFF_SIZE
				offset = 4
				previousWasPlayerCast = 1
			else
				size = buffSize
				offset = 4
				if ( previousWasPlayerCast ) then
					offset = 6
					previousWasPlayerCast = nil
				end
			end

			TargetFrame_UpdateDebuffAnchor("TargetFrameDebuff", i, numFirstRowBuffs, numBuffs, size, offset, isToTShown)
		end

		-- Position buffs
		previousWasPlayerCast = nil
		for i=1, numBuffs do
			if ( largeBuffList[i] ) then
				size = LARGE_BUFF_SIZE
				offset = 3
				previousWasPlayerCast = 1
			else
				size = buffSize
				offset = 3
				if ( previousWasPlayerCast ) then
					offset = 6
					previousWasPlayerCast = nil
				end
			end
			TargetFrame_UpdateBuffAnchor("TargetFrameBuff", i, numFirstRowBuffs, numDebuffs, size, offset, isToTShown)
		end
	end

	-- update the spell bar position
	Target_Spellbar_AdjustPosition()
end

function SmartBuffDebuff_TargetFrame_UpdateBuffAnchor(buffName, index, numFirstRowBuffs, numDebuffs, buffSize, offset, hasTargetofTarget)
	local buff = getglobal(buffName..index)
	local maxWrapRows

	if SmartToTTFrame.enable then
		maxWrapRows = 5
	else
		maxWrapRows = 3
	end

	if (index == 1) then
		if (UnitIsFriend("player", "target")) then
			buff:SetPoint("TOPLEFT", TargetFrame, "BOTTOMLEFT", SMART_BUFFDEBUFF_POSITION.x, SMART_BUFFDEBUFF_POSITION.y)
		else
			if (numDebuffs > 0) then
				buff:SetPoint("TOPLEFT", TargetFrameDebuffs, "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
			else
				buff:SetPoint("TOPLEFT", TargetFrame, "BOTTOMLEFT", SMART_BUFFDEBUFF_POSITION.x, (SMART_BUFFDEBUFF_POSITION.y-buffSize-TargetFrame.buffSpacing))
			end
		end
		TargetFrameBuffs:SetPoint("TOPLEFT", buff, "TOPLEFT", 0, 0)
		TargetFrameBuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	elseif (index == (numFirstRowBuffs+1)) then
		buff:SetPoint("TOPLEFT", getglobal(buffName..1), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
		TargetFrameBuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	--elseif (hasTargetofTarget and index == (2*numFirstRowBuffs+1)) then
		--buff:SetPoint("TOPLEFT", getglobal(buffName..(numFirstRowBuffs+1)), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
	elseif (hasTargetofTarget and mod(index, numFirstRowBuffs) == 1 and TargetFrame.buffRows < maxWrapRows) then
		buff:SetPoint("TOPLEFT", getglobal(buffName..(index-numFirstRowBuffs)), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
		TargetFrameBuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	elseif ((not hasTargetofTarget or TargetFrame.buffRows >= maxWrapRows) and index > numFirstRowBuffs and mod(index+(TARGET_BUFFS_PER_ROW-numFirstRowBuffs), TARGET_BUFFS_PER_ROW) == 1) then
		-- Make a new row, have to take the number of buffs in the first row into account
		buff:SetPoint("TOPLEFT", getglobal(buffName..(index-TARGET_BUFFS_PER_ROW)), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
		TargetFrameBuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	else
		-- Just anchor to previous
		buff:SetPoint("TOPLEFT", getglobal(buffName..(index-1)), "TOPRIGHT", offset, 0)
	end

	-- Resize
	buff:SetWidth(buffSize)
	buff:SetHeight(buffSize)
end

function SmartBuffDebuff_TargetFrame_UpdateDebuffAnchor(buffName, index, numFirstRowBuffs, numBuffs, buffSize, offset, hasTargetofTarget)
	local buff = getglobal(buffName..index)
	local maxWrapRows

	if SmartToTTFrame.enable then
		maxWrapRows = 5
	else
		maxWrapRows = 3
	end

	if (index == 1) then
		if (UnitIsFriend("player", "target") and (numBuffs > 0)) then
			buff:SetPoint("TOPLEFT", TargetFrameBuffs, "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
		else
			buff:SetPoint("TOPLEFT", TargetFrame, "BOTTOMLEFT", SMART_BUFFDEBUFF_POSITION.x, SMART_BUFFDEBUFF_POSITION.y)
		end
		TargetFrameDebuffs:SetPoint("TOPLEFT", buff, "TOPLEFT", 0, 0)
		TargetFrameDebuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	elseif ( index == (numFirstRowBuffs+1) ) then
		buff:SetPoint("TOPLEFT", getglobal(buffName..1), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
		TargetFrameDebuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	--elseif ( hasTargetofTarget and index == (2*numFirstRowBuffs+1) ) then
		--buff:SetPoint("TOPLEFT", getglobal(buffName..(numFirstRowBuffs+1)), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
	elseif (hasTargetofTarget and mod(index, numFirstRowBuffs) == 1 and TargetFrame.buffRows < maxWrapRows) then
		buff:SetPoint("TOPLEFT", getglobal(buffName..(index-numFirstRowBuffs)), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
		TargetFrameDebuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	elseif ((not hasTargetofTarget or TargetFrame.buffRows >= maxWrapRows) and index > numFirstRowBuffs and mod(index+(TARGET_DEBUFFS_PER_ROW-numFirstRowBuffs), TARGET_DEBUFFS_PER_ROW) == 1) then
		-- Make a new row
		buff:SetPoint("TOPLEFT", getglobal(buffName..(index-TARGET_DEBUFFS_PER_ROW)), "BOTTOMLEFT", 0, -TargetFrame.buffSpacing)
		TargetFrameDebuffs:SetPoint("BOTTOMLEFT", buff, "BOTTOMLEFT", 0, 0)
		TargetFrame.buffRows = TargetFrame.buffRows+1
	else
		-- Just anchor to previous
		buff:SetPoint("TOPLEFT", getglobal(buffName..(index-1)), "TOPRIGHT", offset, 0)
	end

	-- Resize
	buff:SetWidth(buffSize)
	buff:SetHeight(buffSize)
	local debuffFrame = getglobal(buffName..index.."Border")
	debuffFrame:SetWidth(buffSize+2)
	debuffFrame:SetHeight(buffSize+2)
end

function SmartBuffDebuff_RefreshBuffs(frame, showBuffs, unit)
	local id = frame:GetID()
	local checkUnit, chkBuff, chkDebuff, maxBuff, maxDebuff, buffFilter, debuffFilter

	if (frame == getglobal("PartyMemberFrame"..id)) then
		checkUnit = "party"..id
		chkBuff = SMART_BUFF_ChkNum.party
		chkDebuff = SMART_DEBUFF_ChkNum.party
		maxBuff = SMART_BUFF_MaxNum.party
		maxDebuff = SMART_DEBUFF_MaxNum.party
		buffFilter = SMART_PARTY_Config.bufffilter
		debuffFilter = SMART_PARTY_Config.debufffilter
	elseif (frame == PetFrame) then
		checkUnit = "pet"
		chkBuff = SMART_BUFF_ChkNum.pet
		chkDebuff = SMART_DEBUFF_ChkNum.pet
		maxBuff = SMART_BUFF_MaxNum.pet
		maxDebuff = SMART_DEBUFF_MaxNum.pet
		buffFilter = false
		debuffFilter = false
	elseif (frame == getglobal("PartyTargetFrame"..id)) then
		--DEFAULT_CHAT_FRAME:AddMessage("SUF: Debug: RefreshBuffs on "..frame:GetName())
		return
	else
		return _RefreshBuffs(frame, showBuffs, unit)
	end

	if checkUnit ~= unit then
		DEFAULT_CHAT_FRAME:AddMessage(string.format("SUF: RefreshBuffs: frame: %s unit: %s checkUnit: %s", frame:GetName(), unit, checkUnit))
	end

	frame.hasDispellable = nil

	local name, rank, icon, count
	local duration, timeLeft, cooldown, startCooldownTime
	local buffButton, buffIcon, buffCount, buffBorder

	-- Buff Refresh Check
	-- If buffFilter is true, repeat CheckBuff until maxBuff
	-- But buffFilter is false, repeat CheckBuff until Exsist buffImage
	-- This rule apply only PartyMemberFrame
	local idxBuff = 0

	if chkBuff > 0 then
		for i=1, maxBuff do
			name, rank, icon, count, duration, timeLeft = UnitBuff(checkUnit, i, buffFilter)

			if (icon) then
				idxBuff = idxBuff + 1

				if (checkUnit == ("party"..id)) then
					buffButton = getglobal("SmartPartyFrame"..id.."Buff"..idxBuff)
				elseif (checkUnit == "pet") then
					buffButton = getglobal("SmartPetFrameBuff"..idxBuff)
				end

				buffIcon = getglobal(buffButton:GetName().."Icon")
				buffCount = getglobal(buffButton:GetName().."Count")
				cooldown = getglobal(buffButton:GetName().."Cooldown")

				if (duration) then
					if (duration > 0) then
						cooldown:Show()
						startCooldownTime = GetTime() - (duration - timeLeft)
						CooldownFrame_SetTimer(cooldown, startCooldownTime, duration, 1)
					else
						cooldown:Hide()
					end
				else
					cooldown:Hide()
				end

				buffIcon:SetTexture(icon)
				buffButton:SetID(idxBuff)
				buffButton.id = idxBuff
				buffButton:Show()

				if (count > 1) then
					buffCount:SetText(count)
					buffCount:Show()
				else
					buffCount:Hide()
				end
				if idxBuff == chkBuff then
					break
				end
			else
				if not buffFilter then
					break
				end
			end
		end
	end

	if idxBuff < frame.numBuffs then
		for i = (idxBuff+1), frame.numBuffs do
			if (checkUnit == ("party"..id)) then
				getglobal("SmartPartyFrame"..id.."Buff"..i):Hide()
			elseif (checkUnit == "pet") then
				getglobal("SmartPetFrameBuff"..i):Hide()
			end
		end
	end

	frame.numBuffs = idxBuff

	-- Debuff Refresh Check
	-- If debuffFilter is true, repeat CheckDebuff until maxBuff
	-- But debuffFilter is false, repeat CheckDebuff until Exsist debuffImage
	-- This rule apply only PartyMemberFrame
	local idxDebuff = 0
	local debuffTotal = 0
	local debuffType, debuffColor, statusColor, unitStatus

	if chkDebuff > 0 then
		if checkUnit == "party"..id then
			unitStatus = getglobal(frame:GetName().."Status")
		end
 
		for i=1, maxDebuff do
			--[[
			if i <= 8 then
				name, rank, icon, count, debuffType, duration, timeLeft =
				"얼음 화살", "13 레벨", "Interface\\Icons\\Spell_Frost_FrostBolt02", 0, "Magic", 9, 9
			else]]
				name, rank, icon, count, debuffType, duration, timeLeft = UnitDebuff(checkUnit, i, debuffFilter)
			--end

			if (icon) then
				idxDebuff = idxDebuff + 1

				if (checkUnit == ("party"..id)) then
					buffButton = getglobal("SmartPartyFrame"..id.."Debuff"..idxDebuff)
				elseif (checkUnit == "pet") then
					buffButton = getglobal("SmartPetFrameDebuff"..idxDebuff)
				end

				buffIcon = getglobal(buffButton:GetName().."Icon")
				buffBorder = getglobal(buffButton:GetName().."Border")
				buffCount = getglobal(buffButton:GetName().."Count")
				cooldown = getglobal(buffButton:GetName().."Cooldown")

				if (duration) then
					if (duration > 0) then
						cooldown:Show()
						startCooldownTime = GetTime()-(duration-timeLeft)
						CooldownFrame_SetTimer(cooldown, startCooldownTime, duration, 1)
					else
						cooldown:Hide()
					end
				else
					cooldown:Hide()
				end

				buffIcon:SetTexture(icon)

				if (debuffType) then
					debuffColor = DebuffTypeColor[debuffType]
					statusColor = DebuffTypeColor[debuffType]
					frame.hasDispellable = 1
					debuffTotal = debuffTotal + 1
				else
					debuffColor = DebuffTypeColor["none"]
				end

				buffBorder:SetVertexColor(debuffColor.r, debuffColor.g, debuffColor.b)

				if (count > 1) then
					buffCount:SetText(count)
					buffCount:Show()
				else
					buffCount:Hide()
				end

				buffButton:SetID(idxDebuff)
				buffButton.id = idxDebuff
				buffButton:Show()

				if idxDebuff == chkDebuff then
					break
				end
			else
				if not debuffFilter then
					break
				end
			end
		end
	end

	if idxDebuff < frame.numDebuffs then
		for i = (idxDebuff+1), frame.numDebuffs do
			if (checkUnit == ("party"..id)) then
				getglobal("SmartPartyFrame"..id.."Debuff"..i):Hide()
			elseif (checkUnit == "pet") then
				getglobal("SmartPetFrameDebuff"..i):Hide()
			end
		end
	end

	frame.numDebuffs = idxDebuff

	if (checkUnit == ("party"..id)) then
		frame.buffRows = math.ceil(frame.numDebuffs / 4)
		local yDelta = math.max(0, (frame.buffRows - 1) * 0.5)

		if SMART_PARTY_Config.statusbartext then
			getglobal("SmartPartyFrame"..id.."Debuff1"):SetPoint("TOPLEFT", frame, "TOPLEFT", 198, -13+yDelta*15)
		else
			getglobal("SmartPartyFrame"..id.."Debuff1"):SetPoint("TOPLEFT", frame, "TOPLEFT", 124, -13+yDelta*15)
		end
	end

	-- Reset unitStatus overlay graphic timer
	if (frame.numDebuffs) then
		if (debuffTotal >= frame.numDebuffs) then
			frame.debuffCountdown = 30
		end
	end

	if (unitStatus and statusColor) then
		unitStatus:SetVertexColor(statusColor.r, statusColor.g, statusColor.b)
	end
end

function SmartBuffDebuff_PartyMemberFrame_RefreshPetBuffs(id)
	if (not id) then
		id = this:GetID()
	end

	local petFrame, unit, maxBuff, maxDebuff

	petFrame = getglobal("PartyMemberFrame"..id.."PetFrame")
	unit = "partypet"..id
	chkBuff = SMART_BUFF_ChkNum.partypet
	chkDebuff = SMART_DEBUFF_ChkNum.partypet
	maxBuff = SMART_BUFF_MaxNum.partypet
	maxDebuff = SMART_DEBUFF_MaxNum.partypet

	-- Buff Refresh Check
	local idxBuff = 0
	if chkBuff > 0 then
		local buffImage, buffButton, buffIcon
		for i = 1, maxBuff do
			_, _, buffImage, _, _, _ = UnitBuff(unit, i, SMART_PARTY_Config.bufffilter)

			if (buffImage) then
				idxBuff = idxBuff + 1
				buffButton = getglobal("SmartPartyFrame"..id.."PetFrameBuff"..idxBuff)
				buffIcon = getglobal(buffButton:GetName().."Icon")
				buffIcon:SetTexture(buffImage)
				buffButton:SetID(idxBuff)
				buffButton.id = idxBuff
				buffButton:Show()

				if idxBuff == chkBuff then
					break
				end
			else
				break
			end
		end
	end

	if idxBuff < petFrame.numBuffs then
		for i = (idxBuff+1), petFrame.numBuffs do
			getglobal("SmartPartyFrame"..id.."PetFrameBuff"..i):Hide()
		end
	end

	petFrame.numBuffs = idxBuff

	-- Debuff Refresh Check
	local idxDebuff = 0
	if chkDebuff > 0 then
		local debuffImage, debuffStack, debuffType
		local debuffButton, debuffIcon, debuffBorder, debuffCount, debuffColor
		for i = 1, maxDebuff do
			_, _, debuffImage, debuffStack, debuffType, _, _ = UnitDebuff(unit, i, SMART_PARTY_Config.debufffilter)

			if (debuffImage) then
				idxDebuff = idxDebuff + 1
				debuffButton = getglobal("SmartPartyFrame"..id.."PetFrameDebuff"..i)
				debuffIcon = getglobal(debuffButton:GetName().."Icon")
				debuffBorder = getglobal(debuffButton:GetName().."Border")
				debuffCount = getglobal(debuffButton:GetName().."Count")

				if (debuffType) then
					debuffColor = DebuffTypeColor[debuffType]
				else
					debuffColor = DebuffTypeColor["none"]
				end

				debuffBorder:SetVertexColor(debuffColor.r, debuffColor.g, debuffColor.b)

				if (debuffStack > 1) then
					debuffCount:SetText(debuffStack)
					debuffCount:Show()
				else
					debuffCount:Hide()
				end

				debuffIcon:SetTexture(debuffImage)
				debuffButton:SetID(idxDebuff)
				debuffButton.id = idxDebuff
				debuffButton:Show()

				if idxDebuff == chkDebuff then
					break
				end
			else
				break
			end
		end
	end

	if idxDebuff < petFrame.numDebuffs then
		for i = (idxDebuff+1), petFrame.numDebuffs do
			getglobal("SmartPartyFrame"..id.."PetFrameDebuff"..i):Hide()
		end
	end

	petFrame.numDebuffs = idxDebuff
end

function PartyMemberBuffTooltip_Update(isPet)
	-- Intentionally empty: Since we already have a more advanced buff/debuff
	-- display than the tooltip, the tooltip doesn't make much sense to show.
end
