local XPerl_Party_Events = {}
PartyFrames = {}

----------------------
-- Loading Function --
----------------------

function XPerl_Party_Events_OnLoad(self)

	local events = {"PLAYER_ENTERING_WORLD", "PARTY_MEMBER_ENABLE", "PARTY_MEMBER_DISABLE", "RAID_ROSTER_UPDATED", "PARTY_MEMBERS_CHANGED",
			"UNIT_COMBAT", "UNIT_FACTION", "UNIT_DYNAMIC_FLAGS", "UNIT_FLAGS", "UNIT_AURA", "UNIT_MODEL_CHANGED",
			"UNIT_TARGET", "UNIT_RAGE", "UNIT_MAXRAGE", "UNIT_ENERGY", "UNIT_MAXENERGY", "UNIT_MANA", "UNIT_MAXMANA",
			"UNIT_HEALTH", "UNIT_MAXHEALTH", "UNIT_LEVEL", "UNIT_DISPLAYPOWER", "UNIT_NAME_UPDATE"}
	for i,event in pairs(events) do
		self:RegisterEvent(event)
	end

	self:SetScript("OnEvent", XPerl_Party_OnEvent)

end

-- onAttrChanged
local function onAttrChanged(self, name, value)
	if (name == "unit") then
		if (value and value ~= "party0") then
			PartyFrames[value] = self
			XPerl_Party_UpdateDisplay(self)
			XPerl_ArcaneBar_RegisterFrame(getglobal(self:GetName().."_NameFrame"), value, "ArcaneBarParty")
		end
	end
end

-- XPerl_Party_OnLoad
function XPerl_Party_OnLoad(self)

	XPerl_Party_SecureHeader:SetAttribute("child"..self:GetID(), self)

	local id = strmatch(self:GetName(), "(%d+)")
	setglobal("XPerl_party"..id, self)

	self.time = 0
	self.feigning = 0

	local tex = getglobal(self:GetName().."HighlightTex")
	tex:SetVertexColor(0.86, 0.82, 0.41)

	XPerl_RegisterHighlight(getglobal(self:GetName().."_TargetFrame"), 3)
	XPerl_RegisterPerlFrames(self, {"NameFrame", "StatsFrame", "PortraitFrame", "LevelFrame", "TargetFrame"})

	self.FlashFrames = {getglobal(self:GetName().."_NameFrame"),
  				getglobal(self:GetName().."_LevelFrame"),
  				getglobal(self:GetName().."_StatsFrame"),
  				getglobal(self:GetName().."_PortraitFrame")}

	self:SetScript("OnUpdate", XPerl_Party_OnUpdate)
	self:SetScript("OnAttributeChanged", onAttrChanged)

	--XPerl_Party_Set_Bits1(self)
end

-- ShowHideValues
local function ShowHideValues(self)
	if (XPerlConfig.ShowPartyValues == 1) then
        	getglobal(self:GetName().."_StatsFrame_HealthBarText"):Show()
        	getglobal(self:GetName().."_StatsFrame_ManaBarText"):Show()
	else
        	getglobal(self:GetName().."_StatsFrame_HealthBarText"):Hide()
        	getglobal(self:GetName().."_StatsFrame_ManaBarText"):Hide()
	end
end

-- XPerl_Party_UpdateHealth
local function XPerl_Party_UpdateHealth(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		local numID = strmatch(partyid, "party(%d)")			-- TODO - will be wrong later
		local Partyhealth = UnitHealth(partyid)
		local Partyhealthmax = UnitHealthMax(partyid)
		local frameID = self:GetName().."_StatsFrame_"
		local healthBar = getglobal(frameID.."HealthBar")
		local healthBarPercent = getglobal(frameID.."HealthBarPercent")
		local reason
		local percVis = healthBarPercent:IsShown()

		if (Partyhealth > Partyhealthmax) then
			-- New glitch with 1.12.1
			if (UnitIsDeadOrGhost(partyid)) then
				Partyhealth = 0
			else
				Partyhealth = Partyhealthmax
			end
		end

		if (self.feigning == 1 and not XPerl_IsFeignDeath(partyid)) then
			self.feigning = 0
		end
		if  (self.feigning == 1) then
		        healthBar:SetMinMaxValues(0, 1)
		        healthBar:SetValue(0)
			XPerl_SetSmoothBarColor(healthBar, 0)
		else
			XPerl_SetHealthBar(healthBar, Partyhealth, Partyhealthmax, XPerlConfig.HealerModeParty, XPerlConfig.HealerModePartyType)
		end

		local frameID = self:GetName().."_StatsFrame_"
		healthBarPercent:SetText(string.format("%d",(100*(Partyhealth / Partyhealthmax))+0.5).."%")

		local petFrame = getglobal("XPerl_partypet"..numID)
		if (not UnitIsConnected(partyid)) then
			hide = XPERL_LOC_OFFLINE
			self:SetAlpha(XPerlConfig.Transparency/2)
			if (petFrame) then
				petFrame:SetAlpha(XPerlConfig.Transparency/2)
			end
		else
			self:SetAlpha(XPerlConfig.Transparency)
			if (petFrame) then
				petFrame:SetAlpha(XPerlConfig.Transparency)
			end

			if (self.feigning == 1) then
				reason = XPERL_LOC_FEIGNDEATH

			elseif (UnitIsDead(partyid)) then
				reason = XPERL_LOC_DEAD

			elseif (UnitIsGhost(partyid)) then
				reason = XPERL_LOC_GHOST

			elseif ((Partyhealth==1) and (Partyhealthmax==1)) then
				reason = XPERL_LOC_UPDATING
			end
		end

		ShowHideValues(self)
		if (reason) then
			local f = getglobal(self:GetName().."_StatsFrame_HealthBarText")
			f:SetText(reason)
			f:Show()
		end
	end
end

--------------------
-- Buff Functions --
--------------------

-- GetBuffButton
-- debuff must be 1 or 0, as it's used in size calc
local function GetBuffButton(self, buffnum, debuff, createIfAbsent)

	local buffType
	if (debuff == 1) then
		buffType = "DeBuff"
	else
		buffType = "Buff"
	end
	local name = self:GetName().."_BuffFrame_"..buffType..buffnum
	local button = getglobal(name)

	if (not button and createIfAbsent) then
		button = CreateFrame("Button", name, getglobal(self:GetName().."_BuffFrame"), "XPerl_"..buffType.."Template")
		button:SetID(buffnum)

		local size = XPerlConfig.PartyBuffSize * (1 + (0.4 * debuff))
		button:SetHeight(size)
		button:SetWidth(size)

		if (debuff == 1) then
			button:SetScript("OnEnter", XPerl_Party_SetDeBuffTooltip)
		else
			button:SetScript("OnEnter", XPerl_Party_SetBuffTooltip)
		end
		button:SetScript("OnLeave", XPerl_PlayerTipHide)

		button:ClearAllPoints()
		if (buffnum == 1) then
			if (debuff == 1) then
				button:SetPoint("LEFT", self:GetName().."_StatsFrame", "RIGHT", 0, 0)
			else
				button:SetPoint("TOPLEFT", getglobal(self:GetName().."_BuffFrame"), "TOPLEFT", 0, 0)
			end
		else
			local prevButton = getglobal(self:GetName().."_BuffFrame_"..buffType..(buffnum - 1))
			button:SetPoint("TOPLEFT", prevButton, "TOPRIGHT", 1 + debuff, 0)
		end
	end

	return button
end

-- XPerl_Party_SetDebuffLocation
local function XPerl_Party_SetDebuffLocation(self)
	local debuff1 = getglobal(self:GetName().."_BuffFrame_DeBuff1")
	if (debuff1) then
        	debuff1:ClearAllPoints()

		if (XPerlConfig.PartyDebuffsBelow == 0) then
			local petFrame = getglobal("XPerl_partypet"..self:GetID())
			if (petFrame and petFrame:IsVisible()) then
        	                debuff1:SetPoint("TOPLEFT", petFrame:GetName().."_NameFrame", "TOPRIGHT", 0, -4)
			else
        	                debuff1:SetPoint("TOPLEFT", self:GetName().."_StatsFrame", "TOPRIGHT", 0, -4)
			end
		else
			local buff1 = getglobal(self:GetName().."_BuffFrame_Buff1")
			if (not buff1) then
        	        	debuff1:SetPoint("TOPLEFT", self:GetName().."_BuffFrame", "TOPLEFT", 0, -20)
			else
        	        	debuff1:SetPoint("TOPLEFT", buff1, "BOTTOMLEFT", 0, -2)
			end
		end
	end
end

-- XPerl_Party_SetBuffLocation
local function XPerl_Party_SetBuffLocation(self)
	local buff1 = getglobal(self:GetName().."_BuffFrame_Buff1")
	if (buff1) then
        	buff1:ClearAllPoints()
		local buffFrame = getglobal(self:GetName().."_BuffFrame")

		buff1:SetPoint("TOPLEFT", buffFrame, "TOPLEFT", 0, 0)
	end
end

-- XPerl_Party_Buff_UpdateAll
local function XPerl_Party_Buff_UpdateAll(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		local thisid = self:GetName()

		if (XPerlConfig.PartyBuffs == 0 and XPerlConfig.PartyDebuffs == 0) then
			getglobal(thisid.."_BuffFrame"):Hide()
		else
			getglobal(thisid.."_BuffFrame"):Show()

			if (UnitExists(partyid)) then
				local needUpdateHealth

				if (XPerlConfig.PartyBuffs == 1) then
					for buffnum=1,16 do
						local name, rank, buff, count = XPerl_UnitBuff(partyid, buffnum, XPerlConfig.PartyCastableBuffs)

						if (buff) then
							local button = GetBuffButton(self, buffnum, 0, true)

							local icon = getglobal(button:GetName().."Icon")
							icon:SetTexture(buff)

							local buffCount = getglobal(button:GetName().."Count")
							if (count > 1) then
								buffCount:SetText(count)
								buffCount:Show()
							else
								buffCount:Hide()
							end
							button:Show()
						else
							local button = getglobal(thisid.."_BuffFrame_Buff"..buffnum)
							if (button) then
								button:Hide()
							end
						end
					end

					XPerl_Party_SetBuffLocation(self)
				else
					for buffnum=1,16 do
						local button = getglobal(thisid.."_BuffFrame_Buff"..buffnum)
						if (button) then
							button:Hide()
						end
					end
				end

				if (XPerlConfig.PartyDebuffs == 1) then
					for buffnum=1,8 do
						local name, rank, buff, count, debuffType = XPerl_UnitDebuff(partyid, buffnum, XPerlConfig.PartyCurableDebuffs)

						if (buff) then
							local button = GetBuffButton(self, buffnum, 1, buff)

							local icon = getglobal(button:GetName().."Icon")
							icon:SetTexture(buff)

							local buffCount = getglobal(button:GetName().."Count")
							if (count > 1) then
								buffCount:SetText(count)
								buffCount:Show()
							else
								buffCount:Hide()
							end

							local borderColor = DebuffTypeColor[(debuffType or "none")]
							local buffBorder = getglobal(button:GetName().."Border")
							buffBorder:SetVertexColor(borderColor.r, borderColor.g, borderColor.b)

							button:Show()
						else
							local button = getglobal(thisid.."_BuffFrame_DeBuff"..buffnum)
							if (button) then
								button:Hide()
							end
						end
					end

					XPerl_Party_SetDebuffLocation(self)
				else
					for buffnum=1,8 do
						local button = getglobal(thisid.."_BuffFrame_DeBuff"..buffnum)
						if (button) then
							button:Hide()
						end
					end
				end

				local _, class = UnitClass(partyid)
				if (class == "HUNTER") then
					if (XPerl_IsFeignDeath(partyid)) then
						if (self.feigning == 0) then
							self.feigning = 1
							needUpdateHealth = true
						end
					else
						if (self.feigning == 1) then
							self.feigning = 0
							needUpdateHealth = true
						end
					end
				end

				if (needUpdateHealth) then
					XPerl_Party_UpdateHealth(self)
				end
			end
		end

		XPerl_CheckDebuffs(self)
	end
end

-- XPerl_Party_SetBuffTooltip
function XPerl_Party_SetBuffTooltip(self)
	local partyid = self:GetParent():GetParent():GetAttribute("unit")
	if (partyid) then
		GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT",30,0)
		XPerl_TooltipSetUnitBuff(GameTooltip, partyid, self:GetID(), XPerlConfig.PartyCastableBuffs)
		XPerl_ToolTip_AddBuffDuration(partyid)
	end
end

-- XPerl_Party_SetDeBuffTooltip
function XPerl_Party_SetDeBuffTooltip(self)
	local partyid = self:GetParent():GetParent():GetAttribute("unit")
	if (partyid) then
		GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT",30,0)
		XPerl_TooltipSetUnitDebuff(GameTooltip, partyid, self:GetID(), XPerlConfig.PartyCurableDebuffs)
		XPerl_ToolTip_AddDebuffDuration(partyid, nil, self:GetID(), XPerlConfig.PartyCurableDebuffs)
	end
end

-------------------------
-- The Update Function --
-------------------------
local function XPerl_Party_CombatFlash(self, elapsed, argNew, argGreen)
	if (XPerl_CombatFlashSet (elapsed, self, argNew, argGreen)) then
		XPerl_CombatFlashSetFrames(self)
	end
end

-- XPerl_Party_UpdatePortrait
function XPerl_Party_UpdatePortrait(self)
	if (XPerlConfig.ShowPartyPortrait == 1) then
		local framePortrait = getglobal(self:GetName().."_PortraitFrame_Portrait")
		local framePortrait3D = getglobal(self:GetName().."_PortraitFrame_Portrait3D")

		local partyid = self:GetAttribute("unit")
		if (partyid) then
			if (XPerlConfig.ShowPartyPortrait3D == 1 and UnitIsVisible(partyid)) then
				framePortrait:Hide()
				framePortrait3D:Show()
				XPerlSetPortrait3D(framePortrait3D, partyid)
			else
				framePortrait3D.last3DTime = nil
				framePortrait:Show()
				framePortrait3D:Hide()
				SetPortraitTexture(framePortrait, partyid)
			end
		end
	end
end

-- XPerl_Party_UpdateName
local function XPerl_Party_UpdateName(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		local thisid = self:GetName()
		local Partyname = UnitName(partyid)
		if (Partyname) then
			local nameFrame = getglobal(thisid.."_NameFrame")
			local textFrame = getglobal(thisid.."_NameFrameText")

			textFrame:SetFontObject(GameFontNormal)
        	        textFrame:SetText(Partyname)

			if (textFrame:GetStringWidth() > nameFrame:GetWidth() - 4) then
				textFrame:SetFontObject(GameFontNormalSmall)
			end

			XPerl_ColourFriendlyUnit(textFrame, partyid)
		end
	end
end

-- XPerl_Party_UpdateLeader
local function XPerl_Party_UpdateLeader(self)
	local thisid = self:GetName()
	local icon = getglobal(thisid.."_NameFrame_LeaderIcon")
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		if ("party"..GetPartyLeaderIndex() == partyid) then
			icon:Show()
		else
			icon:Hide()
		end

		icon = getglobal(thisid.."_NameFrame_MasterIcon")
		local lootMethod
		local lootMaster
		lootMethod, lootMaster = GetLootMethod()
		if ( partyid == "party"..(lootMaster or "nil") ) then
			icon:Show()
		else
			icon:Hide()
		end
	end
end

-- XPerl_Party_Update_Control
local function XPerl_Party_Update_Control(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		if (UnitIsVisible(partyid) and UnitIsCharmed(partyid)) then
			--XPerl_Target_Warning:SetTexture("Interface\Minimap\Ping\ping6")
			--XPerl_Target_Warning:SetBlendMode("ADD")
			getglobal(self:GetName().."_NameFrame_Warning"):Show()
		else
			getglobal(self:GetName().."_NameFrame_Warning"):Hide()
		end
	end
end

-- XPerl_Party_UpdatePVP
local function XPerl_Party_UpdatePVP(self)
	local f = getglobal(self:GetName().."_NameFrame_PVPStatus")
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		if (XPerlConfig.ShowPartyPVP == 1 and UnitIsPVP(partyid)) then
			f:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..(UnitFactionGroup(partyid) or "FFA"))
		        f:Show()
		else
		        f:Hide()
		end
	end
end

-- XPerl_Party_UpdateCombat
function XPerl_Party_UpdateCombat(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		XPerl_Party_UpdateCombat1(partyid, self:GetName())
		XPerl_Party_Update_Control(self)
	end
end

-- XPerl_Party_UpdateCombat1
function XPerl_Party_UpdateCombat1(argID,argName)
	local frame = getglobal(argName.."_NameFrame_ActivityStatus")
	if (UnitAffectingCombat(argID)) then
	        frame:Show()
	else
	        frame:Hide()
	end
end

-- XPerl_Party_UpdateLevel
local function XPerl_Party_UpdateLevel(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		local Partylevel = UnitLevel(partyid)
		local color = GetDifficultyColor(Partylevel)
		getglobal(self:GetName().."_LevelFrame_LevelBarText"):SetTextColor(color.r,color.g,color.b)
		getglobal(self:GetName().."_LevelFrame_LevelBarText"):SetText(Partylevel)
	end
end

-- XPerl_Party_UpdateClass
local function XPerl_Party_UpdateClass(self)
	local partyid = self:GetAttribute("unit")
	if (partyid and UnitIsPlayer(partyid)) then
		local _, PlayerClass = UnitClass(partyid)
		local r, l, t, b = XPerl_ClassPos(PlayerClass)
		getglobal(self:GetName().."_LevelFrame_ClassTexture"):SetTexCoord(r, l, t, b)
	end

	if (XPerlConfig.ShowPartyClassIcon==1) then
	        getglobal(self:GetName().."_LevelFrame_ClassTexture"):Show()
	else
	        getglobal(self:GetName().."_LevelFrame_ClassTexture"):Hide()
	end
end

-- XPerl_Party_UpdateManaType
local function XPerl_Party_UpdateManaType(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		local frameName = self:GetName().."_StatsFrame_ManaBar"
		XPerl_SetManaBarType(partyid, getglobal(frameName))
	end
end

-- XPerl_Party_UpdateMana
local function XPerl_Party_UpdateMana(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		local thisid = self:GetName()
		local Partymana = UnitMana(partyid)
		local Partymanamax = UnitManaMax(partyid)
		local frameManaBar = getglobal(thisid.."_StatsFrame_ManaBar")
		local frameManaBarText = getglobal(thisid.."_StatsFrame_ManaBarText")
		local frameManaBarPercent = getglobal(thisid.."_StatsFrame_ManaBarPercent")
		local frameHealthBarPercent = getglobal(thisid.."_StatsFrame_HealthBarPercent")

		if (Partymanamax == 1 and Partymana > Partymanamax) then
			Partymanamax = Partymana
		end

		frameManaBar:SetMinMaxValues(0, Partymanamax)
		frameManaBar:SetValue(Partymana)
		pmanaPct = (Partymana * 100.0) / Partymanamax
		pmanaPct =  string.format("%3.0f", pmanaPct)

		if (UnitPowerType(partyid)>=1) then
		        frameManaBarPercent:SetText(Partymana)
		else
		        frameManaBarPercent:SetText(string.format("%d",(100*(Partymana / Partymanamax))+0.5).."%")
		end

		if (XPerlConfig.ShowPartyValues == 1) then
			frameManaBarText:Show()
		else
			frameManaBarText:Hide()
		end

		frameManaBarText:SetText(Partymana.."/"..Partymanamax)

		local numID = strmatch(partyid, "party(%d)")			-- TODO - will be wrong later
		local petFrame = getglobal("XPerl_partypet"..numID)
		if (UnitIsConnected(partyid)) then
			self:SetAlpha(XPerlConfig.Transparency)
			if (petFrame) then
				petFrame:SetAlpha(XPerlConfig.Transparency)
			end
		else
			self:SetAlpha(XPerlConfig.Transparency/2)
			if (petFrame) then
		      		petFrame:SetAlpha(XPerlConfig.Transparency/2)
			end
		        getglobal(thisid.."_StatsFrame_HealthBarText"):SetText(XPERL_LOC_OFFLINE)
		end
	end
end

-- XPerl_Party_UpdateRange
local function XPerl_Party_UpdateRange(self)
	local partyid = self:GetAttribute("unit")
	if (partyid) then
		local f = getglobal(self:GetName().."_NameFrame_RangeStatus")

		if (XPerlConfig.ShowParty30YardSymbol == 0 or CheckInteractDistance(partyid, 4) or not UnitIsConnected(partyid)) then
			f:Hide()
		else
			f:Show()
			f:SetAlpha(1)
		end
	end
end

-- XPerl_Party_OnUpdate
function XPerl_Party_OnUpdate(self)
	local update
	self.time = arg1 + self.time
	if self.time >= 0.2 then
		update = true
		self.time = 0
	end
	local any

	if (self.PlayerFlash) then
		XPerl_Party_CombatFlash(self, arg1, false)
	end

	if (update) then
		XPerl_Party_UpdateRange(self)
	end
	any = true
end

-- XPerl_Party_UpdateDisplayAll
function XPerl_Party_UpdateDisplayAll()
	local any
	for i,frame in pairs(PartyFrames) do
		XPerl_Party_UpdateDisplay(frame)
		if (frame:IsShown()) then
			any = true
		end
	end
end

-- XPerl_Party_UpdateDisplay
function XPerl_Party_UpdateDisplay(self)
	local partyid = self:GetAttribute("unit")
	if (partyid and UnitExists(partyid)) then
		XPerl_Party_UpdateName(self)
		--XPerl_Party_UpdateLeader(self)		-- 2.0.4 testing need for this here.
		XPerl_Party_UpdateClass(self)
		XPerl_Party_UpdateManaType(self)
		XPerl_Party_UpdateHealth(self)
		XPerl_Party_UpdateMana(self)
		XPerl_Party_UpdateLevel(self)
		XPerl_Party_Update_Control(self)
        	XPerl_Party_UpdateCombat(self)
		XPerl_Party_UpdatePVP(self)
		XPerl_Party_UpdatePortrait(self)
		XPerl_Party_Buff_UpdateAll(self)
		XPerl_Party_UpdateTarget(self)
	end
end

--------------------
-- Click Handlers --
--------------------

-- XPerl_Party_PlayerTip
function XPerl_Party_PlayerTip(self, argTarget)
	local unitid = self:GetAttribute("unit")
	if (unitid) then
		if (argTarget) then
			unitid = unitid.."target"
		end

		XPerl_PlayerTip(unitid)
	end
end

-- XPerl_Party_UpdateTarget
function XPerl_Party_UpdateTarget(self)
	local frame = getglobal(self:GetName().."_TargetFrame")

	if (frame == nil) then
		return
	end

	if (XPerlConfig.ShowPartyTarget == 1) then
		local partyid = self:GetAttribute("unit")
		if (partyid) then
			local frameText = getglobal("XPerl_"..partyid.."_TargetFrame_Target")
			if (UnitIsConnected(partyid) and UnitExists(partyid) and UnitIsVisible(partyid)) then
				local unit = partyid.."target"
				local targetname = UnitName(unit)

				if (targetname and targetname ~= UNKNOWNOBJECT) then
					frameText:SetText(targetname)

					XPerl_SetUnitNameColor (unit, frameText)

					local frameAct = getglobal("XPerl_"..partyid.."_TargetFrame_TargetActivityStatus")
				        if (UnitAffectingCombat(unit)) then
				                frameAct:SetTexCoord(0.5, 1.0, 0.0, 0.5)
				                frameAct:Show()
					else
				                frameAct:Hide()
					end

					local framePVP = getglobal("XPerl_"..partyid.."_TargetFrame_TargetPVPStatus")
					if (XPerlConfig.ShowPartyPVP == 1 and UnitIsPVP(unit)) then
						framePVP:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..(UnitFactionGroup(unit) or "FFA"))
						framePVP:Show()
					else
						framePVP:Hide()
					end
				end
			end
		end
	end
end

-- CheckRaid
local function CheckRaid()
	if (InCombatLockdown()) then
		tinsert(XPerl_OutOfCombatQueue, CheckRaid)
	else
		if (UnitInRaid("player")) then
			if (XPerlConfig.ShowPartyRaid == 1) then
				XPerl_Party_SecureHeader:Show()
			else
				XPerl_Party_Anchor:StopMovingOrSizing()
				XPerl_Party_SecureHeader:Hide()
			end
		else
			XPerl_Party_SecureHeader:Show()
		end
	end
end

-------------------
-- Event Handler --
-------------------
function XPerl_Party_OnEvent(self, event)
	local func = XPerl_Party_Events[event]
	if (func) then
		if (strmatch(event, "^UNIT_")) then
			local f = PartyFrames[arg1]
			if (f) then
				func(f)
			end
		else
			func(self)
		end
	else
XPerl_ShowMessage("EXTRA EVENT")
	end
end

-- PARTY_LEADER_CHANGED
function XPerl_Party_Events:PARTY_LEADER_CHANGED()
	for i,frame in pairs(PartyFrames) do
		XPerl_Party_UpdateLeader(frame)
	end
end

XPerl_Party_Events.PARTY_LOOT_METHOD_CHANGED	= XPerl_Party_Events.PARTY_LEADER_CHANGED

-- UNIT_COMBAT
function XPerl_Party_Events:UNIT_COMBAT()
	local partyid = self:GetAttribute("unit")
	if (arg1 == partyid) then
		XPerl_Party_UpdateCombat(self)
		if (arg2 == "HEAL") then
			XPerl_Party_CombatFlash(self, 0, true, true)
		elseif (arg4 and arg4 > 0) then
			XPerl_Party_CombatFlash(self, 0, true)
		end
	end
end

-- UNIT_HEALTH, UNIT_MAXHEALTH
function XPerl_Party_Events:UNIT_HEALTH()
	XPerl_Party_UpdateHealth(self)
end

-- PARTY_MEMBER_ENABLE
function XPerl_Party_Events:PARTY_MEMBER_ENABLE()
	for k,v in pairs(PartyFrames) do
		XPerl_Party_UpdateHealth(v)
		XPerl_Party_UpdateCombat(v)
		XPerl_Party_UpdateTarget(v)
	end
end

XPerl_Party_Events.PARTY_MEMBER_DISABLE	= XPerl_Party_Events.PARTY_MEMBER_ENABLE

-- UNIT_MAXHEALTH
function XPerl_Party_Events:UNIT_MAXHEALTH()
	XPerl_Party_UpdateHealth(self)
	XPerl_Party_UpdateLevel(self)	-- Level not available until we've received maxhealth
	XPerl_Party_UpdateClass(self)
end

-- PLAYER_ENTERING_WORLD
function XPerl_Party_Events:PLAYER_ENTERING_WORLD()
	XPerl_Party_SecureHeader:SetAttribute("minWidth", 80)
	XPerl_Party_SecureHeader:SetAttribute("minHeight", 10)
        XPerl_Party_SecureHeader:SetAttribute("xOffset", 0)
        XPerl_Party_SecureHeader:SetAttribute("template", "XPerl_Party_FrameTemplate")
        XPerl_Party_SecureHeader:SetAttribute("templateType", "Button")
	XPerl_Party_SetMainAttributes()
	CheckRaid()
end

-- RAID_ROSTER_UPDATED
function XPerl_Party_Events:RAID_ROSTER_UPDATED()
	CheckRaid()
end

XPerl_Party_Events.PARTY_MEMBERS_CHANGED = XPerl_Party_Events.RAID_ROSTER_UPDATED

-- UNIT_MODEL_CHANGED
function XPerl_Party_Events:UNIT_MODEL_CHANGED()
	XPerl_Party_UpdatePortrait(self)
end
--XPerl_Party_Events.UNIT_PORTRAIT_UPDATE = XPerl_Party_Events.UNIT_MODEL_CHANGED

-- UNIT_MANA
function XPerl_Party_Events:UNIT_MANA()
	XPerl_Party_UpdateMana(self)
end

XPerl_Party_Events.UNIT_MAXMANA		= XPerl_Party_Events.UNIT_MANA
XPerl_Party_Events.UNIT_RAGE		= XPerl_Party_Events.UNIT_MANA
XPerl_Party_Events.UNIT_MAXRAGE		= XPerl_Party_Events.UNIT_MANA
XPerl_Party_Events.UNIT_ENERGY		= XPerl_Party_Events.UNIT_MANA
XPerl_Party_Events.UNIT_MAXENERGY	= XPerl_Party_Events.UNIT_MANA

-- UNIT_DISPLAYPOWER
function XPerl_Party_Events:UNIT_DISPLAYPOWER()
	XPerl_Party_UpdateManaType(self)
	XPerl_Party_UpdateMana(self)
end

-- UNIT_NAME_UPDATE
function XPerl_Party_Events:UNIT_NAME_UPDATE()
	XPerl_Party_UpdateName(self)
end

-- UNIT_LEVEL
function XPerl_Party_Events:UNIT_LEVEL()
	XPerl_Party_UpdateLevel(self)
end

-- UNIT_AURA
function XPerl_Party_Events:UNIT_AURA()
	XPerl_Party_Buff_UpdateAll(self)
end

-- UNIT_FACTION
function XPerl_Party_Events:UNIT_FACTION(unit)
	XPerl_Party_UpdateName(self)
        XPerl_Party_UpdateCombat(self)
	XPerl_Party_Update_Control(self)
	XPerl_Party_UpdatePVP(self)
end

XPerl_Party_Events.UNIT_FLAGS = XPerl_Party_Events.UNIT_FACTION
XPerl_Party_Events.UNIT_DYNAMIC_FLAGS = XPerl_Party_Events.UNIT_FACTION

function XPerl_Party_Events:UNIT_TARGET()
	XPerl_Party_UpdateTarget(self)
end

---- Moving stuff ----
-- XPerl_Party_GetGap
function XPerl_Party_GetGap()
	--return math.floor(math.floor((XPerl_party1:GetBottom() - XPerl_party2:GetTop() + 0.01) * 100) / 100)
	return XPerlConfig.PartySpacing
end

-- XPerl_Party_SetGap
function XPerl_Party_SetGap(newGap)
	if (type(newGap) ~= "number") then
		return
	end
	XPerlConfig.PartySpacing = newGap
	XPerl_Party_SetMainAttributes()
end

-- XPerl_Party_Set_Bits
function XPerl_Party_Set_Bits1(self)
	local name = self:GetName()
	local levelFrame = getglobal(name.."_LevelFrame")
	local nameFrame = getglobal(name.."_NameFrame")
	local statsFrame = getglobal(name.."_StatsFrame")
	local portraitFrame = getglobal(name.."_PortraitFrame")
	local clickFrame = getglobal(name.."Highlight")
	local classTexture = getglobal(name.."_LevelFrame_ClassTexture")
	local levelText = getglobal(name.."_LevelFrame_LevelBarText")

	portraitFrame:ClearAllPoints()
	nameFrame:ClearAllPoints()
	levelFrame:ClearAllPoints()
	statsFrame:ClearAllPoints()
	classTexture:ClearAllPoints()
	levelText:ClearAllPoints()
	clickFrame:ClearAllPoints()

	if (XPerlConfig.ShowPartyPortrait == 0) then
		portraitFrame:Hide()

		levelFrame:SetWidth(30)
		levelFrame:SetHeight(41)

		nameFrame:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0)
		levelFrame:SetPoint("TOPLEFT", nameFrame, "BOTTOMLEFT", 0, 3)
		statsFrame:SetPoint("TOPLEFT", levelFrame, "TOPRIGHT", -2, 0)

		levelText:SetPoint("BOTTOM", levelFrame, "BOTTOM", 0, 4)
		classTexture:SetPoint("TOPLEFT", levelFrame, "TOPLEFT", 5, -5)

		getglobal(name.."_BuffFrame"):SetPoint("TOPLEFT", statsFrame, "BOTTOMLEFT", 5, 0)

		clickFrame:SetPoint("TOPLEFT", nameFrame, "TOPLEFT", 0, 0)
		clickFrame:SetPoint("BOTTOMRIGHT", statsFrame, "BOTTOMRIGHT", 0, 0)
	else
		portraitFrame:Show()

		levelFrame:SetWidth(27)
		levelFrame:SetHeight(22)

		levelFrame:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0)
		portraitFrame:SetPoint("TOPLEFT", levelFrame, "TOPRIGHT", -2, 0)
		nameFrame:SetPoint("TOPLEFT", portraitFrame, "TOPRIGHT", -2, 0)
		statsFrame:SetPoint("TOPLEFT", nameFrame, "BOTTOMLEFT", 0, 3)

		levelText:SetPoint("CENTER", 0, 0)
		classTexture:SetPoint("BOTTOMRIGHT", portraitFrame, "BOTTOMLEFT", 0, 3)

		getglobal(name.."_BuffFrame"):SetPoint("TOPLEFT", portraitFrame, "BOTTOMLEFT", 5, 0)

		clickFrame:SetPoint("TOPLEFT", levelFrame, "TOPLEFT", 0, 0)
		clickFrame:SetPoint("BOTTOMRIGHT", statsFrame, "BOTTOMRIGHT", 0, 0)
	end

	if (XPerlConfig.ShowPartyLevel==0) then
		getglobal(name.."_LevelFrame_LevelBarText"):Hide()
	else
		getglobal(name.."_LevelFrame_LevelBarText"):Show()
		levelFrame:Show()

		if (XPerlConfig.ShowPartyPortrait == 1) then
			levelFrame:SetWidth(27)
		else
			levelFrame:SetWidth(30)
		end
	end

	if (XPerlConfig.ShowPartyClassIcon==0) then
		classTexture:Hide()

		if (XPerlConfig.ShowPartyLevel == 0) then
			levelFrame:SetWidth(2)
			levelFrame:Hide()
		end
	else
		classTexture:Show()
		levelFrame:Show()

		if (XPerlConfig.ShowPartyPortrait == 1) then
			levelFrame:SetWidth(27)
		else
			levelFrame:SetWidth(30)
		end
	end

	local frameHealth = getglobal(name.."_StatsFrame_HealthBarPercent")
	local frameMana = getglobal(name.."_StatsFrame_ManaBarPercent")
	local width = (36 * XPerlConfig.ShowPartyPercent) + 106;	-- 136 enabled, 106 disabled

	statsFrame:SetWidth(width)
	if (XPerlConfig.ShowPartyPercent == 0) then
		frameHealth:Hide()
		frameMana:Hide()
	else
		frameHealth:Show()
		frameMana:Show()
	end

	local height = (XPerlConfig.ShowPartyNames * 22) + 2;		-- 24 when enabled, 2 when disabled
	local targetFrame = getglobal(name.."_TargetFrame")

	targetFrame:ClearAllPoints()
	nameFrame:SetHeight(height)

	if (XPerlConfig.ShowPartyNames==0) then
		nameFrame:Hide()
		targetFrame:SetPoint("TOPLEFT", statsFrame, "BOTTOMLEFT", 0, 2)
	else
		nameFrame:Show()
		targetFrame:SetPoint("BOTTOMLEFT", nameFrame, "BOTTOMRIGHT", -2, 2)
	end
	targetFrame:SetWidth(120)

	XPerlConfig.PartyBuffSize = tonumber(XPerlConfig.PartyBuffSize) or 20
	XPerl_SetBuffSize(name.."_", XPerlConfig.PartyBuffSize, XPerlConfig.PartyBuffSize * 1.4)

	local w = width
	if (XPerlConfig.ShowPartyPortrait == 1) then
		w = w + 54
		if (XPerlConfig.ShowPartyClassIcon == 1) then
			w = w + 30
		end
	elseif (XPerlConfig.ShowPartyClassIcon == 1) then
		w = w + 30
	end
	self:SetWidth(w)

	local f = getglobal(self:GetName().."_TargetFrame")
	if (XPerlConfig.ShowPartyTarget == 1) then
		RegisterUnitWatch(f)
	else
		UnregisterUnitWatch(f)
		f:Hide()
	end
end

-- XPerl_Party_SetMainAttributes
function XPerl_Party_SetMainAttributes()

	XPerl_Party_Anchor:StopMovingOrSizing()

	XPerl_Party_SecureHeader:ClearAllPoints()
	if (XPerlConfig.PartyAnchor == "TOP") then
		XPerl_Party_SecureHeader:SetPoint("TOPLEFT", XPerl_Party_Anchor, "TOPLEFT", 0, 0)
        	XPerl_Party_SecureHeader:SetAttribute("xOffset", 0)
		XPerl_Party_SecureHeader:SetAttribute("yOffset", -XPerlConfig.PartySpacing)
	elseif (XPerlConfig.PartyAnchor == "LEFT") then
		XPerl_Party_SecureHeader:SetPoint("TOPLEFT", XPerl_Party_Anchor, "TOPLEFT", 0, 0)
		XPerl_Party_SecureHeader:SetAttribute("xOffset", XPerlConfig.PartySpacing)
        	XPerl_Party_SecureHeader:SetAttribute("yOffset", 0)
	elseif (XPerlConfig.PartyAnchor == "BOTTOM") then
		XPerl_Party_SecureHeader:SetPoint("BOTTOMLEFT", XPerl_Party_Anchor, "BOTTOMLEFT", 0, 0)
        	XPerl_Party_SecureHeader:SetAttribute("xOffset", 0)
		XPerl_Party_SecureHeader:SetAttribute("yOffset", XPerlConfig.PartySpacing)
	elseif (XPerlConfig.PartyAnchor == "RIGHT") then
		XPerl_Party_SecureHeader:SetPoint("BOTTOMRIGHT", XPerl_Party_Anchor, "BOTTOMRIGHT", 0, 0)
		XPerl_Party_SecureHeader:SetAttribute("xOffset", -XPerlConfig.PartySpacing)
        	XPerl_Party_SecureHeader:SetAttribute("yOffset", 0)
	end

        XPerl_Party_SecureHeader:SetAttribute("point", XPerlConfig.PartyAnchor or "TOP")
end

-- XPerl_Party_Set_Bits
function XPerl_Party_Set_Bits()
	for k,v in pairs(PartyFrames) do
		XPerl_Party_Set_Bits1(v)
	end

	XPerl_ProtectedCall(XPerl_Party_SetMainAttributes)
	CheckRaid()
end

-- XPerl_ScaleParty
function XPerl_ScaleParty(num)
	XPerl_Party_SecureHeader:SetScale(XPerlConfig.Scale_PartyFrame)
end
