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",
};

StaticPopupDialogs["PET_BATTLE_FORFEIT"] = {
	text = PET_BATTLE_FORFEIT_CONFIRMATION,
	button1 = OKAY,
	button2 = CANCEL,
	maxLetters = 30,
	OnAccept = function(self)
		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(self)
		C_PetBattles.ForfeitGame();
	end,
	timeout = 0,
	exclusive = 1,
	hideOnEscape = 1
};
--------------------------------------------
-------------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], LE_BATTLE_PET_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_TURN_STARTED");
	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");
	
	-- 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");
end

function PetBattleFrame_OnEvent(self, event, ...)
	if ( event == "PET_BATTLE_OPENING_START" ) then
		PlaySoundKitID(32047); -- UI_PetBattle_Camera_Move_In
		PetBattleFrame_Display(self);
	elseif ( event == "PET_BATTLE_OPENING_DONE" ) then
		PetBattleFrameTurnTimer_UpdateValues(self.BottomFrame.TurnTimer);
		StartSplashTexture.splashAnim:Play();
		PlaySoundKitID(31584); -- UI_PetBattle_Start
		PetBattleFrame_UpdateSpeedIndicators(self);
	elseif ( event == "PET_BATTLE_TURN_STARTED" ) then
		PetBattleFrameTurnTimer_UpdateValues(self.BottomFrame.TurnTimer);
	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
		PlaySoundKitID(32052); -- UI_PetBattle_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" ) 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);
	end
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 == BATTLE_PET_ACTION_NONE ) ) and ( battleState == LE_PET_BATTLE_STATE_WAITING_PRE_BATTLE ) or ( battleState == LE_PET_BATTLE_STATE_WAITING_FOR_FRONT_PETS );
	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 = LE_BATTLE_PET_ENEMY;
	elseif (PetBattleFrame.ActiveAlly.SpeedIcon:IsShown()) then
		hadSpeedIcon = LE_BATTLE_PET_ALLY;
	end
	
	local enemyActive = C_PetBattles.GetActivePet(LE_BATTLE_PET_ENEMY);
	local enemySpeed = C_PetBattles.GetSpeed(LE_BATTLE_PET_ENEMY, enemyActive);

	local allyActive = C_PetBattles.GetActivePet(LE_BATTLE_PET_ALLY);
	local allySpeed = C_PetBattles.GetSpeed(LE_BATTLE_PET_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 == LE_BATTLE_PET_ALLY)) then
		PetBattleFrame.ActiveEnemy.SpeedFlash:Play();
	elseif (enemySpeed < allySpeed and (not hadSpeedIcon or hadSpeedIcon == LE_BATTLE_PET_ENEMY)) then
		PetBattleFrame.ActiveAlly.SpeedFlash:Play();
	end
end

function PetBattleFrame_UpdateXpBar(self)
	local activePet = C_PetBattles.GetActivePet(LE_BATTLE_PET_ALLY);
	local level = C_PetBattles.GetLevel(LE_BATTLE_PET_ALLY, activePet);
	if (level >= MAX_PET_LEVEL) then
		self.BottomFrame.xpBar:Hide();
		return;
	end
	
	local xp, maxXp = C_PetBattles.GetXP(LE_BATTLE_PET_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 = _G["PetBattleXPBarDiv"..i];
		if not texture then
			texture = self.BottomFrame.xpBar:CreateTexture("MainMenuXPBarDiv"..i, "OVERLAY");
			texture:SetTexture("Interface\\MainMenuBar\\UI-XP-Bar");
			texture:SetSize(9,9);
			texture:SetTexCoord( 0.01562500, 0.15625000, 0.01562500, 0.17187500);
		end
		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(LE_BATTLE_PET_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(LE_BATTLE_PET_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(LE_BATTLE_PET_ALLY);
		local abilityID = C_PetBattles.GetAbilityInfo(LE_BATTLE_PET_ALLY, activePet, self:GetID());
		local maxHealth = C_PetBattles.GetMaxHealth(LE_BATTLE_PET_ALLY, activePet);
		local power = C_PetBattles.GetPower(LE_BATTLE_PET_ALLY, activePet);
		local speed = C_PetBattles.GetSpeed(LE_BATTLE_PET_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(LE_BATTLE_PET_ALLY);
	local activeEnemy = C_PetBattles.GetActivePet(LE_BATTLE_PET_ENEMY);

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

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

	PetBattleAuraHolder_SetUnit(self.EnemyBuffFrame, LE_BATTLE_PET_ENEMY, activeEnemy);
	PetBattleAuraHolder_SetUnit(self.EnemyDebuffFrame, LE_BATTLE_PET_ENEMY, activeEnemy);
	PetBattleAuraHolder_SetUnit(self.AllyBuffFrame, LE_BATTLE_PET_ALLY, activeAlly);
	PetBattleAuraHolder_SetUnit(self.AllyDebuffFrame, LE_BATTLE_PET_ALLY, activeAlly);
	PetBattleAuraHolder_SetUnit(self.EnemyPadBuffFrame, LE_BATTLE_PET_ENEMY, PET_BATTLE_PAD_INDEX);
	PetBattleAuraHolder_SetUnit(self.EnemyPadDebuffFrame, LE_BATTLE_PET_ENEMY, PET_BATTLE_PAD_INDEX);
	PetBattleAuraHolder_SetUnit(self.AllyPadBuffFrame, LE_BATTLE_PET_ALLY, PET_BATTLE_PAD_INDEX);
	PetBattleAuraHolder_SetUnit(self.AllyPadDebuffFrame, LE_BATTLE_PET_ALLY, PET_BATTLE_PAD_INDEX);
end

function PetBattleFrame_Remove(self)
	ActionButton_HideOverlayGlow(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() ~= LE_PET_BATTLE_STATE_WAITING_PRE_BATTLE ) and
		 ( C_PetBattles.GetBattleState() ~= LE_PET_BATTLE_STATE_ROUND_IN_PROGRESS ) and
		 ( C_PetBattles.GetBattleState() ~= LE_PET_BATTLE_STATE_WAITING_FOR_FRONT_PETS ) ) 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, levels = C_PetJournal.GetPetAbilityList(speciesID);
	for i, level in pairs(levels) do
		if level == targetLevel then
			return abilities[i];
		end
	end

	return nil;
end

--------------------------------------------
------Pet Battle Pet Selection Frame--------
--------------------------------------------
function PetBattlePetSelectionFrame_Show(self)
	local numPets = C_PetBattles.GetNumPets(LE_BATTLE_PET_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 == LE_BATTLE_PET_ACTION_ABILITY ) then
		local _, name, icon = C_PetBattles.GetAbilityInfo(LE_BATTLE_PET_ALLY, C_PetBattles.GetActivePet(LE_BATTLE_PET_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(LE_BATTLE_PET_ALLY, C_PetBattles.GetActivePet(LE_BATTLE_PET_ALLY), actionIndex);
			usable = isUsable;
			cooldown = max(currentCooldown, currentLockdown);
		else
			isLocked = true;
		end
	elseif ( actionType == LE_BATTLE_PET_ACTION_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 == LE_BATTLE_PET_ACTION_SWITCH_PET ) 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 == LE_BATTLE_PET_ACTION_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 ~= LE_BATTLE_PET_ACTION_TRAP) then
			self.CooldownFlashAnim:Play();
		end
	end

	if ( actionType == LE_BATTLE_PET_ACTION_TRAP ) then
		if ( usable ) then
			if ( not self.playedSound ) then
				PlaySoundKitID(28814);
				self.playedSound = true;
			end
			ActionButton_ShowOverlayGlow(self);
		else
			self.playedSound = false;
			ActionButton_HideOverlayGlow(self);
		end
	end
end

-------------------------------------------------
-----------Pet Battle Ability Button-------------
--Only for abilities, not other action buttons---
-------------------------------------------------
function PetBattleAbilityButton_OnLoad(self)
	PetBattleActionButton_Initialize(self, LE_BATTLE_PET_ACTION_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(LE_BATTLE_PET_ALLY);
	if (not activePet) then
		return;
	end

	local petType, noStrongWeakHints, _;
	_, _, _, _, _, _, petType, noStrongWeakHints = C_PetBattles.GetAbilityInfo(LE_BATTLE_PET_ALLY, activePet, self:GetID());
	if (not petType) then
		return;
	end
	
	-- show Strong/Weak icons on buttons.
	local enemyPetSlot = C_PetBattles.GetActivePet(LE_BATTLE_PET_ENEMY);
	local enemyType = C_PetBattles.GetPetType(LE_BATTLE_PET_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(LE_BATTLE_PET_ALLY);
	local id, name, icon, maxCooldown, unparsedDescription, numTurns, petType, noStrongWeakHints = C_PetBattles.GetAbilityInfo(LE_BATTLE_PET_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 abilities = {};
		local abilityLevels = {};
		local speciesID = C_PetBattles.GetPetSpeciesID(LE_BATTLE_PET_ALLY, activePet);
		C_PetJournal.GetPetAbilityList(speciesID, abilities, abilityLevels);	--Read ability/ability levels into the correct tables
		self.abilityID = abilities[self:GetID()];
		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 = abilityLevels[self:GetID()];
		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(LE_BATTLE_PET_ALLY);
	if ( self:GetEffectiveAlpha() > 0 ) then
		if ( C_PetBattles.GetAbilityInfo(LE_BATTLE_PET_ALLY, petIndex, self:GetID()) ) then
			PetBattleAbilityTooltip_SetAbility(LE_BATTLE_PET_ALLY, petIndex, self:GetID());
			PetBattleAbilityTooltip_Show("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -5, 120, self.additionalText);
		elseif ( self.abilityID ) then
			if ( self.requiredLevel ) then
				PetBattleAbilityTooltip_SetAbilityByID(LE_BATTLE_PET_ALLY, petIndex, self.abilityID, format(PET_ABILITY_REQUIRES_LEVEL, self.requiredLevel));
			else
				PetBattleAbilityTooltip_SetAbilityByID(LE_BATTLE_PET_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
		PetBattleUnitFrame_ShowDropdown(self, self.petIndex);
	end
end

function PetBattleUnitFrame_ShowDropdown(self, petIndex)
	--Right now, this only has the report option, so we won't display the dropdown if that won't be available
	local name, speciesName = C_PetBattles.GetName(self.petOwner, petIndex);
	
	HideDropDownMenu(1);
	PetBattleUnitFrameDropDown.petOwner = self.petOwner;	
	PetBattleUnitFrameDropDown.name = name;	
	PetBattleUnitFrameDropDown.petIndex = petIndex;
	PetBattleUnitFrameDropDown.speciesID = C_PetBattles.GetPetSpeciesID(self.petOwner, self.petIndex);	
	ToggleDropDownMenu(1, nil, PetBattleUnitFrameDropDown, "cursor");
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 == LE_BATTLE_PET_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 (ENABLE_COLORBLIND_MODE == "1") then 
			self.Name:SetText(self.Name:GetText().." (".._G["BATTLE_PET_BREED_QUALITY"..rarity]..")");
		else
			self.Border:SetVertexColor(ITEM_QUALITY_COLORS[rarity-1].r, ITEM_QUALITY_COLORS[rarity-1].g, ITEM_QUALITY_COLORS[rarity-1].b);		
			self.Name:SetVertexColor(ITEM_QUALITY_COLORS[rarity-1].r, ITEM_QUALITY_COLORS[rarity-1].g, ITEM_QUALITY_COLORS[rarity-1].b);
		end
	end
	
	if (self.BorderAlive and self.BorderAlive:IsShown()) then
		local rarity = C_PetBattles.GetBreedQuality(petOwner, petIndex);
		self.BorderAlive:SetVertexColor(ITEM_QUALITY_COLORS[rarity-1].r, ITEM_QUALITY_COLORS[rarity-1].g, ITEM_QUALITY_COLORS[rarity-1].b);		
	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);
		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 };
	self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
	self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
end

function PetBattleUnitFrameDropDown_ReportUnit(btn, name, petIndex)
	C_PetBattles.SetPendingReportBattlePetTarget(petIndex);
	StaticPopup_Show("CONFIRM_REPORT_BATTLEPET_NAME", name);
end

function PetBattleUnitFrameDropDown_Initialize(self)
	local info = UIDropDownMenu_CreateInfo();
	info.text = self.name;
	info.isTitle = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);

	info.isTitle = nil;
	info.disabled = nil;
	
	local name, speciesName = C_PetBattles.GetName(self.petOwner, self.petIndex);
	if (not C_PetBattles.IsPlayerNPC(LE_BATTLE_PET_ENEMY) and self.petOwner == LE_BATTLE_PET_ENEMY 
		and name and name ~= speciesName) then
		info.text = REPORT_PET_NAME;
		info.func = PetBattleUnitFrameDropDown_ReportUnit;
		info.arg1 = self.name;
		info.arg2 = self.petIndex;
		UIDropDownMenu_AddButton(info);
	end
	
	info.text = PET_SHOW_IN_JOURNAL;
	info.func = function ()
					if (not CollectionsJournal) then
						CollectionsJournal_LoadUI();
					end
					if (not CollectionsJournal:IsShown()) then
						ShowUIPanel(CollectionsJournal);
					end
					CollectionsJournal_SetTab(CollectionsJournal, 2);
					PetJournal_SelectSpecies(PetJournal, self.speciesID);
				end
	UIDropDownMenu_AddButton(info);
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 == LE_BATTLE_PET_ALLY ) then
		opponentSpeed = C_PetBattles.GetSpeed(LE_BATTLE_PET_ENEMY, C_PetBattles.GetActivePet(LE_BATTLE_PET_ENEMY));
	else
		opponentSpeed = C_PetBattles.GetSpeed(LE_BATTLE_PET_ALLY, C_PetBattles.GetActivePet(LE_BATTLE_PET_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(LE_BATTLE_PET_ENEMY, petIndex);
	if ( speciesID ) then
		local _, _, _, _, _, _, _, _, _, _, obtainable = C_PetJournal.GetPetInfoBySpeciesID(speciesID);
		if ( obtainable and petOwner == LE_BATTLE_PET_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 == LE_BATTLE_PET_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 == LE_BATTLE_PET_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(LE_BATTLE_PET_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 == LE_BATTLE_PET_WEATHER ) then
			PetBattleWeatherFrame_Update(self);
		end
	end
end

function PetBattleWeatherFrame_Update(self)
	local auraID, instanceID, turnsRemaining, isBuff = C_PetBattles.GetAuraInfo(LE_BATTLE_PET_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 == LE_BATTLE_PET_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(LE_BATTLE_PET_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(LE_BATTLE_PET_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 == LE_BATTLE_PET_ALLY ) then
		return LE_BATTLE_PET_ENEMY;
	elseif ( player == LE_BATTLE_PET_ENEMY ) then
		return LE_BATTLE_PET_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

