--------------------------------------------
--
-- SMART - BUFF/DEBUFF
--
--------------------------------------------
SMART_BUFFDEBUFF_ENABLE = true
SMART_BUFF_ChkNum = {party=24,pet=16,partypet=16}
SMART_BUFF_MaxNum = {party=24,pet=16,partypet=16}
SMART_DEBUFF_ChkNum = {party=8,pet=6,partypet=6}
SMART_DEBUFF_MaxNum = {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 _RefreshBuffs
local _PartyMemberFrame_RefreshPetBuffs

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

	if not initialized then
		initialized = true

		SmartParty_BuffDebuffCreation()
		SmartPet_BuffDebuffCreation()

		_RefreshBuffs = RefreshBuffs
		_PartyMemberFrame_RefreshPetBuffs = PartyMemberFrame_RefreshPetBuffs

		RefreshBuffs = SmartBuffDebuff_RefreshBuffs
		PartyMemberFrame_RefreshPetBuffs = SmartBuffDebuff_PartyMemberFrame_RefreshPetBuffs
	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_PartyPosition()
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개씩
				01 02 03 04
				05 06 07 08
				09 10 11 12
				13 14 15 16
				]]
				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", 200, -13)
				else
					button:SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i), "TOPRIGHT", 0, -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 y
	for i=1, MAX_PARTY_MEMBERS do
		y = -13 + math.max(0, (getglobal("PartyMemberFrame"..i).buffRows - 1) * 0.5) * 15
		if SMART_PARTY_Config.statusbartext then
			getglobal("SmartPartyFrame"..i.."Debuff1"):SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i), "TOPLEFT", 200, y)
		else
			getglobal("SmartPartyFrame"..i.."Debuff1"):SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..i), "TOPRIGHT", 0, y)
		end
	end
end

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

	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

		if SMART_PARTY_Config.bufffilter then
			buffFilter = buffFilter .. "|RAID"
		end

		if SMART_PARTY_Config.debuffFilter then
			debuffFilter = debuffFilter.."|RAID"
		end
	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
	elseif (frame == getglobal("PartyTargetFrame"..id)) then
		--DEFAULT_CHAT_FRAME:AddMessage("SUF: Debug: RefreshBuffs on "..frame:GetName())
		return
	else
		return _RefreshBuffs(frame, showBuffs, unit, numBuffs)
	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, endtime, cooldown
	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, endtime = UnitAura(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 and duration > 0 and endtime ~= nil) then
					cooldown:Show()
					CooldownFrame_SetTimer(cooldown, GetTime(), endtime-GetTime(), 1)
				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, endtime =
				"얼음 화살", "13 레벨", "Interface\\Icons\\Spell_Frost_FrostBolt02", 0, "Magic", 9, 9
			else]]
				name, rank, icon, count, debuffType, duration, endtime = UnitAura(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 and duration > 0 and endtime ~= nil) then
					cooldown:Show()
					CooldownFrame_SetTimer(cooldown, GetTime(), endtime-GetTime(), 1)
				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 y = -13 + math.max(0, (frame.buffRows - 1) * 0.5) * 15

		if SMART_PARTY_Config.statusbartext then
			getglobal("SmartPartyFrame"..id.."Debuff1"):SetPoint("TOPLEFT", frame, "TOPLEFT", 200, y)
		else
			getglobal("SmartPartyFrame"..id.."Debuff1"):SetPoint("TOPLEFT", frame, "TOPRIGHT", 0, y)
		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(self, id)
	if (not id) then
		id = self: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

	local buffFilter = "HELPFUL"
	if (SMART_PARTY_Config.bufffilter) then buffFilter = buffFilter .. "|RAID" end

	-- Buff Refresh Check
	local idxBuff = 0
	if chkBuff > 0 then
		local buffImage, buffButton, buffIcon
		for i = 1, maxBuff do
			_, _, buffImage = UnitAura(unit, i, 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

	local debuffFilter = "HARMFUL"

	if SMART_PARTY_Config.debufffilter then
		debuffFilter = debuffFilter .. "|RAID"
	end

	-- 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, _, _ = UnitAura(unit, i, 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
