--------------------------------------------
--
-- SMART - PARTY
--
--------------------------------------------
SMART_PARTY_ENABLE = true
SMART_PARTY_Config = {statusbartext=true,percent=false,loss=true,losstopercent=false,level=true,color=true,namewithserver=true,bufffilter=false,debufffilter=false,groupicon=true,movable=false,movablegroup=false,castingbar=false,target=false}

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

SmartParty:SetScript("OnEvent", function()
	PartyMemberFrame_UpdatePet = SmartParty_UpdatePet
end)

-- This function is from Blizzard FrameXML
function SmartParty_UpdatePet(id)
	if ( not id ) then
		id = this:GetID();
	end

	local frameName = "PartyMemberFrame"..id;
	local petFrame = getglobal("PartyMemberFrame"..id.."PetFrame");

	if ( UnitIsConnected("party"..id) and UnitExists("partypet"..id) and SHOW_PARTY_PETS == "1" ) then
		petFrame:Show();
		petFrame:SetPoint("TOPLEFT", frameName, "TOPLEFT", 23, -56); -- changed y for SUF
	else
		petFrame:Hide();
		petFrame:SetPoint("TOPLEFT", frameName, "TOPLEFT", 23, -40); -- changed y for SUF
	end

	PartyMemberFrame_RefreshPetBuffs(id);
	UpdatePartyMemberBackground();
end

------------------------------------------------------------------------------------
-- Party Frame
------------------------------------------------------------------------------------
function SmartParty_OnLoad()
	this.unit = this:GetParent().unit

	this:RegisterEvent("UNIT_FACTION")
	this:RegisterEvent("UNIT_LEVEL")
	this:RegisterEvent("UNIT_HEALTH")
	this:RegisterEvent("UNIT_MANA")
	this:RegisterEvent("UNIT_RAGE")
	this:RegisterEvent("UNIT_ENERGY")
	this:RegisterEvent("UNIT_MAXHEALTH")
	this:RegisterEvent("UNIT_MAXMANA")
	this:RegisterEvent("UNIT_MAXRAGE")
	this:RegisterEvent("UNIT_MAXENERGY")
	this:RegisterEvent("UNIT_DISPLAYPOWER")
	this:RegisterEvent("RAID_TARGET_UPDATE")
	this:RegisterEvent("VARIABLES_LOADED")
	this:RegisterEvent("PLAYER_ENTERING_WORLD")
	this:RegisterEvent("PARTY_MEMBERS_CHANGED")
	this:RegisterEvent("PARTY_MEMBER_ENABLE")
	this:RegisterEvent("PARTY_MEMBER_DISABLE")
	this:RegisterEvent("PARTY_LEADER_CHANGED")
	this:GetParent().smartFrame = this

	this:SetFrameLevel((this:GetParent():GetFrameLevel())+2)
	this:GetParent():SetMovable(true)
	this:GetParent():SetHitRectInsets(0, 8, 4, 4)
	getglobal(this:GetParent():GetName().."HealthBar"):SetHitRectInsets(0,getglobal(this:GetParent():GetName().."HealthBar"):GetWidth(),0,getglobal(this:GetParent():GetName().."HealthBar"):GetHeight())
	getglobal(this:GetParent():GetName().."ManaBar"):SetHitRectInsets(0,getglobal(this:GetParent():GetName().."ManaBar"):GetWidth(),0,getglobal(this:GetParent():GetName().."ManaBar"):GetHeight())
	
	if getglobal(this:GetParent():GetName().."HealthBarText") then
		getglobal(this:GetParent():GetName().."HealthBarText"):SetAlpha(0)
	end

	if getglobal(this:GetParent():GetName().."ManaBarText") then
		getglobal(this:GetParent():GetName().."ManaBarText"):SetAlpha(0)
	end

	this.statusCounter = 0
	this.statusSign = -1

	this:CreateTexture(this:GetName().."RaidTargetIcon", "OVERLAY")
	this.raidtargeticon = getglobal(this:GetName().."RaidTargetIcon")
	this.raidtargeticon:ClearAllPoints()
	this.raidtargeticon:SetPoint("TOPLEFT", this:GetParent():GetName().."Portrait", "TOPLEFT", 0, 2)
	this.raidtargeticon:SetWidth(25)
	this.raidtargeticon:SetHeight(25)
	this.raidtargeticon:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons");

	SmartParty_RaidTargetIcon(this)

	this:GetParent():CreateTexture(this:GetParent():GetName().."StatusTexture", "OVERLAY")
	local texture = getglobal(this:GetParent():GetName().."StatusTexture")
	texture:SetPoint("TOPLEFT",getglobal(this:GetParent():GetName().."Portrait"), "TOPLEFT", 0, 0)
	texture:SetPoint("BOTTOMRIGHT",getglobal(this:GetParent():GetName().."Portrait"), "BOTTOMRIGHT", 0, 0)
	texture:SetTexture("Interface\\AddOns\\SmartUnitFrame\\CircleFlash.tga")
	texture:SetTexCoordModifiesRect(false)
	texture:SetTexCoord(0,1,0,1)
	texture:SetBlendMode("ADD")
	texture:SetVertexColor(1,0.5,0)
end

function SmartParty_AffectingCombatOnUpdate(elapsed)
	local texture = getglobal(this:GetParent():GetName().."StatusTexture")

	if UnitAffectingCombat(this.unit) then
		if not texture:IsShown() then
			texture:Show()
		end

		local alpha = 255
		local counter = this.statusCounter + elapsed
		local sign = this.statusSign

		if (counter > 0.5) then
			sign = -sign
			this.statusSign = sign
		end

		counter = mod(counter, 0.5)

		this.statusCounter = counter

		if (sign == 1) then
			alpha = (55 + (counter * 400)) / 255
		else
			alpha = (255 - (counter * 400)) / 255
		end

		texture:SetAlpha(alpha)
	else
		if texture:IsShown() then
			texture:Hide()
		end
	end
end

function SmartParty_ResetPosition()
	if PartyMemberFrame1:IsUserPlaced() then
		PartyMemberFrame1:ClearAllPoints()

		if SMART_GROUPICON_ENABLE or SMART_PVPICON_ENABLE then
			PartyMemberFrame1:SetPoint("TOPLEFT", "PlayerFrame", "TOPLEFT", 40, -180)
		else
			PartyMemberFrame1:SetPoint("TOPLEFT", "PlayerFrame", "TOPLEFT", 24, -180)
		end
	else
		local _, _, _, _, yOfs = PartyMemberFrame1:GetPoint()

		PartyMemberFrame1:ClearAllPoints()

		if SMART_GROUPICON_ENABLE or SMART_PVPICON_ENABLE then
			PartyMemberFrame1:SetPoint("TOPLEFT", "PlayerFrame", "TOPLEFT", 40, yOfs)
		else
			PartyMemberFrame1:SetPoint("TOPLEFT", "PlayerFrame", "TOPLEFT", 24, yOfs)
		end
	end

	PartyMemberFrame1:SetUserPlaced(false)
end

function SmartParty_GroupCheck(groupCheck)
	if SMART_PARTY_Config.movablegroup or groupCheck then
		local frame

		for id=2, MAX_PARTY_MEMBERS do
			frame = getglobal("PartyMemberFrame"..id)

			if frame:IsUserPlaced() then
				frame:ClearAllPoints()
				frame:SetPoint("TOPLEFT", getglobal("PartyMemberFrame"..(id-1).."PetFrame"), "BOTTOMLEFT", -23, -10)
				frame:SetUserPlaced(false)
			end
		end
	end
end

-- Dead or Ghost / Offline
function SmartParty_SetStatusText(frame)
	local statusText = getglobal(frame:GetName().."StatusText")

	if UnitIsConnected(frame.unit) then
		if UnitIsDead(frame.unit) then
			if SMART_CheckFeign(frame.unit) then
				statusText:SetText("죽은척하기")
			else
				statusText:SetText("죽음")
			end
			statusText:Show()
		elseif UnitIsGhost(frame.unit) then
			statusText:SetText("유령")
			statusText:Show()
		else
			statusText:SetText("")
			statusText:Hide()
		end
	else
		if UnitIsDead(frame.unit) then
			statusText:SetText("죽음")
			statusText:Show()
		elseif UnitIsPlayer(frame.unit) then
			statusText:SetText("오프라인")
			statusText:Show()
		else
			statusText:SetText("")
			statusText:Hide()
		end
	end
end

function SmartParty_HealthUpdate(frame)
	-- HP/MP Percent or HP/MaxHP MP/MaxMP
	if SMART_PARTY_Config.statusbartext then
		if SMART_PARTY_Config.percent then
			getglobal(frame:GetName().."HealthBarText"):Hide()
			SMART_HealthPercent(getglobal(frame:GetName().."HealthPercent"), frame.unit)
		else
			getglobal(frame:GetName().."HealthPercent"):Hide()
			SMART_HealthUpdate(getglobal(frame:GetName().."HealthBarText"), frame.unit)
		end
	else
		getglobal(frame:GetName().."HealthBarText"):Hide()
		getglobal(frame:GetName().."HealthPercent"):Hide()
	end

	-- Health Loss SHOW/HIDE
	if SMART_PARTY_Config.loss then
		if SMART_PARTY_Config.losstopercent then
			SMART_HealthPercent(getglobal(frame:GetName().."HealthLoss"), frame.unit)
		else
			SMART_HealthLoss(getglobal(frame:GetName().."HealthLoss"), frame.unit)
		end
	else
		getglobal(frame:GetName().."HealthLoss"):Hide()
	end
end

-- HP/MP Percent or HP/MaxHP MP/MaxMP
function SmartParty_ManaUpdate(frame)
	if SMART_PARTY_Config.statusbartext then
		if SMART_PARTY_Config.percent then
			getglobal(frame:GetName().."ManaBarText"):Hide()
			SMART_ManaPercent(getglobal(frame:GetName().."ManaPercent"), frame.unit)
		else
			getglobal(frame:GetName().."ManaPercent"):Hide()
			SMART_ManaUpdate(getglobal(frame:GetName().."ManaBarText"), frame.unit)
		end
	else
		getglobal(frame:GetName().."ManaBarText"):Hide()
		getglobal(frame:GetName().."ManaPercent"):Hide()
	end
end

function SmartParty_LevelUpdate(frame)
	if SMART_PARTY_Config.level and UnitIsConnected(frame.unit) then
		local levelText = getglobal(frame:GetName().."LevelText")
		levelText:SetText(UnitLevel(frame.unit))
		levelText:Show()
		if UnitCanAttack(frame.unit, "player") or UnitCanAttack("player", frame.unit) then
			levelText:SetTextColor(1,0,0)
		else
			levelText:SetTextColor(1,0.82,0)
		end
	else
		getglobal(frame:GetName().."LevelText"):Hide()
	end
end

-- Name coloring by class
function SmartParty_ColorName(frame)
	local colorName = getglobal(frame:GetParent():GetName().."Name")

	if UnitIsConnected(frame.unit) then
		if UnitCanAttack(frame.unit, "player") or UnitCanAttack("player", frame.unit) then
			colorName:SetTextColor(1,0,0)
		else
			if SMART_PARTY_Config.color then
				local _, englishClass = UnitClass(frame.unit)
				if (englishClass) then
					local classColor = RAID_CLASS_COLORS[englishClass]
					colorName:SetTextColor(classColor.r,classColor.g,classColor.b)
				else
					colorName:SetTextColor(1,0.82,0)
				end
			else
				colorName:SetTextColor(1,0.82,0)
			end
		end
	else
		colorName:SetTextColor(0.75, 0.75, 0.75)
	end

	colorName:SetText(GetUnitName(frame.unit, SMART_PARTY_Config.namewithserver))
end

-- Raid Target Icon
function SmartParty_RaidTargetIcon(frame)
	SMART_RaidTargetCheck(frame.raidtargeticon, frame.unit)
end

function SmartParty_UpdateMember(frame)
	if not frame then
		frame = this
	end

	if frame then
		if frame.smartFrame then
			frame = frame.smartFrame
		end

		SmartParty_SetStatusText(frame)
		SmartParty_HealthUpdate(frame)
		SmartParty_ManaUpdate(frame)
		SmartParty_LevelUpdate(frame)
		SmartParty_ColorName(frame)
		SmartParty_RaidTargetIcon(frame)
		--RefreshBuffs(frame:GetParent(), 0, frame.unit) -- GetParent() == PartyMemberFrame#
		--SetPortraitTexture(getglobal(frame:GetParent():GetName().."Portrait"), frame.unit)
	end
end

function SmartParty_OnEvent(event)
	if (event == "VARIABLES_LOADED") then
		local mastericon = getglobal(this:GetParent():GetName().."MasterIcon")
		local pvpicon = getglobal(this:GetParent():GetName().."PVPIcon")

		if mastericon then
			mastericon:SetPoint("TOPLEFT", mastericon:GetParent(),"TOPLEFT",29,-31)
		end

		if pvpicon then
			pvpicon:ClearAllPoints()
			pvpicon:SetPoint("TOPLEFT", getglobal(this:GetParent():GetName().."Portrait"),"TOPLEFT", -15, -5)
		end

		if (SMART_CLASSICON_ENABLE and SMART_CLASSICON_PARTY) or (IsAddOnLoaded("ClassIcons")) then
			getglobal(this:GetName().."LevelText"):ClearAllPoints()
			getglobal(this:GetName().."LevelText"):SetPoint("BOTTOMLEFT",getglobal(this:GetParent():GetName().."Portrait"),"BOTTOMLEFT",2,-2)
			getglobal(this:GetName().."LevelText"):SetJustifyH("LEFT")
		end

		hooksecurefunc("PartyMemberFrame_UpdateMember", function(...) SmartParty_UpdateMember(...) end)
		--hooksecurefunc("PartyMemberFrame_UpdatePet", function(...) SmartParty_UpdatePet(...) end)
		--PartyMemberFrame_UpdatePet(this:GetID())
		--SmartParty_UpdatePet(this:GetID())
		return
	end

	if UnitExists(this.unit) then
		if (event == "PLAYER_ENTERING_WORLD") or (event == "PARTY_MEMBERS_CHANGED") or (event == "PARTY_LEADER_CHANGED") then
			SmartParty_UpdateMember(this)
		elseif (event == "PARTY_MEMBER_DISABLE") or (event == "PARTY_MEMBER_ENABLE") then
			if arg1 == this.unit then
				SmartParty_UpdateMember(this)
			end
		elseif (event == "UNIT_HEALTH") or (event == "UNIT_MAXHEALTH") then
			if UnitIsUnit(this.unit, arg1) then
				SmartParty_HealthUpdate(this)
				SmartParty_SetStatusText(this)
			end
		elseif (event == "UNIT_DISPLAYPOWER") or (event == "UNIT_MANA") or (event == "UNIT_RAGE") or (event == "UNIT_ENERGY") or (event == "UNIT_MAXMANA") or (event == "UNIT_MAXRAGE") or (event == "UNIT_MAXENERGY") then
			if UnitIsUnit(this.unit, arg1) then
				SmartParty_ManaUpdate(this)
			end
		elseif (event == "UNIT_FACTION") then
			if UnitIsUnit(this.unit, arg1) or (arg1 == "player") then
				SmartParty_ColorName(this)
				SmartParty_LevelUpdate(this)
			end
		elseif (event == "UNIT_LEVEL") then
			if UnitIsUnit(this.unit, arg1) then
				SmartParty_LevelUpdate(this)
			end
		elseif (event == "UNIT_AURA") then
			if UnitIsUnit(this.unit, arg1) then
				RefreshBuffs(this:GetParent(), 0, this.unit)
			end
		elseif (event == "RAID_TARGET_UPDATE") then
			SmartParty_RaidTargetIcon(this)
		end
	end
end

------------------------------------------------------------------------------------
-- Pet Frame
------------------------------------------------------------------------------------
function SmartPartyPet_OnLoad()
	this:RegisterEvent("PLAYER_ENTERING_WORLD")
	this:RegisterEvent("PARTY_MEMBERS_CHANGED")
	this:RegisterEvent("PARTY_MEMBER_ENABLE")
	this:RegisterEvent("PARTY_MEMBER_DISABLE")
	this:RegisterEvent("PARTY_LEADER_CHANGED")
	this:RegisterEvent("UNIT_PET")
	this:RegisterEvent("UNIT_HEALTH")
	this:RegisterEvent("UNIT_MAXHEALTH")

	this:GetParent():SetMovable(true)
	this:GetParent():SetHitRectInsets(3, 3, 3, 3)

	getglobal(this:GetParent():GetName().."HealthBar"):SetHitRectInsets(0, getglobal(this:GetParent():GetName().."HealthBar"):GetWidth(),0, getglobal(this:GetParent():GetName().."HealthBar"):GetHeight())
end

function SmartPartyPet_OnEvent(event)
	local id = this:GetID()

	if event == "PLAYER_ENTERING_WORLD" or 
		event == "PARTY_MEMBERS_CHANGED" or
		event == "PARTY_MEMBER_ENABLE" or
		event == "PARTY_MEMBER_DISABLE" or 
		event == "PARTY_LEADER_CHANGED" then
		SmartPartyPet_HealthUpdate(id)
	elseif (event == "UNIT_PET") then
		if (arg1 == "party"..id) then
			SmartPartyPet_HealthUpdate(id)
		end
	elseif (event == "UNIT_HEALTH") or (event == "UNIT_MAXHEALTH") then
		if (arg1 == "partypet"..id) then
			SmartPartyPet_HealthUpdate(id)
		end
	end
end

function SmartPartyPet_HealthUpdate(id)
	if UnitExists("partypet"..id) and SMART_PARTY_Config.statusbartext then
		if SMART_PARTY_Config.percent then
			SMART_HealthPercent(getglobal("SmartPartyFrame"..id.."PetFrameHealthBarText"),"partypet"..id)
		else
			SMART_HealthUpdate(getglobal("SmartPartyFrame"..id.."PetFrameHealthBarText"),"partypet"..id)
		end
	else
		getglobal("SmartPartyFrame"..id.."PetFrameHealthBarText"):Hide()
	end
end

------------------------------------------------------------------------------------
-- Spell Casting Bar
------------------------------------------------------------------------------------
function SmartParty_Spellbar_OnLoad()
	this:RegisterEvent("PARTY_MEMBERS_CHANGED")
	this:RegisterEvent("PARTY_MEMBER_ENABLE")
	this:RegisterEvent("PARTY_MEMBER_DISABLE")
	this:RegisterEvent("PARTY_LEADER_CHANGED")
	this:RegisterEvent("CVAR_UPDATE")

	this:SetID(this:GetParent():GetID())
	this:SetFrameStrata("MEDIUM")
	RaiseFrameLevel(this)

	this.unit = "party"..this:GetID()
	CastingBarFrame_OnLoad(this.unit, false)

	local barIcon = getglobal(this:GetName().."Icon")
	barIcon:Hide()

	SetSmartPartySpellbarAspect()
end

function SetSmartPartySpellbarAspect()
	local frameText = getglobal(this:GetName().."Text")
	if (frameText) then
		frameText:SetTextHeight(10)
		frameText:ClearAllPoints()
		frameText:SetPoint("TOP", this, "TOP", 0, 4)
	end

	local frameBorder = getglobal(this:GetName().."Border")
	if (frameBorder) then
		frameBorder:SetTexture("Interface\\CastingBar\\UI-CastingBar-Border-Small")
		frameBorder:SetWidth(156)
		frameBorder:SetHeight(49)
		frameBorder:ClearAllPoints()
		frameBorder:SetPoint("TOP", this, "TOP", 0, 20)
	end

	local frameFlash = getglobal(this:GetName().."Flash")
	if (frameFlash) then
		frameFlash:SetTexture("Interface\\CastingBar\\UI-CastingBar-Flash-Small")
		frameFlash:SetWidth(156)
		frameFlash:SetHeight(49)
		frameFlash:ClearAllPoints()
		frameFlash:SetPoint("TOP", this, "TOP", 0, 20)
	end
end

function SmartParty_Spellbar_OnShow()
	this:ClearAllPoints()

	if (UnitIsConnected(this.unit) and UnitExists("partypet"..this:GetID()) and SHOW_PARTY_PETS == "1") then
		this:SetPoint("BOTTOM", this:GetParent(), "BOTTOM", 8, -34);
	else
		this:SetPoint("BOTTOM", this:GetParent(), "BOTTOM", 8, -8);
	end
end

function SmartParty_Spellbar_OnEvent()
	if SMART_PARTY_Config.castingbar then
		local newevent = event
		local newarg1 = arg1

		if (event == "CVAR_UPDATE") then
			if (this.casting or this.channeling) then
				this:Show()
			else
				this:Hide()
			end
			return
		elseif (event == "PARTY_MEMBERS_CHANGED") or (event == "PARTY_MEMBER_ENABLE") or (event == "PARTY_MEMBER_DISABLE") or (event == "PARTY_LEADER_CHANGED") then
			-- check if the new target is casting a spell
			local nameChannel = UnitChannelInfo(this.unit)
			local nameSpell = UnitCastingInfo(this.unit)

			if (nameChannel) then
				newevent = "UNIT_SPELLCAST_CHANNEL_START"
				newarg1 = "party"..this:GetID()
			elseif (nameSpell) then
				newevent = "UNIT_SPELLCAST_START"
				newarg1 = "party"..this:GetID()
			else
				this.casting = nil
				this.channeling = nil
				this:SetMinMaxValues(0, 0)
				this:SetValue(0)
				this:Hide()
				return
			end
		end

		CastingBarFrame_OnEvent(newevent, newarg1)
	else
		this:Hide()
	end
end

