local XPerl_Party_Pet_Events = {}
local PartyPetFrames = {}

----------------------
-- Loading Function --
----------------------
function XPerl_Party_Pet_OnLoadEvents(self)
	self.time = 0
	XPerl_Party_Pet_EventFrame:RegisterEvent("UNIT_COMBAT")
	XPerl_Party_Pet_EventFrame:RegisterEvent("UNIT_PET")
	XPerl_Party_Pet_EventFrame:RegisterEvent("PARTY_MEMBERS_CHANGED")

	-- Set here to reduce amount of function calls made
	XPerl_Party_Pet_EventFrame:SetScript("OnEvent", XPerl_Party_Pet_OnEvent)
	XPerl_Party_Pet_EventFrame:SetScript("OnUpdate", XPerl_Party_Pet_OnUpdate)
end

-- OwnerUnit
function OwnerUnit(self)
	return "party"..strmatch(self:GetAttribute("unit"), "partypet(%d)")
end

-- XPerl_Party_Pet_OnLoad
function XPerl_Party_Pet_OnLoad(self)
	local petunit = self:GetAttribute("unit")
	PartyPetFrames[petunit] = self

	XPerl_UnitEvents(self, XPerl_Party_Pet_Events, {"UNIT_FACTION", "UNIT_AURA", "UNIT_DYNAMIC_FLAGS", "UNIT_FLAGS"})
	XPerl_RegisterBasics(self, XPerl_Party_Pet_Events)

	XPerl_RegisterHighlight(getglobal(this:GetName().."_CastClickOverlay"), 2)
	XPerl_RegisterPerlFrames(this, {"NameFrame", "StatsFrame"})

	this.FlashFrames = {getglobal(this:GetName().."_NameFrame"), getglobal(this:GetName().."_StatsFrame")}

	self:SetScript("OnShow", XPerl_Party_Pet_UpdateDisplay)
end

-------------------------
-- The Update Function --
-------------------------

-- XPerl_Party_Pet_CheckPet
-- returns true if full update required (frame shown)

-- XPerl_Party_Pet_UpdateName
local function XPerl_Party_Pet_UpdateName(self)
	local petunit = self:GetAttribute("unit")
	local Partypetname = UnitName(petunit)

	if (Partypetname ~= nil) then
		if (XPerlConfig.ShowPartyPetNames == 1) then
			getglobal(self:GetName().."_NameFrame"):Show()
		end
		getglobal(self:GetName().."_NameFrameText"):SetText(Partypetname)

		if (UnitIsPVP(OwnerUnit(self))) then
			getglobal(self:GetName().."_NameFrameText"):SetTextColor(0,1,0)
		else
			getglobal(self:GetName().."_NameFrameText"):SetTextColor(0.5,0.5,1)
		end
	end
end

-- XPerl_Party_Pet_UpdateHealth
local function XPerl_Party_Pet_UpdateHealth(self)
	local petunit = self:GetAttribute("unit")
	local Partypethealth = UnitHealth(petunit)
	local Partypethealthmax = UnitHealthMax(petunit)

	local healthPct = Partypethealth / Partypethealthmax
	local phealthPct = string.format("%3.0f", healthPct * 100)

	getglobal(self:GetName().."_StatsFrame_HealthBar"):SetMinMaxValues(0, Partypethealthmax)
	getglobal(self:GetName().."_StatsFrame_HealthBar"):SetValue(Partypethealth)
	XPerl_SetSmoothBarColor(getglobal(self:GetName().."_StatsFrame_HealthBar"), healthPct)

	if (not UnitIsDead(petunit)) then
		local t = getglobal(self:GetName().."_StatsFrame_HealthBarText")
		if (XPerlConfig.HealerModeParty == 1) then
			if (XPerlConfig.HealerModePartyType == 1) then
				t:SetText(string.format("%d/%d", Partypethealth - Partypethealthmax, Partypethealthmax))
			else
				t:SetText(Partypethealth - Partypethealthmax)
			end
		else
			t:SetText(string.format("%d",(100*(Partypethealth / Partypethealthmax))+0.5).."%")
		end

		getglobal(self:GetName().."_StatsFrame_HealthBarText"):Show()
	end
end

-- XPerl_Party_Pet_UpdateManaType
local function XPerl_Party_Pet_UpdateManaType(self)
	local petunit = self:GetAttribute("unit")
	local frameName = self:GetName().."_StatsFrame_ManaBar"
	XPerl_SetManaBarType(petunit, getglobal(frameName))
end

-- XPerl_Party_Pet_UpdateMana
local function XPerl_Party_Pet_UpdateMana(self)
	local petunit = self:GetAttribute("unit")
	local Partypetmana = UnitMana(petunit)
	local Partypetmanamax = UnitManaMax(petunit)

	getglobal(self:GetName().."_StatsFrame_ManaBar"):SetMinMaxValues(0, Partypetmanamax)
	getglobal(self:GetName().."_StatsFrame_ManaBar"):SetValue(Partypetmana)

	pmanaPct = (Partypetmana * 100.0) / Partypetmanamax
	pmanaPct =  string.format("%3.0f", pmanaPct)
	getglobal(self:GetName().."_StatsFrame_ManaBarText"):Show()
	if (UnitPowerType(petunit) >= 1) then
		getglobal(self:GetName().."_StatsFrame_ManaBarText"):SetText(Partypetmana)
	else
		getglobal(self:GetName().."_StatsFrame_ManaBarText"):SetText(string.format("%d",(100*(Partypetmana / Partypetmanamax))+0.5).."%")
	end
	if (XPerlConfig.ShowPartyPetPercent == 0) then
		getglobal(self:GetName().."_StatsFrame_ManaBarText"):Hide()
	end
end

-- XPerl_Party_Pet_UpdateLevel
local function XPerl_Party_Pet_UpdateLevel(self)
	local petunit = self:GetAttribute("unit")
	local Partypetlevel = UnitLevel(petunit)
	local color = GetDifficultyColor(Partypetlevel)

	getglobal(self:GetName().."_NameFrameLevelText"):SetTextColor(color.r,color.g,color.b)

	if (Partypetlevel == 0) then
		Partypetlevel = ""
	end
	getglobal(self:GetName().."_NameFrameLevelText"):SetText(Partypetlevel)
end

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

-- GetBuffButton
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)

		button:SetHeight(12)
		button:SetWidth(12)

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

		button:ClearAllPoints()
		if (buffnum == 1) then
			if (debuff == 1) then
				button:SetPoint("TOPLEFT", 0, -14)
			else
				button:SetPoint("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_Pet_Buff_UpdateAll
function XPerl_Party_Pet_Buff_UpdateAll(self)
	local petunit = self:GetAttribute("unit")
	local buffFrame = getglobal(self:GetName().."_BuffFrame")
	if (XPerlConfig.ShowPartyPetBuffs == 1) then
		if (UnitExists(petunit)) then
			buffFrame:Show()

			for buffnum=1,10 do
				local name, rank, buff = XPerl_UnitBuff(petunit, buffnum, XPerlConfig.PartyCastableBuffs)
				if (buff) then
					local button = GetBuffButton(self, buffnum, 0, buff)
					local icon = getglobal(button:GetName().."Icon")
					icon:SetTexture(buff)
					button:Show()
				elseif (button) then
					local button = getglobal(self:GetName().."_BuffFrame_Buff"..buffnum)
					if (button) then
				    		button:Hide()
					end
				end
			end
			for buffnum=1,8 do
				local name, rank, buff = XPerl_UnitDebuff(petunit, buffnum, XPerlConfig.PartyCurableDebuffs)
				if (buff) then
					local button = GetBuffButton(self, buffnum, 1, buff)
					local icon = getglobal(button:GetName().."Icon")
					icon:SetTexture(buff)
					button:Show()
				elseif (button) then
					local button = getglobal(self:GetName().."_BuffFrame_DeBuff"..buffnum)
					if (button) then
						button:Hide()
					end
				end
			end
		else
			buffFrame:Hide()
		end
	else
		buffFrame:Hide()
	end

	XPerl_CheckDebuffs(self)
end

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

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

-- XPerl_Party_Pet_UpdateDisplayAll
function XPerl_Party_Pet_UpdateDisplayAll()
	for i,frame in pairs(PartyPetFrames) do
		if (frame:IsShown()) then
			XPerl_Party_Pet_UpdateDisplay(frame)
		end
	end
end

-- XPerl_Party_Pet_UpdateDisplay
function XPerl_Party_Pet_UpdateDisplay(self)
	XPerl_Party_Pet_UpdateName(self)
	XPerl_Party_Pet_UpdateHealth(self)
	XPerl_Party_Pet_UpdateLevel(self)
	XPerl_Party_Pet_UpdateManaType(self)
	XPerl_Party_Pet_UpdateMana(self)
	XPerl_Party_Pet_UpdateCombat(self)
	XPerl_Party_Pet_Buff_UpdateAll(self)
end

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

-- XPerl_Party_Pet_PlayerTip
function XPerl_Party_Pet_PlayerTip()
	local unit = this:GetParent():GetAttribute("unit")
	if (UnitExists(unit)) then
		XPerl_PlayerTip(unit)
	end
end

-- XPerl_Party_Pet_Update_Control
local function XPerl_Party_Pet_Update_Control(self)
	local petunit = self:GetAttribute("unit")
        if (UnitIsVisible(petunit) and UnitIsCharmed(petunit)) then
		getglobal(self:GetName().."_NameFrame_Warning"):Show()
	else
		getglobal(self:GetName().."_NameFrame_Warning"):Hide()
	end
end

-- XPerl_Party_Pet_UpdateCombat
function XPerl_Party_Pet_UpdateCombat(self)
	local petunit = self:GetAttribute("unit")
        if (UnitIsVisible(petunit) and UnitAffectingCombat(petunit)) then
                getglobal(self:GetName().."_NameFrameLevelText"):Hide()
                getglobal(self:GetName().."_NameFrame_ActivityStatus"):Show()
        else
                getglobal(self:GetName().."_NameFrame_ActivityStatus"):Hide()
		if (XPerlConfig.ShowPartyPetLevel == 1) then
                	getglobal(self:GetName().."_NameFrameLevelText"):Show()
		end
        end
	XPerl_Party_Pet_Update_Control(self)
end

-- XPerl_Party_Pet_CombatFlash
local function XPerl_Party_Pet_CombatFlash(f, elapsed, argNew, argGreen)
	if (XPerl_CombatFlashSet (elapsed, f, argNew, argGreen)) then
		XPerl_CombatFlashSetFrames(f)
	end
end

-- XPerl_Party_Pet_OnUpdate
function XPerl_Party_Pet_OnUpdate()
	local any
	for i,f in pairs(PartyPetFrames) do
		if (f:IsShown()) then
			any = true
			if (f.PlayerFlash) then
				XPerl_Party_Pet_CombatFlash(f, arg1, false)
			end
		end
	end

	if (not any) then
		XPerl_Party_Pet_EventFrame:Hide()		-- Stop processing OnUpdate
	end
end

-------------------
-- Event Handler --
-------------------

-- XPerl_Party_Pet_OnEvent
function XPerl_Party_Pet_OnEvent(self, event)
	local func = XPerl_Party_Pet_Events[event]
	if (func) then
		if (strmatch(event, "^UNIT_")) then
			local f = PartyPetFrames[arg1]
			if (f) then
				func(f)
			end
		else
			func()
		end
	else
XPerl_ShowMessage("EXTRA EVENT")
	end
end

-- UNIT_COMBAT
function XPerl_Party_Pet_Events:UNIT_COMBAT()
	if (arg2 == "HEAL") then
		XPerl_Party_Pet_CombatFlash(self, 0, true, true)
	elseif (arg4 and arg4 > 0) then
		XPerl_Party_Pet_CombatFlash(self, 0, true)
	end
end

-- PARTY_MEMBERS_CHANGED
function XPerl_Party_Pet_Events:PARTY_MEMBERS_CHANGED()
	XPerl_Party_Pet_UpdateDisplayAll()
end

-- UNIT_PET
function XPerl_Party_Pet_Events:UNIT_PET()
	if (arg1 == OwnerUnit(self)) then
		XPerl_Party_Pet_UpdateDisplay(self)
	end
end

-- UNIT_FLAGS
function XPerl_Party_Pet_Events:UNIT_FLAGS()
	XPerl_Party_Pet_UpdateCombat(self)
end

XPerl_Party_Pet_Events.UNIT_DYNAMIC_FLAGS = XPerl_Party_Pet_Events.UNIT_FLAGS

-- UNIT_NAME_UPDATE
function XPerl_Party_Pet_Events:UNIT_NAME_UPDATE()
	XPerl_Party_Pet_UpdateName(self)
end

-- UNIT_FACTION
function XPerl_Party_Pet_Events:UNIT_FACTION()
	XPerl_Party_Pet_UpdateName(self)
	XPerl_Party_Pet_UpdateCombat(self)
end

-- UNIT_LEVEL
function XPerl_Party_Pet_Events:UNIT_LEVEL()
	XPerl_Party_Pet_UpdateLevel(self)
end

-- UNIT_HEALTH
function XPerl_Party_Pet_Events:UNIT_HEALTH()
	XPerl_Party_Pet_UpdateHealth(self)
end

-- UNIT_MAXHEALTH
function XPerl_Party_Pet_Events:UNIT_MAXHEALTH()
	XPerl_Party_Pet_UpdateHealth(self)
	XPerl_Party_Pet_UpdateLevel(self)
end

-- UNIT_AURA
function XPerl_Party_Pet_Events:UNIT_AURA()
	XPerl_Party_Pet_Buff_UpdateAll(self)
end

-- UNIT_DISPLAYPOWER
function XPerl_Party_Pet_Events:UNIT_DISPLAYPOWER()
	XPerl_Party_Pet_UpdateManaType(self)
end

-- UNIT_MANA
function XPerl_Party_Pet_Events:UNIT_MANA()
	XPerl_Party_Pet_UpdateMana(self)
end

XPerl_Party_Pet_Events.UNIT_MAXMANA	= XPerl_Party_Pet_Events.UNIT_MANA
XPerl_Party_Pet_Events.UNIT_RAGE	= XPerl_Party_Pet_Events.UNIT_MANA
XPerl_Party_Pet_Events.UNIT_MAXRAGE	= XPerl_Party_Pet_Events.UNIT_MANA
XPerl_Party_Pet_Events.UNIT_FOCUS	= XPerl_Party_Pet_Events.UNIT_MANA
XPerl_Party_Pet_Events.UNIT_MAXFOCUS	= XPerl_Party_Pet_Events.UNIT_MANA
XPerl_Party_Pet_Events.UNIT_ENERGY	= XPerl_Party_Pet_Events.UNIT_MANA
XPerl_Party_Pet_Events.UNIT_MAXENERGY	= XPerl_Party_Pet_Events.UNIT_MANA

-- EnableDisable()
local function EnableDisable()

	for i,frame in pairs(PartyPetFrames) do
		if (XPerlConfig.ShowPartyPets == 1) then
			RegisterUnitWatch(frame)
		else
			UnregisterUnitWatch(frame)
			frame:Hide()
		end
	end
end

-- XPerl_Party_Pet_Set_Name
function XPerl_Party_Pet_Set_Name()
	for i,frame in pairs(PartyPetFrames) do
		local f = getglobal(frame:GetName().."_NameFrame")
		if (XPerlConfig.ShowPartyPetName == 1) then
			f:Show()
			f:SetHeight(20)
		else
			f:Hide()
			f:SetHeight(4)
		end

		f = getglobal(frame:GetName().."_StatsFrame")
		local manaBar = getglobal(frame:GetName().."_StatsFrame_ManaBar")
		if (XPerlConfig.ShowPartyPetMana == 1) then
			f:SetHeight(33)
			manaBar:Show()
		else
			f:SetHeight(23)
			manaBar:Hide()
		end

		local levelText = getglobal(frame:GetName().."_NameFrameLevelText")
		if (XPerlConfig.ShowPartyPetLevel == 1) then
			levelText:Show()
		else
			levelText:Hide()
		end

		XPerl_Party_Pet_Buff_UpdateAll(frame)

		XPerl_ProtectedCall(EnableDisable)
	end
end

-- XPerl_ScalePartyPets(num)
function XPerl_ScalePartyPets(num)
	XPerl_partypet4:SetScale(num)
	XPerl_partypet3:SetScale(num)
	XPerl_partypet2:SetScale(num)
	XPerl_partypet1:SetScale(num)
end
