NUM_BATTLE_PETS_IN_BATTLE = 3;
NUM_BATTLE_PET_ABILITIES = 3;
BATTLE_PET_ABILITY_SWITCH = 4;
BATTLE_PET_ABILITY_CATCH = 5;
NUM_BATTLE_PET_HOTKEYS = BATTLE_PET_ABILITY_CATCH;
END_OF_PET_BATTLE_PET_LEVEL_UP = "petbattlepetlevel";
END_OF_PET_BATTLE_RESULT = "petbattleresult";
END_OF_PET_BATTLE_CAPTURE = "petbattlecapture";
local MAX_PET_LEVEL = 25;

BATTLE_PET_DISPLAY_ROTATION = 3 * math.pi / 8;

PET_BATTLE_WEATHER_TEXTURES = {
	[590] = "Interface\\PetBattles\\Weather-ArcaneStorm",
	[205] = "Interface\\PetBattles\\Weather-Blizzard",
	[171] = "Interface\\PetBattles\\Weather-BurntEarth",
	[257] = "Interface\\PetBattles\\Weather-Darkness",
	[203] = "Interface\\PetBattles\\Weather-StaticField",
	[596] = "Interface\\PetBattles\\Weather-Moonlight",
	[718] = "Interface\\PetBattles\\Weather-Mud",
	[229] = "Interface\\PetBattles\\Weather-Rain",
	[454] = "Interface\\PetBattles\\Weather-Sandstorm",
	[403] = "Interface\\PetBattles\\Weather-Sunlight",
	--[63] = "Interface\\PetBattles\\Weather-Windy",

	[235] = "Interface\\PetBattles\\Weather-Rain",
	[2350] = "Interface\\PetBattles\\Weather-ToxicFumes",
};

StaticPopupDialogs["PET_BATTLE_FORFEIT"] = {
	text = PET_BATTLE_FORFEIT_CONFIRMATION,
	button1 = OKAY,
	button2 = CANCEL,
	maxLetters = 30,
	OnAccept = function(dialog, data)
		C_PetBattles.ForfeitGame();
	end,
	timeout = 0,
	exclusive = 1,
	hideOnEscape = 1
};

StaticPopupDialogs["PET_BATTLE_FORFEIT_NO_PENALTY"] = {
	text = PET_BATTLE_FORFEIT_CONFIRMATION_NO_PENALTY,
	button1 = OKAY,
	button2 = CANCEL,
	maxLetters = 30,
	OnAccept = function(dialog, data)
		C_PetBattles.ForfeitGame();
	end,
	timeout = 0,
	exclusive = 1,
	hideOnEscape = 1
};

local PetBattlesOverrides = {}
function PetBattlesOverrides.GetPositionOverride(petSpeciesID)
	if petSpeciesID == 3175 then
		return -0.45, -2, 0;
	elseif petSpeciesID == 2003 then
		return -0.8, 0.6, -0.4;
	elseif petSpeciesID == 504 then
		return -3.0, -0.0, -0.5;
	elseif petSpeciesID == 4257 then
		return -1, -1.75, 0;
	end
end

--------------------------------------------
-------------Pet Battle Frame---------------
--------------------------------------------
function PetBattleFrame_OnLoad(self)
	self.BottomFrame.abilityButtons = {};

	local flowFrame = self.BottomFrame.FlowFrame;
	FlowContainer_Initialize(flowFrame);
	FlowContainer_SetOrientation(flowFrame, "horizontal");
	FlowContainer_SetHorizontalSpacing(flowFrame, 10);

	for i=1, NUM_BATTLE_PETS_IN_BATTLE do
		PetBattleUnitFrame_SetUnit(self.BottomFrame.PetSelectionFrame["Pet"..i], Enum.BattlePetOwner.Ally, i);
	end
	PetBattleFrame_UpdateAbilityButtonHotKeys(self);
	
	PetBattleFrame_LoadXPTicks(self);

	self:RegisterEvent("PET_BATTLE_OPENING_START");
	self:RegisterEvent("PET_BATTLE_OPENING_DONE");

	self:RegisterEvent("PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE");
	self:RegisterEvent("PET_BATTLE_PET_CHANGED");
	self:RegisterEvent("PET_BATTLE_XP_CHANGED");
	self:RegisterEvent("PET_BATTLE_ACTION_SELECTED");
	self:RegisterEvent("PET_BATTLE_PET_TYPE_CHANGED");
	self:RegisterEvent("PET_BATTLE_OVERRIDE_ABILITY");
	
	-- Transitioning out of battle event
	self:RegisterEvent("PET_BATTLE_OVER");

	-- End of battle event:
	self:RegisterEvent("PET_BATTLE_CLOSE");

	-- Other events:
	self:RegisterEvent("UPDATE_BINDINGS");
	self:RegisterEvent("GAME_PAD_ACTIVE_CHANGED");
end

function PetBattleFrame_OnEvent(self, event, ...)
	if ( event == "PET_BATTLE_OPENING_START" ) then
		PlaySound(SOUNDKIT.UI_PET_BATTLE_CAMERA_MOVE_IN);
		PetBattleFrame_Display(self);
	elseif ( event == "PET_BATTLE_OPENING_DONE" ) then
		PetBattleFrameTurnTimer_UpdateValues(self.BottomFrame.TurnTimer);
		StartSplashTexture.splashAnim:Play();
		PlaySound(SOUNDKIT.UI_PET_BATTLE_START);
		PetBattleFrame_UpdateSpeedIndicators(self);
	elseif ( event == "PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE" ) then
		PetBattleFrameTurnTimer_UpdateValues(self.BottomFrame.TurnTimer);
		PetBattleFrame_UpdatePetSelectionFrame(self);
		PetBattleFrame_UpdateSpeedIndicators(self);
		PetBattleFrame_UpdateInstructions(self);
		if (C_PetBattles.IsSkipAvailable()) then
			self.BottomFrame.TurnTimer.SkipButton:Enable();
		else
			self.BottomFrame.TurnTimer.SkipButton:Disable();
		end
	elseif ( event == "PET_BATTLE_PET_CHANGED" ) then
		PetBattleFrame_UpdateAssignedUnitFrames(self);
		PetBattleFrame_UpdateAllActionButtons(self);
		PetBattleFrame_UpdateSpeedIndicators(self);
		PetBattleFrame_UpdateXpBar(self);
	elseif ( event == "PET_BATTLE_OVER" ) then
		PlaySound(SOUNDKIT.UI_PET_BATTLE_CAMERA_MOVE_OUT);
	elseif ( event == "PET_BATTLE_CLOSE" ) then
		PetBattleFrame_Remove(self);
		StaticPopup_Hide("PET_BATTLE_FORFEIT");
		StaticPopup_Hide("PET_BATTLE_FORFEIT_NO_PENALTY");
	elseif ( event == "UPDATE_BINDINGS" or event == "GAME_PAD_ACTIVE_CHANGED" ) then
		PetBattleFrame_UpdateAbilityButtonHotKeys(self);
	elseif ( event == "PET_BATTLE_XP_CHANGED" ) then
		PetBattleFrame_UpdateXpBar(self);
	elseif ( event == "PET_BATTLE_ACTION_SELECTED" ) then
		self.BottomFrame.TurnTimer.SkipButton:Disable();
	elseif ( event == "PET_BATTLE_PET_TYPE_CHANGED" ) then
		PetBattleFrame_UpdateAllActionButtons(self);
	elseif ( event == "PET_BATTLE_OVERRIDE_ABILITY" ) then
		local abilityIndex = ...;
		local button = self.BottomFrame.abilityButtons[abilityIndex];
		PetBattleAbilityButton_UpdateIcons(button);
		PetBattleActionButton_UpdateState(button);
	end
end
function PetBattleFrame_OnShow(self)
	EditModeManagerFrame:BlockEnteringEditMode(self);
end

function PetBattleFrame_OnHide(self)
	EditModeManagerFrame:UnblockEnteringEditMode(self);
end

function PetBattleFrame_UpdateInstructions(self)
	local battleState = C_PetBattles.GetBattleState();
	if (( C_PetBattles.ShouldShowPetSelect() == true ) and 
		( not C_PetBattles.GetSelectedAction() ) ) then
		self.BottomFrame.FlowFrame.SelectPetInstruction:Show();
	else
		self.BottomFrame.FlowFrame.SelectPetInstruction:Hide();
	end
end

function PetBattleFrame_Display(self)
	AddFrameLock("PETBATTLES");		-- FrameLock removed by PetBattleFrame_Remove
	self:Show();
	if ( FCFManager_GetNumDedicatedFrames("PET_BATTLE_COMBAT_LOG") == 0 ) then
		FCF_OpenTemporaryWindow("PET_BATTLE_COMBAT_LOG");
	end
	PetBattleFrame_UpdatePetSelectionFrame(self);
	PetBattleFrame_UpdateAssignedUnitFrames(self);
	PetBattleFrame_UpdateActionBarLayout(self);
	PetBattleFrame_UpdateAllActionButtons(self);
	PetBattleFrame_InitSpeedIndicators(self);
	PetBattleFrame_UpdateSpeedIndicators(self);
	PetBattleFrame_UpdateXpBar(self);
	PetBattleFrame_UpdatePassButtonAndTimer(self);
	PetBattleFrame_UpdateInstructions(self);
	PetBattleWeatherFrame_Update(self.WeatherFrame);
end

function PetBattleFrame_PetSelectionFrameUpdateVisible(showFrame) 
	local selectionFrame = PetBattleFrame.BottomFrame.PetSelectionFrame;
	local battleState = C_PetBattles.GetBattleState();
	local selectedActionType = C_PetBattles.GetSelectedAction();
	local mustSwap = ( ( not selectedActionType ) or ( selectedActionType ==  Enum.BattlePetAction.None ) ) and ( battleState == Enum.PetbattleState.WaitingPreBattle ) or ( battleState == Enum.PetbattleState.WaitingForFrontPets );
	if ( selectionFrame:IsShown() and ( not mustSwap ) ) then
		PetBattlePetSelectionFrame_Hide(selectionFrame);
	elseif (showFrame) then
		PetBattlePetSelectionFrame_Show(selectionFrame);
	end
end

function PetBattleFrame_UpdatePetSelectionFrame(self)
	local battleState = C_PetBattles.GetBattleState();
	if ((C_PetBattles.ShouldShowPetSelect() == true) and
		( not C_PetBattles.GetSelectedAction() ) ) then
		PetBattlePetSelectionFrame_Show(PetBattleFrame.BottomFrame.PetSelectionFrame);
	else
		PetBattlePetSelectionFrame_Hide(PetBattleFrame.BottomFrame.PetSelectionFrame);
	end
end

function PetBattleFrame_UpdateAllActionButtons(self)
	for i=1, #self.BottomFrame.abilityButtons do
		local button = self.BottomFrame.abilityButtons[i];
		PetBattleAbilityButton_UpdateIcons(button);
		PetBattleActionButton_UpdateState(button);
	end
	PetBattleActionButton_UpdateState(self.BottomFrame.SwitchPetButton);
	PetBattleActionButton_UpdateState(self.BottomFrame.CatchButton);
end

function PetBattleFrame_InitSpeedIndicators(self)
	PetBattleFrame.ActiveAlly.Border:SetShown(true);
	PetBattleFrame.ActiveEnemy.Border2:SetShown(false);
	PetBattleFrame.ActiveEnemy.SpeedUnderlay:SetShown(false);
	PetBattleFrame.ActiveEnemy.SpeedIcon:SetShown(false);

	PetBattleFrame.ActiveAlly.Border:SetShown(true);
	PetBattleFrame.ActiveAlly.Border2:SetShown(false);
	PetBattleFrame.ActiveAlly.SpeedUnderlay:SetShown(false);
	PetBattleFrame.ActiveAlly.SpeedIcon:SetShown(false);
end

function PetBattleFrame_UpdateSpeedIndicators(self)
	local hadSpeedIcon = nil;
	if (PetBattleFrame.ActiveEnemy.SpeedIcon:IsShown()) then
		hadSpeedIcon = Enum.BattlePetOwner.Enemy;
	elseif (PetBattleFrame.ActiveAlly.SpeedIcon:IsShown()) then
		hadSpeedIcon = Enum.BattlePetOwner.Ally;
	end
	
	local enemyActive = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Enemy);
	local enemySpeed = C_PetBattles.GetSpeed(Enum.BattlePetOwner.Enemy, enemyActive);

	local allyActive = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally);
	local allySpeed = C_PetBattles.GetSpeed(Enum.BattlePetOwner.Ally, allyActive);
	
	PetBattleFrame.ActiveEnemy.Border:SetShown(enemySpeed <= allySpeed);
	PetBattleFrame.ActiveEnemy.Border2:SetShown(enemySpeed > allySpeed);
	PetBattleFrame.ActiveEnemy.SpeedUnderlay:SetShown(enemySpeed > allySpeed);
	PetBattleFrame.ActiveEnemy.SpeedIcon:SetShown(enemySpeed > allySpeed);
	
	PetBattleFrame.ActiveAlly.Border:SetShown(enemySpeed >= allySpeed);
	PetBattleFrame.ActiveAlly.Border2:SetShown(enemySpeed < allySpeed);
	PetBattleFrame.ActiveAlly.SpeedUnderlay:SetShown(enemySpeed < allySpeed);
	PetBattleFrame.ActiveAlly.SpeedIcon:SetShown(enemySpeed < allySpeed);
	
	if (enemySpeed > allySpeed and (not hadSpeedIcon or hadSpeedIcon == Enum.BattlePetOwner.Ally)) then
		PetBattleFrame.ActiveEnemy.SpeedFlash:Play();
	elseif (enemySpeed < allySpeed and (not hadSpeedIcon or hadSpeedIcon == Enum.BattlePetOwner.Enemy)) then
		PetBattleFrame.ActiveAlly.SpeedFlash:Play();
	end
end

function PetBattleFrame_UpdateXpBar(self)
	local activePet = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally);
	local level = C_PetBattles.GetLevel(Enum.BattlePetOwner.Ally, activePet);
	if (level >= MAX_PET_LEVEL) then
		self.BottomFrame.xpBar:Hide();
		return;
	end
	
	local xp, maxXp = C_PetBattles.GetXP(Enum.BattlePetOwner.Ally, activePet);
	self.BottomFrame.xpBar:SetMinMaxValues(0, maxXp);
	self.BottomFrame.xpBar:SetValue(xp);
	self.BottomFrame.xpBar:Show();
end

function PetBattleFrame_LoadXPTicks(self)
	local width = self.BottomFrame.xpBar:GetWidth();
	local divWidth = width / 7;
	local xpos = divWidth;
	for i = 1, 6 do
		local texture = self.BottomFrame.xpBar:CreateTexture("PetBattleXPBarDiv"..i, "OVERLAY");
		texture:SetTexture("Interface\\MainMenuBar\\UI-XP-Bar");
		texture:SetSize(9,9);
		texture:SetTexCoord( 0.01562500, 0.15625000, 0.01562500, 0.17187500);
		local xalign = floor(xpos);
		texture:SetPoint("LEFT", xalign, 1);
		texture:SetVertexColor("0.7450980392156863", "0.6352941176470588", "0.5176470588235294");
		xpos = xpos + divWidth;
	end
end

function PetBattleFrame_UpdateActionButtonLevel(self, actionButton)
	actionButton:SetFrameLevel(self.BottomFrame.FlowFrame:GetFrameLevel() + 1);
end

function PetBattleFrame_UpdateAbilityButtonHotKeys(self)
	for i=1, #self.BottomFrame.abilityButtons do
		local button = self.BottomFrame.abilityButtons[i];
		PetBattleAbilityButton_UpdateHotKey(button);
	end
	PetBattleAbilityButton_UpdateHotKey(self.BottomFrame.SwitchPetButton);
	PetBattleAbilityButton_UpdateHotKey(self.BottomFrame.CatchButton);
end

function PetBattleFrame_UpdatePassButtonAndTimer(self)
	local pveBattle = C_PetBattles.IsPlayerNPC(Enum.BattlePetOwner.Enemy);
	
	-- Timer & Button for PvP
	self.BottomFrame.TurnTimer.TimerBG:SetShown(not pveBattle);
	self.BottomFrame.TurnTimer.Bar:SetShown(not pveBattle);
	self.BottomFrame.TurnTimer.ArtFrame:SetShown(not pveBattle);
	self.BottomFrame.TurnTimer.TimerText:SetShown(not pveBattle);
	
	-- Button Only
	self.BottomFrame.TurnTimer.ArtFrame2:SetShown(pveBattle);

	-- Move the button!
	self.BottomFrame.TurnTimer.SkipButton:ClearAllPoints();
	if (pveBattle) then
		self.BottomFrame.TurnTimer.SkipButton:SetPoint("CENTER", 0, 0);
	else
		self.BottomFrame.TurnTimer.SkipButton:SetPoint("LEFT", 25, 0);
	end
end

function PetBattleFrame_UpdateActionBarLayout(self)
	local flowFrame = self.BottomFrame.FlowFrame;
	FlowContainer_RemoveAllObjects(flowFrame);
	FlowContainer_PauseUpdates(flowFrame);

	FlowContainer_SetStartingOffset(flowFrame, 0, -4);

	for i=1, NUM_BATTLE_PET_ABILITIES do
		local actionButton = self.BottomFrame.abilityButtons[i];
		if ( not actionButton ) then
			self.BottomFrame.abilityButtons[i] = CreateFrame("CheckButton", nil, self.BottomFrame, "PetBattleAbilityButtonTemplate", i);
			actionButton = self.BottomFrame.abilityButtons[i];
			PetBattleFrame_UpdateActionButtonLevel(PetBattleFrame, actionButton);
		end

		FlowContainer_AddObject(flowFrame, actionButton);
	end

	FlowContainer_AddObject(flowFrame, self.BottomFrame.SwitchPetButton);
	PetBattleFrame_UpdateActionButtonLevel(PetBattleFrame, self.BottomFrame.SwitchPetButton);

	FlowContainer_AddObject(flowFrame, self.BottomFrame.Delimiter);
	PetBattleFrame_UpdateActionButtonLevel(PetBattleFrame, self.BottomFrame.Delimiter);

	FlowContainer_AddObject(flowFrame, self.BottomFrame.CatchButton);
	PetBattleFrame_UpdateActionButtonLevel(PetBattleFrame, self.BottomFrame.CatchButton);

	FlowContainer_AddObject(flowFrame, self.BottomFrame.ForfeitButton);
	PetBattleFrame_UpdateActionButtonLevel(PetBattleFrame, self.BottomFrame.ForfeitButton);

	FlowContainer_ResumeUpdates(flowFrame);

	local usedX, usedY = FlowContainer_GetUsedBounds(flowFrame);
	flowFrame:SetWidth(usedX);
	self.BottomFrame:SetWidth(usedX + 260);

	self.BottomFrame.FlowFrame.SelectPetInstruction:ClearAllPoints();
	self.BottomFrame.FlowFrame.SelectPetInstruction:SetPoint("TOPLEFT", self.BottomFrame.abilityButtons[1], "TOPLEFT", 0, 0);
	self.BottomFrame.FlowFrame.SelectPetInstruction:SetPoint("BOTTOMRIGHT", self.BottomFrame.SwitchPetButton, "BOTTOMRIGHT", 0, 0);

end

function PetBattleFrame_ShowMultiWildNotification(self)
	if (C_PetBattles.IsWildBattle() == true) then
		local numOpponentPets = C_PetBattles.GetNumPets(Enum.BattlePetOwner.Enemy);
		local text = nil;
		if (numOpponentPets == 2) then
			text = PET_BATTLE_ANOTHER_PET_JOINED;
		elseif (numOpponentPets == 3) then
			text = PET_BATTLE_TWO_PETS_JOINED;
		end
		
		if (text) then
			RaidNotice_AddMessage(RaidWarningFrame, text, ChatTypeInfo["RAID_BOSS_EMOTE"], 5.0 );
		end
	end
end

function PetBattleFrame_ButtonDown(id)
	if ( id > NUM_BATTLE_PET_HOTKEYS ) then
		return;
	end

	local button = PetBattleFrame.BottomFrame.abilityButtons[id];
	if (id == BATTLE_PET_ABILITY_SWITCH) then
		button = PetBattleFrame.BottomFrame.SwitchPetButton;
	elseif (id == BATTLE_PET_ABILITY_CATCH) then
		button = PetBattleFrame.BottomFrame.CatchButton;
	end
	
	if (not button) then
		return;
	end

	StaticPopup_Hide("PET_BATTLE_FORFEIT", nil);
	StaticPopup_Hide("PET_BATTLE_FORFEIT_NO_PENALTY", nil);
	if ( button:GetButtonState() == "NORMAL" ) then
		button:SetButtonState("PUSHED");
	end
	if ( GetCVarBool("ActionButtonUseKeydown") ) then
		button:Click();
	end
end

function PetBattleFrame_ButtonUp(id)
	if ( id > NUM_BATTLE_PET_ABILITIES ) then
		return;
	end

	local button = PetBattleFrame.BottomFrame.abilityButtons[id];

	if ( button:GetButtonState() == "PUSHED" ) then
		button:SetButtonState("NORMAL");
		if ( not GetCVarBool("ActionButtonUseKeydown") ) then
			button:Click();
		end
	end
end

function PetBattleAbilityButton_OnClick(self)
	if ( IsModifiedClick() ) then
		local activePet = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally);
		local abilityID = C_PetBattles.GetAbilityInfo(Enum.BattlePetOwner.Ally, activePet, self:GetID());
		local maxHealth = C_PetBattles.GetMaxHealth(Enum.BattlePetOwner.Ally, activePet);
		local power = C_PetBattles.GetPower(Enum.BattlePetOwner.Ally, activePet);
		local speed = C_PetBattles.GetSpeed(Enum.BattlePetOwner.Ally, activePet);
		
		HandleModifiedItemClick(GetBattlePetAbilityHyperlink(abilityID, maxHealth, power, speed));
	else
		StaticPopup_Hide("PET_BATTLE_FORFEIT",nil);
		StaticPopup_Hide("PET_BATTLE_FORFEIT_NO_PENALTY", nil);
		C_PetBattles.UseAbility(self:GetID());
		PetBattleFrame_PetSelectionFrameUpdateVisible();
	end
end

function PetBattleFrame_UpdateAssignedUnitFrames(self)
	local activeAlly = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally);
	local activeEnemy = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Enemy);

	PetBattleUnitFrame_SetUnit(self.ActiveAlly, Enum.BattlePetOwner.Ally, activeAlly);
	local nextIndex = 2;
	for i=1, NUM_BATTLE_PETS_IN_BATTLE do
		if ( i ~= activeAlly ) then
			PetBattleUnitFrame_SetUnit(self["Ally"..nextIndex], Enum.BattlePetOwner.Ally, i);
			nextIndex = nextIndex + 1;
		end
	end

	PetBattleUnitFrame_SetUnit(self.ActiveEnemy, Enum.BattlePetOwner.Enemy, activeEnemy);
	nextIndex = 2;
	for i=1, NUM_BATTLE_PETS_IN_BATTLE do
		if ( i ~= activeEnemy ) then
			PetBattleUnitFrame_SetUnit(self["Enemy"..nextIndex], Enum.BattlePetOwner.Enemy, i);
			nextIndex = nextIndex + 1;
		end
	end

	PetBattleAuraHolder_SetUnit(self.EnemyBuffFrame, Enum.BattlePetOwner.Enemy, activeEnemy);
	PetBattleAuraHolder_SetUnit(self.EnemyDebuffFrame, Enum.BattlePetOwner.Enemy, activeEnemy);
	PetBattleAuraHolder_SetUnit(self.AllyBuffFrame, Enum.BattlePetOwner.Ally, activeAlly);
	PetBattleAuraHolder_SetUnit(self.AllyDebuffFrame, Enum.BattlePetOwner.Ally, activeAlly);
	PetBattleAuraHolder_SetUnit(self.EnemyPadBuffFrame, Enum.BattlePetOwner.Enemy, PET_BATTLE_PAD_INDEX);
	PetBattleAuraHolder_SetUnit(self.EnemyPadDebuffFrame, Enum.BattlePetOwner.Enemy, PET_BATTLE_PAD_INDEX);
	PetBattleAuraHolder_SetUnit(self.AllyPadBuffFrame, Enum.BattlePetOwner.Ally, PET_BATTLE_PAD_INDEX);
	PetBattleAuraHolder_SetUnit(self.AllyPadDebuffFrame, Enum.BattlePetOwner.Ally, PET_BATTLE_PAD_INDEX);
end

function PetBattleFrame_Remove(self)
	ActionButtonSpellAlertManager:HideAlert(PetBattleFrame.BottomFrame.CatchButton);
	PetBattleFrame.BottomFrame.CatchButton.playedSound = false;
	self:Hide();
	RemoveFrameLock("PETBATTLES");
end

local TIMER_BAR_TEXCOORD_LEFT = 0.56347656;
local TIMER_BAR_TEXCOORD_RIGHT = 0.89453125;
local TIMER_BAR_TEXCOORD_TOP = 0.00195313;
local TIMER_BAR_TEXCOORD_BOTTOM = 0.03515625;
function PetBattleFrameTurnTimer_OnUpdate(self, elapsed)
	if ( ( C_PetBattles.GetBattleState() ~= Enum.PetbattleState.WaitingPreBattle ) and
		 ( C_PetBattles.GetBattleState() ~= Enum.PetbattleState.RoundInProgress ) and
		 ( C_PetBattles.GetBattleState() ~= Enum.PetbattleState.WaitingForFrontPets ) ) then
		self.Bar:SetAlpha(0);
		self.TimerText:SetText("");
	elseif ( self.turnExpires ) then
		local timeRemaining = self.turnExpires - GetTime();

		--Deal with variable lag from the server without looking weird
		if ( timeRemaining <= 0.01 ) then
			timeRemaining = 0.01;
		end

		local timeRatio = 1.0;
		if ( self.turnTime > 0.0 ) then
			timeRatio = timeRemaining / self.turnTime;
		end
		local usableSpace = 337;

		self.Bar:SetWidth(timeRatio * usableSpace);
		self.Bar:SetTexCoord(TIMER_BAR_TEXCOORD_LEFT, TIMER_BAR_TEXCOORD_LEFT + (TIMER_BAR_TEXCOORD_RIGHT - TIMER_BAR_TEXCOORD_LEFT) * timeRatio, TIMER_BAR_TEXCOORD_TOP, TIMER_BAR_TEXCOORD_BOTTOM);

		if ( C_PetBattles.IsWaitingOnOpponent() ) then
			self.Bar:SetAlpha(0.5);
			self.TimerText:SetText(PET_BATTLE_WAITING_FOR_OPPONENT);
		else
			self.Bar:SetAlpha(1);
			if ( self.turnTime > 0.0 ) then
				self.TimerText:SetText(ceil(timeRemaining));
			else
				self.TimerText:SetText("")
			end
		end
	else
		self.Bar:SetAlpha(0);
		if ( C_PetBattles.IsWaitingOnOpponent() ) then
			self.TimerText:SetText(PET_BATTLE_WAITING_FOR_OPPONENT);
		else
			self.TimerText:SetText(PET_BATTLE_SELECT_AN_ACTION);
		end
	end
end

function PetBattleFrameTurnTimer_UpdateValues(self)
	local timeRemaining, turnTime = C_PetBattles.GetTurnTimeInfo(); 
	self.turnExpires = GetTime() + timeRemaining;
	self.turnTime = turnTime;
end

function PetBattleForfeitButton_OnClick(self)
	local forfeitPenalty = C_PetBattles.GetForfeitPenalty();
	if(forfeitPenalty == 0) then
		StaticPopup_Show("PET_BATTLE_FORFEIT_NO_PENALTY", nil, nil, nil)
	else
		StaticPopup_Show("PET_BATTLE_FORFEIT", forfeitPenalty, nil, nil)
	end
end

function PetBattleCatchButton_OnClick(self)
	local forfeitPenalty = C_PetBattles.GetForfeitPenalty();
	if(forfeitPenalty == 0) then
		StaticPopup_Hide("PET_BATTLE_FORFEIT_NO_PENALTY",nil);
	else
		StaticPopup_Hide("PET_BATTLE_FORFEIT",nil);
	end
	C_PetBattles.UseTrap();
end

function PetBattleCatchButton_OnShow(self)
	local trapAbilityID = C_PetBattles.GetPlayerTrapAbility();
	if (trapAbilityID and trapAbilityID > 0) then
		local abID, abName, abIcon, abCooldown, abDescription = C_PetBattles.GetAbilityInfoByID(trapAbilityID);
		self.name = abName;
		self.description = abDescription;
		self.Icon:SetTexture(abIcon);
	else
		self.name = CATCH_PET;
		self.description = CATCH_PET_DESCRIPTION;
		self.additionalText = PET_BATTLE_TRAP_ERR_2;
		GameTooltip:Show();
	end
end

function PetBattleCatchButton_OnEnter(self)
	GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
	GameTooltip:SetText(self.name, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, true);
	GameTooltip:AddLine(self.description, nil, nil, nil, true);
	if (self.additionalText) then
		GameTooltip:AddLine(self.additionalText, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, true);
	end
	GameTooltip:Show();
end

function PetBattleFrame_GetAbilityAtLevel(speciesID, targetLevel)
	local abilities = C_PetJournal.GetPetAbilityListTable(speciesID);
	for _, ability in pairs(abilities)  do
		if ability.level == targetLevel then
			return ability.abilityID; 
		end
	end

	return nil;
end

--------------------------------------------
------Pet Battle Pet Selection Frame--------
--------------------------------------------
function PetBattlePetSelectionFrame_Show(self)
	local numPets = C_PetBattles.GetNumPets(Enum.BattlePetOwner.Ally);
	self:SetWidth((self.Pet1:GetWidth() + 10) * numPets + 30);

	for i=1, numPets do
		PetBattleUnitFrame_UpdateHealthInstant(self["Pet"..i]);
		PetBattleUnitFrame_UpdateDisplay(self["Pet"..i]);
		self["Pet"..i]:Show();
		self["Pet"..i]:SetEnabled(C_PetBattles.CanPetSwapIn(i));
	end
	for i=numPets + 1, NUM_BATTLE_PETS_IN_BATTLE do
		self["Pet"..i]:Hide();
	end
	self:Show();
	PetBattleFrame.BottomFrame.SwitchPetButton:SetChecked(true);
end

function PetBattlePetSelectionFrame_Hide(self)
	self:Hide();
	PetBattleFrame.BottomFrame.SwitchPetButton:SetChecked(false);
end

--------------------------------------------
--------Pet Battle Action Button------------
--------------------------------------------
function PetBattleActionButton_Initialize(self, actionType, actionIndex)
	self.actionType = actionType;
	self.actionIndex = actionIndex;

	self:RegisterEvent("PET_BATTLE_ACTION_SELECTED");
	self:RegisterEvent("PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE");
	PetBattleActionButton_UpdateState(self);
end

function PetBattleActionButton_OnEvent(self, event, ...)
	if ( event == "PET_BATTLE_ACTION_SELECTED" ) then
		PetBattleActionButton_UpdateState(self);
	elseif ( event == "PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE" ) then
		PetBattleActionButton_UpdateState(self);
		PetBattleAbilityButton_UpdateBetterIcon(self)
	end
end

function PetBattleActionButton_UpdateState(self)
	local actionType = self.actionType;
	local actionIndex = self.actionIndex;

	local _, usable, cooldown, hasSelected, isSelected, isLocked, isHidden;
	local selectedActionType, selectedActionIndex = C_PetBattles.GetSelectedAction();

	--Decide whether we have a selected action and if it's this button.
	if ( selectedActionType ) then
		hasSelected = true;
		if ( actionType == selectedActionType and (not actionIndex or actionIndex == selectedActionIndex) ) then
			isSelected = true;
		end
	end

	--Get the battle state to check when looking at each action type.
	local battleState = C_PetBattles.GetBattleState();

	--Set up usable/cooldown/locked for each action type.
	if ( actionType == Enum.BattlePetAction.Ability ) then
		local _, name, icon = C_PetBattles.GetAbilityInfo(Enum.BattlePetOwner.Ally, C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally), actionIndex);

		--If we're being forced to swap pets, hide us
		if ( C_PetBattles.ShouldShowPetSelect() == true ) then
			isHidden = true;
		end

		--If we exist, check whether we're usable and what the cooldown is.
		if ( name ) then
			local isUsable, currentCooldown, currentLockdown = C_PetBattles.GetAbilityState(Enum.BattlePetOwner.Ally, C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally), actionIndex);
			usable = isUsable;
			cooldown = max(currentCooldown, currentLockdown);
		else
			isLocked = true;
		end
	elseif ( actionType == Enum.BattlePetAction.Trap ) then
		local trapErr;
		usable, trapErr = C_PetBattles.IsTrapAvailable();
		if (not usable and trapErr and trapErr > 1) then
			self.additionalText = _G["PET_BATTLE_TRAP_ERR_"..trapErr];
			self.Lock:SetShown(trapErr == 2); -- PETBATTLE_TRAPSTATUS_CANT_TRAP_NEWBIE
		else
			self.additionalText = nil;
		end
	elseif ( actionType == Enum.BattlePetAction.SwitchPet ) then
		--If we're being forced to swap pets, hide us
		if ( C_PetBattles.ShouldShowPetSelect() == true ) then
			isHidden = true;
		end
		
		usable = false;
		-- There must be at least one pet that can swap in
		for i = 1, NUM_BATTLE_PETS_IN_BATTLE do
			usable = usable or C_PetBattles.CanPetSwapIn(i);
		end
		-- AND the active pet must be able to swap out
		usable = usable and C_PetBattles.CanActivePetSwapOut();
	elseif ( actionType == Enum.BattlePetAction.Skip ) then
		usable = C_PetBattles.IsSkipAvailable();
	else
		usable = true;
	end

	if ( isHidden ) then
		self:Disable();
		self:SetAlpha(0);
	elseif ( isLocked ) then
		--Set the frame up to look like a cooldown, but with a required level
		if ( self.Icon ) then
			self.Icon:SetVertexColor(0.5, 0.5, 0.5);
			self.Icon:SetDesaturated(true);
		end
		self:Disable();
		self:SetAlpha(1);
		if ( self.SelectedHighlight ) then
			self.SelectedHighlight:Hide();
		end
		if ( self.CooldownShadow ) then
			self.CooldownShadow:Show();
		end
		if ( self.Cooldown ) then
			self.Cooldown:Hide();
		end
		if ( self.Lock ) then
			self.Lock:Show();
		end
		if ( self.AdditionalIcon ) then
			self.AdditionalIcon:SetVertexColor(0.5, 0.5, 0.5);
		end
		if ( self.BetterIcon ) then
			self.BetterIcon:Hide();
		end
	elseif ( cooldown and cooldown > 0 ) then
		--Set the frame up to look like a cooldown.
		if ( self.Icon ) then
			self.Icon:SetVertexColor(0.5, 0.5, 0.5);
			self.Icon:SetDesaturated(true);
		end
		self:Disable();
		self:SetAlpha(1);
		if ( self.SelectedHighlight ) then
			self.SelectedHighlight:Hide();
		end
		if ( self.CooldownShadow ) then
			self.CooldownShadow:Show();
		end
		if ( self.Cooldown ) then
			self.Cooldown:SetText(cooldown);
			self.Cooldown:Show();
		end
		if ( self.Lock ) then
			self.Lock:Hide();
		end
		if ( self.AdditionalIcon ) then
			self.AdditionalIcon:SetVertexColor(0.5, 0.5, 0.5);
		end
	elseif ( (not usable or hasSelected) and not isSelected ) then
		--Set the frame up to look unusable.
		if ( self.Icon ) then
			self.Icon:SetVertexColor(0.5, 0.5, 0.5);
			self.Icon:SetDesaturated(true);
		end
		self:Disable();
		self:SetAlpha(1);
		if ( self.SelectedHighlight ) then
			self.SelectedHighlight:Hide();
		end
		if ( self.CooldownShadow ) then
			self.CooldownShadow:Hide();
		end
		if ( self.Cooldown ) then
			self.Cooldown:Hide();
		end
		if ( self.Lock ) then
			self.Lock:Hide();
		end
		if ( self.AdditionalIcon ) then
			self.AdditionalIcon:SetVertexColor(0.5, 0.5, 0.5);
		end
	elseif ( hasSelected and isSelected ) then
		--Set the frame up to look selected.
		if ( self.Icon ) then
			self.Icon:SetVertexColor(1, 1, 1);
			self.Icon:SetDesaturated(false);
		end
		self:SetButtonState("NORMAL");
		self:Disable();
		self:SetAlpha(1);
		if ( self.SelectedHighlight ) then
			self.SelectedHighlight:Show();
		end
		if ( self.CooldownShadow ) then
			self.CooldownShadow:Hide();
		end
		if ( self.Cooldown ) then
			self.Cooldown:Hide();
		end
		if ( self.Lock ) then
			self.Lock:Hide();
		end
		if ( self.AdditionalIcon ) then
			self.AdditionalIcon:SetVertexColor(1, 1, 1);
		end
	else
		--Set the frame up to look clickable/usable.
		if ( self.Icon ) then
			self.Icon:SetVertexColor(1, 1, 1);
			self.Icon:SetDesaturated(false);
		end
		self:Enable();
		self:SetAlpha(1);
		if ( self.SelectedHighlight ) then
			self.SelectedHighlight:Hide();
		end
		if ( self.CooldownShadow ) then
			self.CooldownShadow:Hide();
		end
		if ( self.Cooldown ) then
			self.Cooldown:Hide();
		end
		if ( self.Lock ) then
			self.Lock:Hide();
		end
		if ( self.AdditionalIcon ) then
			self.AdditionalIcon:SetVertexColor(1, 1, 1);
		end
		if (self.CooldownFlash and actionType ~= Enum.BattlePetAction.Trap) then
			self.CooldownFlashAnim:Play();
		end
	end

	if ( actionType == Enum.BattlePetAction.Trap ) then
		if ( usable ) then
			if ( not self.playedSound ) then
				PlaySound(SOUNDKIT.UI_PET_BATTLES_TRAP_READY);
				self.playedSound = true;
			end
			ActionButtonSpellAlertManager:ShowAlert(self);
		else
			self.playedSound = false;
			ActionButtonSpellAlertManager:HideAlert(self);
		end
	end
end

-------------------------------------------------
-----------Pet Battle Ability Button-------------
--Only for abilities, not other action buttons---
-------------------------------------------------
function PetBattleAbilityButton_OnLoad(self)
	PetBattleActionButton_Initialize(self, Enum.BattlePetAction.Ability, self:GetID());
	PetBattleAbilityButton_UpdateHotKey(self);
end

function PetBattleAbilityButton_UpdateBetterIcon(self)
	if (not self.BetterIcon) then
		return;
	end
	self.BetterIcon:Hide();
	
	local activePet = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally);
	if (not activePet) then
		return;
	end

	local petType, noStrongWeakHints, _;
	_, _, _, _, _, _, petType, noStrongWeakHints = C_PetBattles.GetAbilityInfo(Enum.BattlePetOwner.Ally, activePet, self:GetID());
	if (not petType) then
		return;
	end
	
	-- show Strong/Weak icons on buttons.
	local enemyPetSlot = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Enemy);
	local enemyType = C_PetBattles.GetPetType(Enum.BattlePetOwner.Enemy, enemyPetSlot);
	local modifier = C_PetBattles.GetAttackModifier(petType, enemyType);

	if ( noStrongWeakHints or modifier == 1 ) then
		self.BetterIcon:Hide();
	elseif (modifier > 1) then
		self.BetterIcon:SetTexture("Interface\\PetBattles\\BattleBar-AbilityBadge-Strong");
		self.BetterIcon:Show();
	elseif (modifier < 1) then
		self.BetterIcon:SetTexture("Interface\\PetBattles\\BattleBar-AbilityBadge-Weak");
		self.BetterIcon:Show();
	end
end

function PetBattleAbilityButton_UpdateIcons(self)
	local activePet = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally);
	local id, name, icon, maxCooldown, unparsedDescription, numTurns, petType, noStrongWeakHints = C_PetBattles.GetAbilityInfo(Enum.BattlePetOwner.Ally, activePet, self:GetID());
	self.abilityID = id;
	if ( not icon ) then
		icon = "Interface\\Icons\\INV_Misc_QuestionMark";
	end
	if ( not name ) then
		--We don't have an ability here.
		local speciesID = C_PetBattles.GetPetSpeciesID(Enum.BattlePetOwner.Ally, activePet);
		local abilities = C_PetJournal.GetPetAbilityListTable(speciesID);	--Read ability/ability levels into the correct tables
		if(not abilities[self:GetID()]) then 
			self:Hide();
			return; 
		end 
		
		self.abilityID = abilities[self:GetID()].abilityID;
		if ( not self.abilityID ) then
			self.Icon:SetTexture("INTERFACE\\ICONS\\INV_Misc_Key_05");
			self:Hide();
		else
			name, icon = C_PetJournal.GetPetAbilityInfo(self.abilityID);
			self.Icon:SetTexture(icon);
			self.Lock:Show();
			self.requiredLevel = abilities[self:GetID()].level
		end
		self.Icon:SetVertexColor(1, 1, 1);
		self:Disable();
		return;
	end
	self.Icon:SetTexture(icon);
	self:Enable();
	self:Show();

	-- show Strong/Weak icons on buttons.
	PetBattleAbilityButton_UpdateBetterIcon(self);
end

function PetBattleAbilityButton_OnEnter(self)
	local petIndex = C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally);
	if ( self:GetEffectiveAlpha() > 0 ) then
		if ( C_PetBattles.GetAbilityInfo(Enum.BattlePetOwner.Ally, petIndex, self:GetID()) ) then
			PetBattleAbilityTooltip_SetAbility(Enum.BattlePetOwner.Ally, petIndex, self:GetID());
			PetBattleAbilityTooltip_Show("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -5, 120, self.additionalText);
		elseif ( self.abilityID ) then
			if ( self.requiredLevel ) then
				PetBattleAbilityTooltip_SetAbilityByID(Enum.BattlePetOwner.Ally, petIndex, self.abilityID, format(PET_ABILITY_REQUIRES_LEVEL, self.requiredLevel));
			else
				PetBattleAbilityTooltip_SetAbilityByID(Enum.BattlePetOwner.Ally, petIndex, self.abilityID);
			end
			PetBattleAbilityTooltip_Show("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -5, 120);
		end
	else
		PetBattlePrimaryAbilityTooltip:Hide();
	end
end

function PetBattleAbilityButton_OnLeave(self)
	PetBattlePrimaryAbilityTooltip:Hide();
end

function PetBattleAbilityButton_UpdateHotKey(self)
	local key = GetBindingKey("ACTIONBUTTON"..self:GetID());
	if ( key ) then
		self.HotKey:SetText(key);
		self.HotKey:Show();
	else
		self.HotKey:Hide();
	end
end

--------------------------------------------
----------Pet Battle Unit Frame-------------
--------------------------------------------
function PetBattleUnitFrame_OnLoad(self)
	self:RegisterEvent("PET_BATTLE_MAX_HEALTH_CHANGED");
	self:RegisterEvent("PET_BATTLE_HEALTH_CHANGED");
	self:RegisterEvent("PET_BATTLE_PET_CHANGED");
	
	self:RegisterEvent("PET_BATTLE_AURA_APPLIED");
	self:RegisterEvent("PET_BATTLE_AURA_CANCELED");
	self:RegisterEvent("PET_BATTLE_AURA_CHANGED");
	self:RegisterEvent("PET_BATTLE_PET_TYPE_CHANGED");
end

function PetBattleUnitFrame_OnClick(self, button)
	if ( button == "RightButton" ) then
		MenuUtil.CreateContextMenu(self, function(owner, rootDescription)
			rootDescription:SetTag("MENU_PET_BATTLE_PET");

			local name, speciesName = C_PetBattles.GetName(self.petOwner, self.petIndex);
			rootDescription:CreateTitle(name);

			if name and (name ~= speciesName) then
				local ownerIsEnemy = self.petOwner == Enum.BattlePetOwner.Enemy;
				local ownerIsNPC = not C_PetBattles.IsPlayerNPC(Enum.BattlePetOwner.Enemy);
				if ownerIsEnemy and (not ownerIsNPC) then
					rootDescription:CreateButton(REPORT_PET_NAME, function()
						C_PetBattles.SetPendingReportBattlePetTarget(self.petIndex);
						StaticPopup_Show("CONFIRM_REPORT_BATTLEPET_NAME", self.name);
					end);
				end
			end

			rootDescription:CreateButton(PET_SHOW_IN_JOURNAL, function()
				if not CollectionsJournal then
					CollectionsJournal_LoadUI();
				end

				if not CollectionsJournal:IsShown() then
					ShowUIPanel(CollectionsJournal);
				end

				CollectionsJournal_SetTab(CollectionsJournal, 2);

				local speciesID = C_PetBattles.GetPetSpeciesID(self.petOwner, self.petIndex);
				PetJournal_SelectSpecies(PetJournal, speciesID);
			end);
		end);
	end
end

function PetBattleUnitFrame_OnEvent(self, event, ...)
	if ( event == "PET_BATTLE_HEALTH_CHANGED" or event == "PET_BATTLE_MAX_HEALTH_CHANGED" ) then
		local petOwner, petIndex = ...;
		if ( petOwner == self.petOwner and petIndex == self.petIndex ) then
			PetBattleUnitFrame_UpdateHealthInstant(self);
		end
	elseif ( event == "PET_BATTLE_PET_CHANGED" ) then
		PetBattleUnitFrame_UpdateDisplay(self);
	elseif ( event == "PET_BATTLE_AURA_APPLIED" or
		event == "PET_BATTLE_AURA_CANCELED" or
		event == "PET_BATTLE_AURA_CHANGED" or 
		event == "PET_BATTLE_PET_TYPE_CHANGED" ) then
		local petOwner, petIndex = ...;
		if ( petOwner == self.petOwner and petIndex == self.petIndex ) then
			PetBattleUnitFrame_UpdatePetType(self);
		end
	end
end

function PetBattleUnitFrame_SetUnit(self, petOwner, petIndex)
	self.petOwner = petOwner;
	self.petIndex = petIndex;
	PetBattleUnitFrame_UpdateDisplay(self);
	PetBattleUnitFrame_UpdateHealthInstant(self);
	if ( petIndex > C_PetBattles.GetNumPets(petOwner) ) then
		self:Hide();
	else
		self:Show();
	end
end

function PetBattleUnitFrame_UpdateDisplay(self)
	local petOwner = self.petOwner;
	local petIndex = self.petIndex;

	if ( not petOwner or not petIndex ) then
		return;
	end

	if ( petIndex > C_PetBattles.GetNumPets(petOwner) ) then
		return;
	end

	local battleState = C_PetBattles.GetBattleState();

	--Update the pet species icon
	if ( self.Icon ) then
		if ( petOwner == Enum.BattlePetOwner.Ally ) then
			self.Icon:SetTexCoord(1, 0, 0, 1);
		else
			self.Icon:SetTexCoord(0, 1, 0, 1);
		end
		self.Icon:SetTexture(C_PetBattles.GetIcon(petOwner, petIndex));
	end

	--Get name info
	local name, speciesName = C_PetBattles.GetName(petOwner, petIndex);

	--Update the pet's custom name (will be the species name if it hasn't been changed).
	if ( self.Name ) then
		self.Name:SetText(name);
	end

	--Update the pet's species name (will be hidden if the custom name matches).
	if ( self.SpeciesName ) then
		if ( name ~= speciesName ) then
			self.SpeciesName:SetText(speciesName);
			self.SpeciesName:Show();
		else
			self.SpeciesName:Hide();
		end
	end
	
	--Update the pet rarity border
	if (self.Border) then
		local rarity = C_PetBattles.GetBreedQuality(petOwner, petIndex);
		if (CVarCallbackRegistry:GetCVarValueBool("colorblindMode")) then 
			self.Name:SetText(self.Name:GetText().." (".._G["BATTLE_PET_BREED_QUALITY"..rarity+1]..")");
		else
			local colorData = ColorManager.GetColorDataForItemQuality(rarity);
			if colorData then
				self.Border:SetVertexColor(colorData.r, colorData.g,colorData.b);		
				self.Name:SetVertexColor(colorData.r, colorData.g, colorData.b);
			end
		end
	end
	
	if (self.BorderAlive and self.BorderAlive:IsShown()) then
		local rarity = C_PetBattles.GetBreedQuality(petOwner, petIndex);
		local colorData = ColorManager.GetColorDataForItemQuality(rarity);
		if colorData then
			self.BorderAlive:SetVertexColor(colorData.r, colorData.g, colorData.b);		
		end
	end
	
	--Update the display of the level
	if ( self.Level ) then
		self.Level:SetText(C_PetBattles.GetLevel(petOwner, petIndex));
	end

	--Update the 3D model of the pet
	if ( self.PetModel ) then
		self.PetModel:SetDisplayInfo(C_PetBattles.GetDisplayID(petOwner, petIndex));
		self.PetModel:SetRotation(-BATTLE_PET_DISPLAY_ROTATION);
		self.PetModel:SetDoBlend(false);

		local petSpeciesID = C_PetBattles.GetPetSpeciesID(petOwner, petIndex);
		local x, y, z = PetBattlesOverrides.GetPositionOverride(petSpeciesID);
		if x and y and z then
			self.PetModel:SetPosition(x, y, z);
		else
			self.PetModel:SetPosition(0, 0, 0);
		end

		if ( C_PetBattles.GetHealth(petOwner, petIndex) == 0 ) then
			self.PetModel:SetAnimation(6, 0); --Display the dead animation
			--self.PetModel:SetAnimation(0, 0);
		else
			self.PetModel:SetAnimation(742, 0); -- Display the PetBattleStand animation
			--self.PetModel:SetAnimation(742, 0);
		end
	end

	--Updated the indicator that this is the active pet
	if ( self.SelectedTexture ) then
		if ( C_PetBattles.ShouldShowPetSelect() == false and
			C_PetBattles.GetActivePet(petOwner) == petIndex ) then
			self.SelectedTexture:Show();
		else
			self.SelectedTexture:Hide();
		end
	end

	--Update the XP bar
	if ( self.XPBar ) then
		local xp, maxXp = C_PetBattles.GetXP(petOwner, petIndex);
		self.XPBar:SetWidth(max((xp / max(maxXp,1)) * self.xpBarWidth, 1));
	end

	--Update the XP text
	if ( self.XPText ) then
		local xp, maxXp = C_PetBattles.GetXP(petOwner, petIndex);
		self.XPText:SetFormattedText(self.xpTextFormat or PET_BATTLE_CURRENT_XP_FORMAT, xp, maxXp);
	end

	--Update the pet type (e.g. "Flying", "Critter", "Magical", etc.)
	PetBattleUnitFrame_UpdatePetType(self);
end

function PetBattleUnitFrame_UpdateHealthInstant(self)
	local petOwner = self.petOwner;
	local petIndex = self.petIndex;

	local health = C_PetBattles.GetHealth(petOwner, petIndex);
	local maxHealth = C_PetBattles.GetMaxHealth(petOwner, petIndex);

	if ( self.HealthText ) then
		self.HealthText:SetFormattedText(self.healthTextFormat or PET_BATTLE_CURRENT_HEALTH_FORMAT, health, maxHealth);
	end
	if ( self.ActualHealthBar ) then
		if ( health == 0 ) then
			self.ActualHealthBar:Hide();
		else
			self.ActualHealthBar:Show();
		end
		self.ActualHealthBar:SetWidth((health / max(maxHealth,1)) * self.healthBarWidth);
	end
	if ( self.BorderAlive ) then
		if ( health == 0 ) then
			self.BorderAlive:Hide();
		else
			self.BorderAlive:Show();
		end
	end
	if ( self.BorderDead ) then
		if ( health == 0 ) then
			self.BorderDead:Show();
		else
			self.BorderDead:Hide();
		end
	end
	if ( self.hideWhenDeadList ) then
		for _, object in pairs(self.hideWhenDeadList) do
			if ( health == 0 ) then
				object:Hide();
			else
				object:Show();
			end
		end
	end
	if ( self.showWhenDeadList ) then
		for _, object in pairs(self.showWhenDeadList) do
			if ( health == 0 ) then
				object:Show();
			else
				object:Hide();
			end
		end
	end
end

function PetBattleUnitFrame_UpdatePetType(self)
	if ( self.PetType ) then
		local petType = C_PetBattles.GetPetType(self.petOwner, self.petIndex);

		self.PetType.Icon:SetTexture("Interface\\PetBattles\\PetIcon-"..PET_TYPE_SUFFIX[petType]);

		local auraID = PET_BATTLE_PET_TYPE_PASSIVES[petType];
		self.PetType.auraID = auraID;

		if ( auraID and self.PetType.ActiveStatus ) then
			local hasAura = PetBattleUtil_PetHasAura(self.petOwner, self.petIndex, auraID);
			if ( hasAura ) then
				self.PetType.ActiveStatus:Show();
			else
				self.PetType.ActiveStatus:Hide();
			end
		end
	end
end

--------------------------------------------
----------Pet Battle Unit Tooltips----------
--------------------------------------------
function PetBattleUnitTooltip_OnLoad(self)
	self.healthBarWidth = 230;
	self.xpBarWidth = 230;
	self.healthTextFormat = PET_BATTLE_HEALTH_VERBOSE;
	self.xpTextFormat = PET_BATTLE_CURRENT_XP_FORMAT_VERBOSE;
	PetBattleUnitFrame_OnLoad(self);

	self.weakToTextures = { self.WeakTo1 };
	self.resistantToTextures = { self.ResistantTo1 };
end

function PetBattleUnitTooltip_UpdateForUnit(self, petOwner, petIndex)
	PetBattleUnitFrame_SetUnit(self, petOwner, petIndex);

	local height = 198;
	local attack = C_PetBattles.GetPower(petOwner, petIndex);
	local speed = C_PetBattles.GetSpeed(petOwner, petIndex);
	local level = C_PetBattles.GetLevel(petOwner, petIndex);
	local opponentSpeed = 0;
	if ( petOwner == Enum.BattlePetOwner.Ally ) then
		opponentSpeed = C_PetBattles.GetSpeed(Enum.BattlePetOwner.Enemy, C_PetBattles.GetActivePet(Enum.BattlePetOwner.Enemy));
	else
		opponentSpeed = C_PetBattles.GetSpeed(Enum.BattlePetOwner.Ally, C_PetBattles.GetActivePet(Enum.BattlePetOwner.Ally));
	end
	if (speed > opponentSpeed) then
		height = height + 36;
		self.SpeedAdvantage:Show();
		self.SpeedAdvantageIcon:Show();
		self.Delimiter2:SetPoint("TOPLEFT", self.SpeedAdvantageIcon, "BOTTOMLEFT", -3, -10)
	else
		self.SpeedAdvantage:Hide();
		self.SpeedAdvantageIcon:Hide();
		self.Delimiter2:SetPoint("TOPLEFT", self.SpeedAdvantageIcon, "BOTTOMLEFT", -3, 26)
	end
	
	self.AttackAmount:SetText(attack);
	self.SpeedAmount:SetText(speed);
	
	local displayCollected = false;
	local speciesID = C_PetBattles.GetPetSpeciesID(Enum.BattlePetOwner.Enemy, petIndex);
	if ( speciesID ) then
		local _, _, _, _, _, _, _, _, _, _, obtainable = C_PetJournal.GetPetInfoBySpeciesID(speciesID);
		if ( obtainable and petOwner == Enum.BattlePetOwner.Enemy and C_PetBattles.IsWildBattle() ) then
			displayCollected = true;
		end
	end
	if ( displayCollected ) then
		local numOwned, maxAllowed = C_PetJournal.GetNumCollectedInfo(speciesID);
		if (numOwned < maxAllowed) then
			self.CollectedText:SetText(GREEN_FONT_COLOR_CODE..format(ITEM_PET_KNOWN, numOwned, maxAllowed)..FONT_COLOR_CODE_CLOSE);
		else
			self.CollectedText:SetText(RED_FONT_COLOR_CODE..format(ITEM_PET_KNOWN, numOwned, maxAllowed)..FONT_COLOR_CODE_CLOSE);
		end
		self.CollectedText:Show();
		self.HealthBorder:SetPoint("TOPLEFT", self.CollectedText, "BOTTOMLEFT", -1, -6);
		height = height + self.CollectedText:GetHeight()
	else
		self.CollectedText:Hide();
		self.HealthBorder:SetPoint("TOPLEFT", self.Icon, "BOTTOMLEFT", -1, -6);
	end
	
	if ( petOwner == Enum.BattlePetOwner.Ally and level < MAX_PET_LEVEL ) then
		--Add the XP bar
		self.XPBar:Show();
		self.XPBG:Show();
		self.XPBorder:Show();
		self.XPText:Show();
		self.Delimiter:SetPoint("TOP", self.XPBG, "BOTTOM", 0, -10);
		height = height + 18;
	else
		--Remove the XP bar
		self.XPBar:Hide();
		self.XPBG:Hide();
		self.XPBorder:Hide();
		self.XPText:Hide();
		self.Delimiter:SetPoint("TOP", self.HealthBG, "BOTTOM", 0, -10);
	end

	if ( petOwner == Enum.BattlePetOwner.Ally or C_PetBattles.IsPlayerNPC(petOwner) ) then
		--Show and update abilities
		self.AbilitiesLabel:Show();
		local enemyPetType = C_PetBattles.GetPetType(PetBattleUtil_GetOtherPlayer(petOwner), C_PetBattles.GetActivePet(PetBattleUtil_GetOtherPlayer(petOwner)));
		for i=1, NUM_BATTLE_PET_ABILITIES do
			local id, name, icon, maxCooldown, description, numTurns, abilityPetType, noStrongWeakHints = C_PetBattles.GetAbilityInfo(petOwner, petIndex, i);

			local abilityIcon = self["AbilityIcon"..i];
			local abilityName = self["AbilityName"..i];
			if ( id ) then
				local modifier = 1.0;
				if (abilityPetType and enemyPetType) then
					modifier = C_PetBattles.GetAttackModifier(abilityPetType, enemyPetType);
				end
				
				if ( noStrongWeakHints or modifier == 1 ) then
					abilityIcon:SetTexture("Interface\\PetBattles\\BattleBar-AbilityBadge-Neutral");
				elseif ( modifier < 1 ) then
					abilityIcon:SetTexture("Interface\\PetBattles\\BattleBar-AbilityBadge-Weak");
				elseif ( modifier > 1 ) then
					abilityIcon:SetTexture("Interface\\PetBattles\\BattleBar-AbilityBadge-Strong");
				end
				abilityName:SetText(name);
				abilityIcon:Show();
				abilityName:Show();
			else
				abilityIcon:Hide();
				abilityName:Hide();
			end
		end
	else

		--Hide abilities
		self.AbilitiesLabel:Hide();
		for i=1, NUM_BATTLE_PET_ABILITIES do
			self["AbilityIcon"..i]:Hide();
			self["AbilityName"..i]:Hide();
		end
	end

	if ( SHOW_WEAK_AND_RESISTANT ) then

		--Show and update weak to/resistant against
		self.WeakToLabel:Show();
		self.ResistantToLabel:Show();
		
		local nextWeakIndex, nextResistIndex = 1, 1;
		local currentPetType = C_PetBattles.GetPetType(petOwner, petIndex);
		for i=1, C_PetJournal.GetNumPetTypes() do
			local modifier = C_PetBattles.GetAttackModifier(i, currentPetType);
			if ( modifier > 1 ) then
				local icon = self.weakToTextures[nextWeakIndex];
				if ( not icon ) then
					self.weakToTextures[nextWeakIndex] = self:CreateTexture(nil, "ARTWORK", "PetBattleUnitTooltipPetTypeStrengthTemplate");
					icon = self.weakToTextures[nextWeakIndex];
					icon:ClearAllPoints();
					icon:SetPoint("LEFT", self.weakToTextures[nextWeakIndex - 1], "RIGHT", 5, 0);
				end
				icon:SetTexture("Interface\\PetBattles\\PetIcon-"..PET_TYPE_SUFFIX[i]);
				icon:Show();
				nextWeakIndex = nextWeakIndex + 1;
			elseif ( modifier < 1 ) then
				local icon = self.resistantToTextures[nextResistIndex];
				if ( not icon ) then
					self.resistantToTextures[nextResistIndex] = self:CreateTexture(nil, "ARTWORK", "PetBattleUnitTooltipPetTypeStrengthTemplate");
					icon = self.resistantToTextures[nextResistIndex];
					icon:ClearAllPoints();
					icon:SetPoint("LEFT", self.resistantToTextures[nextResistIndex - 1], "RIGHT", 5, 0);
				end
				icon:SetTexture("Interface\\PetBattles\\PetIcon-"..PET_TYPE_SUFFIX[i]);
				icon:Show();
				nextResistIndex = nextResistIndex + 1;
			end
		end

		for i=nextWeakIndex, #self.weakToTextures do
			self.weakToTextures[i]:Hide();
		end
		for i=nextResistIndex, #self.resistantToTextures do
			self.resistantToTextures[i]:Hide();
		end

		height = height + 5;
	else
		--Hide the weak to/resistant to
		self.WeakToLabel:Hide();
		self.ResistantToLabel:Hide();

		for _, texture in pairs(self.weakToTextures) do
			texture:Hide();
		end
		for _, texture in pairs(self.resistantToTextures) do
			texture:Hide();
		end
	end
	
	--Updates debuffs
	local nextFrame = 1;
	local debuffs = self.Debuffs;
	local debuffsHeight = 0;
	for i=1, C_PetBattles.GetNumAuras(petOwner, petIndex) do
		local auraID, instanceID, turnsRemaining, isBuff = C_PetBattles.GetAuraInfo(petOwner, petIndex, i);
		if (not isBuff) then
			--We want to display this frame.
			local frame = debuffs.frames[nextFrame];
			if ( not frame ) then
				--No frame, create one
				debuffs.frames[nextFrame] = CreateFrame("FRAME", nil, debuffs, debuffs.template);
				frame = debuffs.frames[nextFrame];
				
				--Anchor the new frame
				if ( nextFrame == 1 ) then
					frame:SetPoint("TOPLEFT", debuffs, "TOPLEFT", 0, 0);
				else
					frame:SetPoint("TOPLEFT", debuffs.frames[nextFrame - 1], "BOTTOMLEFT", 0, -6);
				end
			end
			
			--Update the actual aura
			local id, name, icon, maxCooldown, description = C_PetBattles.GetAbilityInfoByID(auraID);
			
			frame.Icon:SetTexture(icon);
			frame.Name:SetText(name);
			if ( turnsRemaining < 0 ) then
				frame.Duration:SetText("");
			else
				frame.Duration:SetFormattedText(PET_BATTLE_AURA_TURNS_REMAINING, turnsRemaining);
			end
			frame.auraIndex = i;
			frame:Show();

			nextFrame = nextFrame + 1;
			debuffsHeight = debuffsHeight + 40;
		end
	end
	
	for i=nextFrame, #debuffs.frames do
		debuffs.frames[i]:Hide();
	end
	
	if (nextFrame > 1) then
		debuffs:Show()
		self.Delimiter2:Show()
		debuffsHeight = debuffsHeight + 5 --extra padding to go below the debuffs
	else
		debuffs:Hide()
		self.Delimiter2:Hide()
	end
	
	debuffs:SetHeight(debuffsHeight);
	height = height + debuffsHeight;
	self:SetHeight(height);
end

function PetBattleUnitTooltip_Attach(self, point, frame, relativePoint, xOffset, yOffset)
	self:SetParent(frame);
	self:SetFrameStrata("TOOLTIP");
	self:ClearAllPoints();
	self:SetPoint(point, frame, relativePoint, xOffset, yOffset);
end

--------------------------------------------
---------Pet Battle Ability Tooltip---------
--------------------------------------------
PET_BATTLE_ABILITY_INFO = SharedPetBattleAbilityTooltip_GetInfoTable();

function PET_BATTLE_ABILITY_INFO:GetCooldown()
	if (self.abilityID) then
		return 0;
	end
	local isUsable, currentCooldown = C_PetBattles.GetAbilityState(self.petOwner, self.petIndex, self.abilityIndex);
	return currentCooldown;
end

function PET_BATTLE_ABILITY_INFO:GetAbilityID()
	if (self.abilityID) then
		return self.abilityID;
	end
	local id = C_PetBattles.GetAbilityInfo(self.petOwner, self.petIndex, self.abilityIndex);
	return id;
end

function PET_BATTLE_ABILITY_INFO:IsInBattle()
	return true;
end

function PET_BATTLE_ABILITY_INFO:GetMaxHealth(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetMaxHealth(petOwner, petIndex);
end

function PET_BATTLE_ABILITY_INFO:GetHealth(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetHealth(petOwner, petIndex);
end

function PET_BATTLE_ABILITY_INFO:GetAttackStat(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetPower(petOwner, petIndex);
end

function PET_BATTLE_ABILITY_INFO:GetSpeedStat(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetSpeed(petOwner, petIndex);
end

function PET_BATTLE_ABILITY_INFO:GetState(stateID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetStateValue(petOwner, petIndex, stateID);
end

function PET_BATTLE_ABILITY_INFO:GetWeatherState(stateID)
	return C_PetBattles.GetStateValue(Enum.BattlePetOwner.Weather, PET_BATTLE_PAD_INDEX, stateID);
end

function PET_BATTLE_ABILITY_INFO:GetPadState(stateID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetStateValue(petOwner, PET_BATTLE_PAD_INDEX, stateID);
end

function PET_BATTLE_ABILITY_INFO:GetPetOwner(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return petOwner;
end

function PET_BATTLE_ABILITY_INFO:HasAura(auraID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return PetBattleUtil_PetHasAura(petOwner, petIndex, auraID);
end

function PET_BATTLE_ABILITY_INFO:GetPetType(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetPetType(petOwner, petIndex);
end


--For use by other functions here
function PET_BATTLE_ABILITY_INFO:GetUnitFromToken(target)
	if ( target == "default" ) then
		target = "self";
	elseif ( target == "affected" ) then
		target = "enemy";
	end

	if ( target == "self" ) then
		return self.petOwner, self.petIndex;
	elseif ( target == "enemy" ) then
		local owner = PetBattleUtil_GetOtherPlayer(self.petOwner);
		return owner, C_PetBattles.GetActivePet(owner);
	else
		error("Unsupported token: "..tostring(target));
	end
end

function PetBattleAbilityTooltip_SetAbility(petOwner, petIndex, abilityIndex)
	PET_BATTLE_ABILITY_INFO.petOwner = petOwner;
	PET_BATTLE_ABILITY_INFO.petIndex = petIndex;
	PET_BATTLE_ABILITY_INFO.abilityID = nil;
	PET_BATTLE_ABILITY_INFO.abilityIndex = abilityIndex;
	SharedPetBattleAbilityTooltip_SetAbility(PetBattlePrimaryAbilityTooltip, PET_BATTLE_ABILITY_INFO);
end

function PetBattleAbilityTooltip_SetAbilityByID(petOwner, petIndex, abilityID, additionalText)
	PET_BATTLE_ABILITY_INFO.petOwner = petOwner;
	PET_BATTLE_ABILITY_INFO.petIndex = petIndex;
	PET_BATTLE_ABILITY_INFO.abilityID = abilityID;
	PET_BATTLE_ABILITY_INFO.abilityIndex = nil;
	SharedPetBattleAbilityTooltip_SetAbility(PetBattlePrimaryAbilityTooltip, PET_BATTLE_ABILITY_INFO, additionalText);
end

----------------------------------------------
------------Pet Battle Weather Frame----------
----------------------------------------------
function PetBattleWeatherFrame_OnLoad(self)
	self:RegisterEvent("PET_BATTLE_AURA_APPLIED");
	self:RegisterEvent("PET_BATTLE_AURA_CANCELED");
	self:RegisterEvent("PET_BATTLE_AURA_CHANGED");
end

function PetBattleWeatherFrame_OnEvent(self, event, ...)
	if ( event == "PET_BATTLE_AURA_APPLIED" or
		event == "PET_BATTLE_AURA_CANCELED" or
		event == "PET_BATTLE_AURA_CHANGED" ) then
		local petOwner, petIndex = ...;
		if ( petOwner == Enum.BattlePetOwner.Weather ) then
			PetBattleWeatherFrame_Update(self);
		end
	end
end

function PetBattleWeatherFrame_Update(self)
	local auraID, instanceID, turnsRemaining, isBuff = C_PetBattles.GetAuraInfo(Enum.BattlePetOwner.Weather, PET_BATTLE_PAD_INDEX, 1);
	if ( auraID ) then
		local id, name, icon, maxCooldown, description = C_PetBattles.GetAbilityInfoByID(auraID);
		self.Icon:SetTexture(icon);
		self.Name:SetText(name);
		if ( turnsRemaining < 0 ) then
			self.Duration:SetText("");
		else
			self.Duration:SetText(turnsRemaining);
		end

		local backgroundTexture = PET_BATTLE_WEATHER_TEXTURES[auraID];
		if ( backgroundTexture ) then
			self.BackgroundArt:SetTexture(backgroundTexture);
			self.BackgroundArt:Show();
		else
			self.BackgroundArt:Hide();
		end

		self:Show();
	else
		self:Hide();
	end
end

----------------------------------------------
------------Pet Battle Aura Holder------------
----------------------------------------------
function PetBattleAuraHolder_OnLoad(self)
	if ( not self.template ) then
		GMError("Must provide template for PetBattleAuraHolder");
	end
	if ( not self.displayBuffs and not self.displayDebuffs ) then
		GMError("Neither buffs nor nebuffs are displayed in a PetBattleAuraHolder");
	end

	self.frames = {};

	self:RegisterEvent("PET_BATTLE_AURA_APPLIED");
	self:RegisterEvent("PET_BATTLE_AURA_CANCELED");
	self:RegisterEvent("PET_BATTLE_AURA_CHANGED");
end

function PetBattleAuraHolder_OnEvent(self, event, ...)
	if ( event == "PET_BATTLE_AURA_APPLIED" or event == "PET_BATTLE_AURA_CANCELED" or event == "PET_BATTLE_AURA_CHANGED" ) then
		local petOwner, petIndex, instanceID = ...;
		if ( petOwner == self.petOwner and petIndex == self.petIndex ) then
			PetBattleAuraHolder_Update(self);
		end
	end
end

function PetBattleAuraHolder_SetUnit(self, petOwner, petIndex)
	self.petOwner = petOwner;
	self.petIndex = petIndex;
	PetBattleAuraHolder_Update(self);
end

function PetBattleAuraHolder_Update(self)
	if ( not self.petOwner or not self.petIndex ) then
		self:Hide();
		return;
	end

	local growsTo = self.growsToDirection;
	local numPerRow = self.numPerRow;
	local growsFrom = "LEFT";
	if ( growsTo == "LEFT" ) then
		growsFrom = "RIGHT";
	end

	local nextFrame = 1;
	for i=1, C_PetBattles.GetNumAuras(self.petOwner, self.petIndex) do
		local auraID, instanceID, turnsRemaining, isBuff = C_PetBattles.GetAuraInfo(self.petOwner, self.petIndex, i);
		if ( (isBuff and self.displayBuffs) or (not isBuff and self.displayDebuffs) ) then
			--We want to display this frame.
			local frame = self.frames[nextFrame];
			if ( not frame ) then
				--No frame, create one
				self.frames[nextFrame] = CreateFrame("FRAME", nil, self, self.template);
				frame = self.frames[nextFrame];

				--Anchor the new frame
				if ( nextFrame == 1 ) then
					frame:SetPoint("TOP"..growsFrom, self, "TOP"..growsFrom, 0, 0);
				elseif ( (nextFrame - 1) % numPerRow == 0 ) then
					frame:SetPoint("TOP"..growsFrom, self.frames[nextFrame - numPerRow], "BOTTOM"..growsFrom, 0, 0);
				else
					frame:SetPoint("TOP"..growsFrom, self.frames[nextFrame - 1], "TOP"..growsTo, growsTo == "LEFT" and -4 or 4, 0);
				end
			end

			--Update the actual aura
			local id, name, icon, maxCooldown, description = C_PetBattles.GetAbilityInfoByID(auraID);

			if ( isBuff ) then
				frame.DebuffBorder:Hide();
			else
				frame.DebuffBorder:Show();
			end

			frame.Icon:SetTexture(icon);
			if ( turnsRemaining < 0 ) then
				frame.Duration:SetText("");
			else
				frame.Duration:SetFormattedText(PET_BATTLE_AURA_TURNS_REMAINING, turnsRemaining);
			end
			frame.auraIndex = i;
			frame:Show();

			nextFrame = nextFrame + 1;
		end
	end

	if ( nextFrame > 1 ) then
		--We have at least one aura displayed
		local numRows = math.floor((nextFrame - 2) / numPerRow) + 1; -- -2, 1 for this being the "next", not "previous" frame, 1 for 0-based math.
		self:SetHeight(self.frames[1]:GetHeight() * numRows);
		self:Show();
	else
		--Empty
		self:SetHeight(1);
		self:Hide();
	end

	for i=nextFrame, #self.frames do
		self.frames[i]:Hide();
	end
end

function PetBattleAura_OnEnter(self)
	local parent = self:GetParent();
	local isEnemy = (parent.petOwner == Enum.BattlePetOwner.Enemy);
	PetBattleAbilityTooltip_SetAura(parent.petOwner, parent.petIndex, self.auraIndex);
	if ( isEnemy ) then
		PetBattleAbilityTooltip_Show("TOPRIGHT", self, "BOTTOMLEFT", 15, 5);
	else
		PetBattleAbilityTooltip_Show("TOPLEFT", self, "BOTTOMRIGHT", -15, 5);
	end
end

function PetBattleAura_OnLeave(self)
	PetBattlePrimaryAbilityTooltip:Hide();
end

PET_BATTLE_AURA_INFO = SharedPetBattleAbilityTooltip_GetInfoTable();
function PET_BATTLE_AURA_INFO:GetAbilityID()
	local auraID, instanceID, turnsRemaining, isBuff = C_PetBattles.GetAuraInfo(self.petOwner, self.petIndex, self.auraIndex);
	return auraID;
end

function PET_BATTLE_AURA_INFO:GetRemainingDuration()
	local auraID, instanceID, turnsRemaining, isBuff = C_PetBattles.GetAuraInfo(self.petOwner, self.petIndex, self.auraIndex);
	return turnsRemaining;
end

function PET_BATTLE_AURA_INFO:IsInBattle()
	return true;
end

function PET_BATTLE_AURA_INFO:GetMaxHealth(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetMaxHealth(petOwner, petIndex);
end

function PET_BATTLE_AURA_INFO:GetHealth(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetHealth(petOwner, petIndex);
end

function PET_BATTLE_AURA_INFO:GetAttackStat(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetPower(petOwner, petIndex);
end

function PET_BATTLE_AURA_INFO:GetSpeedStat(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetSpeed(petOwner, petIndex);
end

function PET_BATTLE_AURA_INFO:GetState(stateID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetStateValue(petOwner, petIndex, stateID);
end

function PET_BATTLE_AURA_INFO:GetWeatherState(stateID)
	return C_PetBattles.GetStateValue(Enum.BattlePetOwner.Weather, PET_BATTLE_PAD_INDEX, stateID);
end

function PET_BATTLE_AURA_INFO:GetPadState(stateID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetStateValue(petOwner, PET_BATTLE_PAD_INDEX, stateID);
end

function PET_BATTLE_AURA_INFO:GetPetOwner(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return petOwner;
end

function PET_BATTLE_AURA_INFO:HasAura(auraID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return PetBattleUtil_PetHasAura(petOwner, petIndex, auraID);
end

function PET_BATTLE_AURA_INFO:GetPetType(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetPetType(petOwner, petIndex);
end

function PET_BATTLE_AURA_INFO:GetUnitFromToken(target)
	if ( target == "default" ) then
		target = "auracaster";
	elseif ( target == "affected" ) then
		target = "aurawearer";
	end

	if ( target == "aurawearer" ) then
		local petOwner, petIndex = self.petOwner, self.petIndex; --The "wearer" refers to the affected pet, not the pad.
		if ( petIndex == PET_BATTLE_PAD_INDEX ) then
			petIndex = C_PetBattles.GetActivePet(petOwner);
		end
		return petOwner, petIndex;
	elseif ( target == "auracaster" ) then
		local _, _, _, _, casterOwner, casterIndex = C_PetBattles.GetAuraInfo(self.petOwner, self.petIndex, self.auraIndex);
		return casterOwner, casterIndex;
	elseif ( target == "auraenemy" ) then
		local petOwner = PetBattleUtil_GetOtherPlayer(self.petOwner);
		return petOwner, C_PetBattles.GetActivePet(petOwner);
	else
		error("Unsupported token: "..tostring(target));
	end
end

function PetBattleAbilityTooltip_SetAura(petOwner, petIndex, auraIndex)
	PET_BATTLE_AURA_INFO.petOwner = petOwner;
	PET_BATTLE_AURA_INFO.petIndex = petIndex;
	PET_BATTLE_AURA_INFO.auraIndex = auraIndex;
	SharedPetBattleAbilityTooltip_SetAbility(PetBattlePrimaryAbilityTooltip, PET_BATTLE_AURA_INFO);
end

----------------------------------------------
----------Pet Battle Aura ID Tooltip----------
----------------------------------------------
PET_BATTLE_AURA_ID_INFO = SharedPetBattleAbilityTooltip_GetInfoTable();
function PET_BATTLE_AURA_ID_INFO:GetAbilityID()
	return self.auraID;
end

function PET_BATTLE_AURA_ID_INFO:IsInBattle()
	return true;
end

function PET_BATTLE_AURA_ID_INFO:GetMaxHealth(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetMaxHealth(petOwner, petIndex);
end

function PET_BATTLE_AURA_ID_INFO:GetHealth(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetHealth(petOwner, petIndex);
end

function PET_BATTLE_AURA_ID_INFO:GetAttackStat(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetPower(petOwner, petIndex);
end

function PET_BATTLE_AURA_ID_INFO:GetSpeedStat(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetSpeed(petOwner, petIndex);
end

function PET_BATTLE_AURA_ID_INFO:GetState(stateID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetStateValue(petOwner, petIndex, stateID);
end

function PET_BATTLE_AURA_ID_INFO:GetWeatherState(stateID)
	return C_PetBattles.GetStateValue(Enum.BattlePetOwner.Weather, PET_BATTLE_PAD_INDEX, stateID);
end

function PET_BATTLE_AURA_ID_INFO:GetPadState(stateID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetStateValue(petOwner, PET_BATTLE_PAD_INDEX, stateID);
end

function PET_BATTLE_AURA_ID_INFO:GetPetOwner(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return petOwner;
end

function PET_BATTLE_AURA_ID_INFO:HasAura(auraID, target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return PetBattleUtil_PetHasAura(petOwner, petIndex, auraID);
end

function PET_BATTLE_AURA_ID_INFO:GetPetType(target)
	local petOwner, petIndex = self:GetUnitFromToken(target);
	return C_PetBattles.GetPetType(petOwner, petIndex);
end
function PET_BATTLE_AURA_ID_INFO:GetUnitFromToken(target)
	if ( target == "default" ) then
		target = "auracaster";
	elseif ( target == "affected" ) then
		target = "aurawearer";
	end

	if ( target == "aurawearer" ) then
		local petOwner, petIndex = self.petOwner, self.petIndex;
		if ( petIndex == PET_BATTLE_PAD_INDEX ) then --The "wearer" refers to the affected pet, not the pad.
			petIndex = C_PetBattles.GetActivePet(petOwner);
		end
		return petOwner, petIndex;
	elseif ( target == "auracaster" ) then
		return self.petOwner, self.petIndex;	--Setting by ID should only occur for auras that aren't actually on the target (such as passives). These can be considered as cast by this pet.
	elseif ( target == "auraenemy" ) then
		local petOwner = PetBattleUtil_GetOtherPlayer(self.petOwner);
		return petOwner, C_PetBattles.GetActivePet(petOwner);
	else
		error("Unsupported token: "..tostring(target));
	end
end

function PetBattleAbilityTooltip_SetAuraID(petOwner, petIndex, auraID)
	PET_BATTLE_AURA_ID_INFO.petOwner = petOwner;
	PET_BATTLE_AURA_ID_INFO.petIndex = petIndex;
	PET_BATTLE_AURA_ID_INFO.auraID = auraID;
	SharedPetBattleAbilityTooltip_SetAbility(PetBattlePrimaryAbilityTooltip, PET_BATTLE_AURA_ID_INFO);
end

----------------------------------------------
-------Pet Battle Ability Tooltip Funcs-------
----------------------------------------------
function PetBattleAbilityTooltip_Show(anchorPoint, anchorTo, relativePoint, xOffset, yOffset)
	PetBattlePrimaryAbilityTooltip:ClearAllPoints();
	PetBattlePrimaryAbilityTooltip:SetPoint(anchorPoint, anchorTo, relativePoint, xOffset, yOffset);
	PetBattlePrimaryAbilityTooltip:Show();
end

----------------------------------------------
------------Pet Battle Util Funcs-------------
----------------------------------------------
function PetBattleUtil_GetOtherPlayer(player)
	if ( player == Enum.BattlePetOwner.Ally ) then
		return Enum.BattlePetOwner.Enemy;
	elseif ( player == Enum.BattlePetOwner.Enemy ) then
		return Enum.BattlePetOwner.Ally;
	end
end

function PetBattleUtil_PetHasAura(petOwner, petIndex, auraID)
	for i=1, C_PetBattles.GetNumAuras(petOwner, petIndex) do
		local id, instanceID, turnsRemaining, isBuff = C_PetBattles.GetAuraInfo(petOwner, petIndex, i);
		if ( id == auraID ) then
			return true;
		end
	end
	return false;
end

