local _,L = ...
local rematch = Rematch
local card = RematchPetCard
local settings, roster

card.statButtons = {} -- frame pool of RematchPetCardStatTemplate buttons

rematch:InitModule(function()
	rematch.PetCard = card
	settings = RematchSettings
	roster = rematch.Roster
	local font,size,flag = card.Title.Name:GetFont()
	card.Title.Name:SetFont(font,size+2,flag)
	card.Back.Bottom.DamageTaken:SetText(L["Damage\nTaken"])
	card.Back.Bottom.StrongFrom:SetText(L["from"])
	card.Back.Bottom.WeakFrom:SetText(L["from"])
	card.Back.Bottom.StrongAbilities:SetText(L["abilities"])
	card.Back.Bottom.WeakAbilities:SetText(L["abilities"])
	card.PinButton.tooltipTitle = L["Unpin Pet Card"]
	card.PinButton.tooltipBody = L["While pinned, the pet card will display where you last moved it.\n\nClick this to unpin the pet card and snap it back to the pets."]
	card.PetCardTitle:SetText(L["Pet Card"])
	card.Front.Middle.AltFlipHelp:SetText(L["Hold [Alt] to view more about this pet."])
	for i=1,6 do
		card.Front.Bottom.Abilities[i]:RegisterForClicks("AnyUp")
	end
	rematch:ConvertTitlebarCloseButton(card.CloseButton)
	rematch:SetTitlebarButtonIcon(card.PinButton,"pin")
end)

-- TODO: rewrite this; break it apart into components (it's too long)
function rematch:ShowPetCard(parent,petID,force)

	if (card.locked and not force) or rematch:UIJustChanged() then
		return -- don't show a new pet card if current one is locked or just left a menu/frame shown/etc
	end

	if settings.ClickPetCard and not force then
		return
	end

	-- if FastPetCard not enabled, then cause a 0.25 delay before showing a card (unless it's forced)
	if not settings.ClickPetCard and not settings.FastPetCard then
		if parent and petID and not force then
			card.parent = parent
			card.petID = petID
			rematch:StartTimer("PetCard",0.25,rematch.ShowPetCard)
			return
		elseif not force then
			parent = card.parent
			petID = card.petID
		end
	end

	if not parent or not petID then return end

	-- search hits are shown only for cards displayed from the pet panel
	-- check if card's parent is a descendant of the pet panel
	local forPetPanel
	local candidate = parent
	repeat
		candidate = candidate:GetParent()
		if not candidate or candidate==UIParent then
			forPetPanel = false
		elseif candidate==rematch.PetPanel then
			forPetPanel = true
		end
	until forPetPanel~=nil

	local leveling,speciesID,customName,level,xp,maxXP,displayID,isFavorite,name,icon,petType,_,sourceText,description,canBattle,isTradable,unique,obtainable
	local health,maxHealth,power,speed,rarity,petBreed
	local idTYpe

	if type(petID)=="table" and petID.speciesID then -- petID is a table of stats
		speciesID = petID.speciesID
		level = petID.level
		health = petID.health or 100
		maxHealth = health
		power = petID.power or 0
		speed = petID.speed or 0
		rarity = petID.rarity or 4
		petBreed = petID.breed
		name,icon,petType,_,sourceText,description,_,canBattle,isTradable,unique,obtainable,displayID = C_PetJournal.GetPetInfoBySpeciesID(speciesID)
		idType = "table"
	else -- petID is either a string ("BattlePet-0-00etc") or a numbered species (42) or a leveling pet (0)
		idType = rematch:GetIDType(petID)
		if idType=="pet" then
			speciesID,customName,level,xp,maxXP,displayID,isFavorite,name,icon,petType,_,sourceText,description,_,canBattle,isTradable,unique,obtainable = C_PetJournal.GetPetInfoByPetID(petID)
			health,maxHealth,power,speed,rarity = C_PetJournal.GetPetStats(petID)
		elseif idType=="species" then
			speciesID = petID
			name,icon,petType,_,sourceText,description,_,canBattle,isTradable,unique,obtainable,displayID = C_PetJournal.GetPetInfoBySpeciesID(petID)
		elseif idType=="leveling" then
			leveling = true
			name = L["Leveling Pet"]
			icon = "Interface\\AddOns\\Rematch\\Textures\\levelingicon-round.blp"
		end
	end

	if (not speciesID or not petType) and not leveling then
		return
	end

	-- hide the search hits
	card.Title.Icon.SearchHit:Hide()
	card.Title.Type.SearchHit:Hide()
	for i=1,6 do
		card.Front.Bottom.Abilities[i].SearchHit:Hide()
	end

	-- title stuff
	card.Title.Name:SetText(customName or name)
	if leveling then
		card.Title.Icon.Texture:SetTexture(icon)
		card.Title.Type.Texture:SetTexCoord(0,1,0,1)
		SetPortraitToTexture(card.Title.Type.Texture,"Interface\\Icons\\INV_Pet_Achievement_CatchPetFamily25")
	else
		SetPortraitToTexture(card.Title.Icon.Texture,icon)
		card.Title.Type.Texture:SetTexCoord(0.4921875,0.796875,0.50390625,0.65625)
		rematch:FillPetTypeIcon(card.Title.Type.Texture,petType,"Interface\\PetBattles\\PetIcon-")
	end

	--[[ Front ]]

	-- filling out middle card info
	local info = card.Front.Middle

	info.Level:SetText(level or "")
	info.LevelBG:SetShown(level and canBattle)
	info.LevelLabel:SetShown(level and canBattle)
	info.Level:SetShown(level and canBattle)

	-- bottom of middle card info
	local ybottom = 6
	-- xp bar
	if canBattle and level and level<25 and xp then
		info.XP:Show()
		info.XP:SetValue(xp/maxXP*100)
		info.XP.Text:SetText(format(L["XP: %d/%d (%d%%)"],xp,maxXP,xp*100/maxXP))
		ybottom = ybottom + 16
	else
		info.XP:Hide()
	end
	-- "Hold [Alt] to flip card etc" help bit
	if not settings.HideMenuHelp and not leveling then
		info.AltFlipHelp:ClearAllPoints()
		info.AltFlipHelp:SetPoint("BOTTOMLEFT",8,ybottom)
		ybottom = ybottom + info.AltFlipHelp:GetStringHeight()+4
		info.AltFlipHelp:Show()
	else
		info.AltFlipHelp:Hide()
	end
	-- possible breeds
	info.PossibleBreeds:Hide()
	if rematch.breedSource and canBattle then
		local breeds = rematch.info
		wipe(breeds)
		if rematch.breedSource=="BattlePetBreedID" then
			if not BPBID_Arrays.BreedsPerSpecies then BPBID_Arrays.InitializeArrays() end
			local data,numBreeds = BPBID_Arrays
			if #rematch.breedNames==0 then
				rematch:GatherBreedNames()
			end
			if data.BreedsPerSpecies[speciesID] then
				for i=1,#data.BreedsPerSpecies[speciesID] do
					local breed = data.BreedsPerSpecies[speciesID][i]
					tinsert(breeds,rematch.breedNames[breed-2])
				end
			end
		elseif rematch.breedSource=="PetTracker_Breeds" then
			if PetTracker.Breeds[speciesID] then
				for _,breed in pairs(PetTracker.Breeds[speciesID]) do
					tinsert(breeds,PetTracker:GetBreedIcon(breed,0.85))
				end
			end
		elseif rematch.breedSource=="LibPetBreedInfo-1.0" then
			local lib = rematch.breedLib
			local data = lib:GetAvailableBreeds(speciesID)
			if data then
				for _,breed in pairs(data) do
					tinsert(breeds,lib:GetBreedName(breed))
				end
			end
		end
		local possibleBreeds = #breeds>0 and table.concat(breeds,rematch.breedSource=="PetTracker_Breeds" and " " or ", ") or UNKNOWN
		info.PossibleBreeds:SetText(format("%s: \124cffffffff%s",L["Possible Breeds"],possibleBreeds))
		info.PossibleBreeds:ClearAllPoints()
		info.PossibleBreeds:SetPoint("BOTTOMLEFT",8,ybottom)
		ybottom = ybottom + info.PossibleBreeds:GetStringHeight()+4
		info.PossibleBreeds:Show()
	end
	-- collected
	info.Collected:Hide()
	local collected = speciesID and C_PetJournal.GetOwnedBattlePetString(speciesID)
	if collected and canBattle then
		local collectedPets = rematch.info
		wipe(collectedPets)
		for otherPetID in roster:AllOwnedPets() do
			local otherSpeciesID,_,otherLevel = C_PetJournal.GetPetInfoByPetID(otherPetID)
			if otherSpeciesID==speciesID then
				local _,_,_,_,otherRarity = C_PetJournal.GetPetStats(otherPetID)
				local _,_,_,otherHex = GetItemQualityColor(otherRarity-1)
				if rematch.breedSource then
					tinsert(collectedPets,format("\124c%s%d %s\124r",otherHex,otherLevel,rematch:GetBreedByPetID(otherPetID)))
				else
					tinsert(collectedPets,format("\124c%s%s %d\124r",otherHex,LEVEL,otherLevel))
				end
			end
		end
		info.Collected:SetText(format("%s: %s",collected,table.concat(collectedPets,rematch.breedSource=="PetTracker_Breeds" and " " or ", ")))
		info.Collected:ClearAllPoints()
		info.Collected:SetPoint("BOTTOMLEFT",info,"BOTTOMLEFT",8,ybottom)
		ybottom = ybottom + info.Collected:GetStringHeight()+4
		info.Collected:Show()
	end

	local	model = leveling and card.Front.LevelingModel or card.Front.Model
	if leveling then
		model:SetModel("Interface\\Buttons\\talktomequestion_ltblue.m2")
		model:SetModelScale(3)
		card.Front.Model:Hide()
	elseif displayID and displayID~=0 and displayID~=model.displayID then
		model.displayID = displayID
		model:SetDisplayInfo(displayID)
		model:SetDoBlend(false)
	end
	if not leveling then
		card.Front.LevelingModel:Hide()
	end
	model:SetPoint("BOTTOMRIGHT",info,"BOTTOMRIGHT",-3,ybottom-4)
	model:Show()
	

	-- stats along left of card
	card.statIndex = 1
	card.ypos = -4
	-- wipe existing stats
	for _,button in pairs(card.statButtons) do
		button:Hide()
	end
	-- add pet's real name in first line if it has a custom name
	if customName then
		info.RealName:SetText(name)
		card.ypos = card.ypos - info.RealName:GetStringHeight() - 6
	end
	info.RealName:SetShown(customName and true)
	-- actual stats here
	if idType=="pet" then -- this is a pet player owns
		if C_PetJournal.PetIsSlotted(petID) then
			card:AddStat(L["Slotted"],"Interface\\RaidFrame\\ReadyCheck-Ready",0,1,0,1,L["Slotted"],L["This pet is loaded in one of the three battle pet slots."])
		end
		if isFavorite then
			card:AddStat(L["Favorite"],"Interface\\Common\\FavoritesIcon",0.125,0.71875,0.09375,0.6875,L["Favorite"],L["This pet is marked as a Favorite from its right-click menu."])
		end
		if rematch:IsPetLeveling(petID) then
			card:AddStat(L["Leveling"],"Interface\\AddOns\\Rematch\\Textures\\footnotes",0.25,0.5,0,0.5,L["Leveling"],L["This pet is in Rematch's leveling queue."])
		end
	end
	if canBattle and (idType=="pet" or idType=="table") then
		local healthText = health==0 and format("%s0/%d (%s)",rematch.hexRed,maxHealth,DEAD) or health<maxHealth and format("%s%d/%d (%d%%)",rematch.hexRed,health,maxHealth,health/maxHealth*100) or maxHealth
		card:AddStat(healthText,"Interface\\PetBattles\\PetBattle-StatIcons",0.5,1,0.5,1,PET_BATTLE_STAT_HEALTH,PET_BATTLE_TOOLTIP_HEALTH_MAX)
		card:AddStat(power,"Interface\\PetBattles\\PetBattle-StatIcons",0,0.5,0,0.5,PET_BATTLE_STAT_POWER,PET_BATTLE_TOOLTIP_POWER)
		card:AddStat(speed,"Interface\\PetBattles\\PetBattle-StatIcons",0,0.5,0.5,1,PET_BATTLE_STAT_SPEED,PET_BATTLE_TOOLTIP_SPEED)
		local r,g,b,hex = GetItemQualityColor(rarity-1)
		card:AddStat(format("\124c%s%s",hex,_G["BATTLE_PET_BREED_QUALITY"..(min(6,rarity))]),"Interface\\PetBattles\\PetBattle-StatIcons",0.5,1,0,0.5,PET_BATTLE_STAT_QUALITY,PET_BATTLE_TOOLTIP_RARITY)
		info.LevelBG:SetVertexColor(r,g,b)
	end

	if rematch.breedSource and (type(petID)=="string" or petBreed) then
		card:AddStat(petBreed or rematch:GetBreedByPetID(petID),"Interface\\AchievementFrame\\UI-Achievement-Progressive-Shield",0.09375,0.578125,0.140625,0.625,L["Breed"],format(L["Determines how stats are distributed.  All breed data is pulled from your installed %s%s\124r addon."],rematch.hexWhite,GetAddOnMetadata(rematch.breedSource,"Title") or rematch.breedSource))
	end

	if settings.ShowSpeciesID then
		card:AddStat(speciesID,"Interface\\WorldMap\\Gear_64Grey",0.1,0.9,0.1,0.9,L["Species ID"],L["All versions of this pet share this unique \"species\" number."])
	end

	if not leveling then
		local count = roster:IsPetInTeam(petID,true)
		if count then
			card:AddStat(format(L["%d Teams"],count),"Interface\\FriendsFrame\\UI-Toast-ChatInviteIcon",0.125,0.875,0.09375,0.84375,L["Teams"],format(L["%s Click to search for all teams that include this pet."],rematch.LMB),card.TeamsStatOnClick)
		end
	end

	if obtainable then
		card:AddStat(SEARCH,"Interface\\Minimap\\Tracking\\None",0,1,0,1,SEARCH,format(L["%s Click to search for all versions of this pet."],rematch.LMB),card.SearchStatOnClick)
	end

	-- abilities
	local teamSlot,teamKey = parent:GetID() -- if abilities from team list, get team's key
	if teamSlot>0 and teamSlot<4 then
		teamKey = parent:GetParent().key
	end
	local abilities = card.Front.Bottom.Abilities
	for i=1,6 do
		abilities[i]:Hide()
		abilities[i].Hint:Hide()
		card:DesaturateAbility(abilities[i],false)
	end
	wipe(rematch.abilityList)
	if canBattle then
		C_PetJournal.GetPetAbilityList(speciesID,rematch.abilityList,rematch.levelList)
		for i=1,6 do
			if canBattle and rematch.abilityList[i] then
				local _,abilityName,abilityIcon,_,abilityDescription,_,abilityType,noHints = C_PetBattles.GetAbilityInfoByID(rematch.abilityList[i])
				if abilityName then
					abilities[i].abilityID = rematch.abilityList[i]
					abilities[i].Name:SetText(abilityName)
					abilities[i].Icon:SetTexture(abilityIcon)
					rematch:FillPetTypeIcon(abilities[i].Type,abilityType)
					abilities[i]:Show()
					-- desaturate unused pets if this is for a team pet in the team list
					if teamKey then
						local found
						for j=1,3 do
							if RematchSaved[teamKey][teamSlot][j+1]==rematch.abilityList[i] then
								found = true
							end
						end
						if not found then
							card:DesaturateAbility(abilities[i],true)
						end
					end
					-- for battle unit frames, UpdatePetCardAbility will show strong/weak hints and return true if not found
					if parent:GetParent()==PetBattleFrame and C_PetBattles.IsPlayerNPC(2) and rematch.Battle:UpdatePetCardAbility(abilities[i],rematch.abilityList[i],abilityType,parent.petOwner,parent.petIndex) then
						card:DesaturateAbility(abilities[i],true)
					end
					-- show search hits if this is for the pet panel (and if any filters apply)
					if forPetPanel then
						if roster.searchMask and roster.searchMask~="" and abilityDescription and (abilityName:match(roster.searchMask) or abilityDescription:match(roster.searchMask)) then
							-- if name or description matches search, show its SearchHit silver border
							abilities[i].SearchHit:Show()
						elseif roster:IsFilterUsed("Similar") and roster:GetFilter("Similar",rematch.abilityList[i]) then
							-- if "Similar" filter used and this ability is among the abilities, show its SearchHit
							abilities[i].SearchHit:Show()
						elseif roster:IsFilterUsed("Strong") and not noHints then
							-- show the SearchHit if this ability is Strong Vs the filtered types
							for typeIndex in pairs(settings.Filters.Strong) do
								if rematch.hintsDefense[typeIndex][1] == abilityType then
									abilities[i].SearchHit:Show()
								end
							end
						end
					end
				end
			end
		end
	end
	card.Front.Bottom.CantBattle:SetShown(not canBattle)
	if leveling then
		card.Front.Bottom.CantBattle:SetText(L["When this team loads, your current leveling pet will go in this spot."])
	else
		card.Front.Bottom.CantBattle:SetText(BATTLE_PET_CANNOT_BATTLE)
	end

	-- finally if this is for the pet panel, see if search hit should be shown on title buttons
	if forPetPanel then
		-- show search hit on pet icon if search text is in pet's sourceText
		if roster.searchMask and ((sourceText or ""):match(roster.searchMask) or (name or ""):match(roster.searchMask) or (customName or ""):match(roster.searchMask)) then
			card.Title.Icon.SearchHit:Show()
		end
		-- show search hit on type icon if "Touch vs" or "Types" filter used
		if roster:IsFilterUsed("Tough") or roster:IsFilterUsed("Types") then
			card.Title.Type.SearchHit:Show()
		end
	end

	--[[ Back ]]

	local backHeight = 0 -- measuring height of back of card too in case lore needs more room
	if not leveling then -- leveling pets have no back of card
		-- shrink font if source text is very long (some pets like spiders list nearly every zone in the game!)
		local sourceLength = (sourceText or ""):len()
		if sourceLength>300 then
			card.Back.Source.Text:SetFontObject("GameFontHighlightSmall")
			if sourceLength>500 then -- if text is really really long, cut it short
				sourceText = sourceText:sub(1,500).."..."
			end
		else
			card.Back.Source.Text:SetFontObject("GameFontHighlight")
		end
		if not obtainable then
			sourceText = L["This is an opponent pet."]
		end

		rematch:FillPetTypeIcon(card.Back.Bottom.StrongType,rematch.hintsDefense[petType][1],"Interface\\PetBattles\\PetIcon-")
		rematch:FillPetTypeIcon(card.Back.Bottom.WeakType,rematch.hintsDefense[petType][2],"Interface\\PetBattles\\PetIcon-")

		card.Back.Source.Text:SetText(format("%s%s%s",sourceText,isTradable and "" or "\n\124cffff0000"..BATTLE_PET_NOT_TRADABLE,unique and "\n\124cffffd200"..ITEM_UNIQUE or ""))
		local sourceHeight = card.Back.Source.Text:GetStringHeight()+16
		card.Back.Source:SetHeight(sourceHeight)
		card.Back.Middle.Lore:SetText(description)
		card.Back.Bottom.TypeName:SetText(_G["BATTLE_PET_NAME_"..petType])
		rematch:FillPetTypeIcon(card.Back.Bottom.TypeIcon,petType,"Interface\\PetBattles\\PetIcon-")
		local racial = select(5,C_PetBattles.GetAbilityInfoByID(PET_BATTLE_PET_TYPE_PASSIVES[petType]))
		racial = racial:match("^.-\r\n(.-)\r"):gsub("%[percentage.-%]%%","4%%")
		card.Back.Bottom.Racial:SetText(racial)
		local bottomHeight = card.Back.Bottom.Racial:GetStringHeight()+104
		card.Back.Bottom:SetHeight(bottomHeight)
		-- total heights of back components; will stretch card height to fit this if needed
		backHeight = 78 + sourceHeight + bottomHeight + card.Back.Middle.Lore:GetStringHeight()+24
	end

	--[[ Leftovers ]]

	-- desaturate BGs for missing pets
	if idType=="pet" then
		card.Title.TitleBG:SetDesaturated(false)
		card.Front.Bottom.AbilitiesBG:SetDesaturated(false)
		card.Back.Bottom.BottomBG:SetDesaturated(false)
	else
		card.Title.TitleBG:SetDesaturated(true)
		card.Front.Bottom.AbilitiesBG:SetDesaturated(true)
		card.Back.Bottom.BottomBG:SetDesaturated(true)
	end

	-- adjust abilities for pets with only 3 abilities (unobtainable ones, but not always)
	-- example: Manos/Fatos/Hanos have 3 abilities each; Erris' Sprouts/Runts/Prince Charming have 6
	-- however some opponent pets have weird abilitylists: Kiazor the Destroyer has 1,2,5; Scuttles has 1,2,4!
	-- so both columns will show if there's any ability in the 4th, 5th or 6th slot
	local bothColumns = (rematch.abilityList[4] or rematch.abilityList[5] or rematch.abilityList[6]) and true
	for i=1,3 do
		local abilityOffset = bothColumns and 7 or 54
		local abilityWidth = bothColumns and 114 or 140
		card.Front.Bottom.Abilities[i]:SetPoint("BOTTOMLEFT",abilityOffset,(3-i)*34+7)
		card.Front.Bottom.Abilities[i]:SetWidth(abilityWidth)
	end

	-- position the card
	card:UpdateLockState()
	card:ClearAllPoints()
	if parent==FloatingBattlePetTooltip then -- if parent is the "link" pet card
		if settings.PetCardItemRefXPos then
			card:SetPoint("CENTER",UIParent,"BOTTOMLEFT",settings.PetCardItemRefXPos,settings.PetCardItemRefYPos)
		else
			card:SetPoint("CENTER",UIParent,"CENTER",0,-200)
		end
		card.PinButton:Hide()
	elseif settings.FixedPetCard and settings.PetCardXPos then -- otherwise if the card is pinned
		card:SetPoint("CENTER",UIParent,"BOTTOMLEFT",settings.PetCardXPos,settings.PetCardYPos)
		card.PinButton:Show()
	elseif parent:GetParent()==PetBattleFrame then -- otherwise if this card is for a battle UI unit
		rematch.Battle:AnchorPetCardToBattleUnit(parent)
		card.PinButton:Hide()
	else -- for all others do a smart anchor to the parent
		rematch:SmartAnchor(card,parent,nil,22)
		card.PinButton:Hide()
	end
	-- adjust card height to fit max of front height, back height or 416(standard size)
	card:SetHeight(max(190+abs(card.ypos)+ybottom,backHeight,416))

	-- save parent and petID to recreate card if needed
	card.parent = parent
	card.petID = petID

	-- show the card
	card:FlipCardIfAltDown()
	rematch:AdjustScale(card)
	card:Show()
end

-- called at end of ShowPetCard and in the OnEvent for MODIFIER_STATE_CHANGED
function card:FlipCardIfAltDown()
	local altDown = IsAltKeyDown() and card.petID~=0 -- don't flip leveling pets
	card.Front:SetShown(not altDown)
	card.Back:SetShown(altDown)
end

-- fills out a stat on the card and adjusts card.ypos for next stat
function card:AddStat(text,icon,left,right,top,bottom,title,body,func)
	if not card.statButtons[card.statIndex] then
		card.statButtons[card.statIndex] = CreateFrame("Button",nil,card.Front.Middle,"RematchPetCardStatTemplate")
	end
	local button = card.statButtons[card.statIndex]
	if type(func)=="function" then
		button.Text:SetText("")
		button.ButtonText:SetText(text)
		button:SetScript("OnClick",func)
	else
		button.Text:SetText(text)
		button.ButtonText:SetText("")
		button:SetScript("OnClick",nil)
	end
	button.Text:SetTextColor(1,1,1)
	button.Icon:SetTexture(icon)
	button.Icon:SetTexCoord(left,right,top,bottom)
	button.tooltipTitle = title
	button.tooltipBody = body
	button:SetPoint("TOPLEFT",8,card.ypos)
	button:Show()
	card.ypos = card.ypos - 20
	card.statIndex = card.statIndex + 1
	return card.statIndex-1
end

-- maybe should be true for OnLeaves
function rematch:HidePetCard(maybe)
	if not settings.FastPetCard then
		rematch:StopTimer("PetCard")
	end
	if (maybe and card.locked) or card.keepOnScreen then return end
	card:Hide()
end

function card:OnShow()
	card:RegisterEvent("MODIFIER_STATE_CHANGED")
end

function card:OnHide()
	card:UnregisterEvent("MODIFIER_STATE_CHANGED")
	card.locked = nil
	card.petID = nil
	rematch.BottomPanel.SummonButton:Disable()
	card:UpdateHighlights()
end

function card:CurrentPetIDIsDifferent(petID)
	if type(petID)~="table" then -- if passed/card petIDs are not a table
		return petID~=card.petID -- simply return true if they inequal
	elseif type(card.petID)~="table" then -- if card petID is not a table
		return true -- then it's automatically different (since passed is a table)
	else -- both passed and card petID are tables, compare its values
		for k,v in pairs(card.petID) do
			if petID[k]~=v then
				return true
			end
		end
		return false
	end
end

function rematch:LockPetCard(parent,petID)
	if card:CurrentPetIDIsDifferent(petID) then
		if settings.ClickPetCard or not card:IsVisible() then
			card.locked = true
		end
		rematch:ShowPetCard(parent,petID,true)
	elseif petID then
		card.locked = not card.locked
		card:UpdateLockState()
		if settings.ClickPetCard then
			rematch:HidePetCard()
		end
	end
	rematch.BottomPanel:Update()
	card:UpdateHighlights()
end

-- this makes the border/titlebar/lock appear or disappear (alpha)
function card:UpdateLockState()
	local locked = card.locked
	card:SetAlpha(card.locked and 1 or 0)
	card.Title.Icon:EnableMouse(card.locked)
	card.Title.Type:EnableMouse(card.locked)
	card:EnableMouse(card.locked)
	card.CloseButton:EnableMouse(card.locked)
	card.PinButton:EnableMouse(card.locked)
	card.Front.Middle.PossibleBreedsCapture:EnableMouse(card.locked)
	for _,button in pairs(card.statButtons) do
		button:EnableMouse(locked)
	end
	for _,button in pairs(card.Front.Bottom.Abilities) do
		button:EnableMouse(locked)
	end
	card.PinButton:SetShown(RematchSettings.PetCardXPos and settings.FixedPetCard and true)
end

function card:OnMouseDown(button)
	card:StartMoving()
	if card.parent==FloatingBattlePetTooltip then
		settings.PetCardItemRefXPos, settings.PetCardItemRefYPos = card:GetCenter()
	else
		settings.PetCardXPos, settings.PetCardYPos = card:GetCenter()
	end
	card:UpdateLockState()
end

function card:OnMouseUp(button)
	card:StopMovingOrSizing()
	if card.parent==FloatingBattlePetTooltip then
		settings.PetCardItemRefXPos, settings.PetCardItemRefYPos = card:GetCenter()
	else
		settings.PetCardXPos, settings.PetCardYPos = card:GetCenter()
	end
	card:UpdateLockState()
end

function card:PinOnClick()
	settings.PetCardXPos = nil
	settings.PetCardYPos = nil
	rematch:ShowPetCard(card.parent,card.petID,true)
	card:UpdateLockState()
end

function card:OnKeyDown(key)
	if key==GetBindingKey("TOGGLEGAMEMENU") and card.locked then
		rematch:HidePetCard()
		self:SetPropagateKeyboardInput(false)
	else
		self:SetPropagateKeyboardInput(true)
	end
end

function card:TitleButtonOnEnter()
	if card.petID~=0 then
		card.Front:Hide()
		card.Back:Show()
	end
end

function card:TitleButtonOnLeave()
	if card.petID~=0 then
		card.Front:Show()
		card.Back:Hide()
	end
end

function card:PossibleBreedsOnEnter()
	local middle = card.Front.Middle
	if not middle.PossibleBreeds:IsVisible() then
		return
	end
	local btable = middle.BreedTable
	middle.PossibleBreedsHighlight:Show()
	btable:SetFrameLevel(self:GetFrameLevel()+5)
	btable.Footnote:SetText(format(L["All breed data pulled from %s%s\124r."],rematch.hexWhite,GetAddOnMetadata(rematch.breedSource,"Title") or rematch.breedSource))
	btable.Title:SetText(rematch.breedSource=="PetTracker_Breeds" and L["Possible Breeds"] or L["Stats At Level 25 \124cff0070ddRare"])

	btable.Rows = btable.Rows or {}
	btable.Highlight:Hide()
	for _,row in ipairs(btable.Rows) do
		row:Hide() -- clean up all rows
	end

	local speciesID, owned
	if type(card.petID)=="string" then
		speciesID = C_PetJournal.GetPetInfoByPetID(card.petID)
		owned = true
	elseif type(card.petID)=="table" then
		speciesID = card.petID.speciesID
	else
		speciesID = card.petID
	end

	card:FillBreedTable(speciesID,rematch.info) -- gather possible breed data into rematch.info

	local petBreed = type(card.petID)=="table" and card.petID.breed or rematch:GetBreedByPetID(card.petID)

	for index,info in ipairs(rematch.info) do
		if not btable.Rows[index] then
			btable.Rows[index] = CreateFrame("Frame",nil,btable,"RematchBreedTableTemplate")
			btable.Rows[index]:SetPoint("TOPLEFT",8,-50-(index-1)*16)
		end
		local row = btable.Rows[index]
		row.Breed:SetText(info[1])
		row.Health:SetText(info[2])
		row.Power:SetText(info[3])
		row.Speed:SetText(info[4])
		if info[1]==petBreed then
			btable.Highlight:SetPoint("TOPLEFT",row,2,0)
			btable.Highlight:SetPoint("BOTTOMRIGHT",row,-2,-1)
			btable.Highlight:Show()
		end
		row:Show()
	end

	local numBreeds = #rematch.info
	if numBreeds==0 then
		btable.NoBreeds:SetText(L["No known breeds :("])
		btable.NoBreeds:Show()
		btable:SetHeight(32+87)
	else
		btable.NoBreeds:Hide()
		btable:SetHeight(numBreeds*16+87)
	end
	btable:Show()
end

function card:PossibleBreedsOnLeave()
	card.Front.Middle.PossibleBreedsHighlight:Hide()
	card.Front.Middle.BreedTable:Hide()
end

-- takes a table (breeds) and fills it with all known breeds and their stats as a 25 rare: { breedName, health, power, speed }
function card:FillBreedTable(speciesID,breeds)
	wipe(breeds)
	if rematch.breedSource=="BattlePetBreedID" then
		if not BPBID_Arrays.BreedsPerSpecies then
			BPBID_Arrays.InitializeArrays()
		end
		local data,numBreeds = BPBID_Arrays
		if data.BreedsPerSpecies[speciesID] then
			for i=1,#data.BreedsPerSpecies[speciesID] do
				local breed = data.BreedsPerSpecies[speciesID][i]
				local breedText = rematch.breedNames[breed-2] -- rematch:GetBPBIDBreedName(breed)
				local health = ceil((data.BasePetStats[speciesID][1] + data.BreedStats[breed][1]) * 25 * ((data.RealRarityValues[4] - 0.5) * 2 + 1) * 5 + 100 - 0.5)
				local power = ceil((data.BasePetStats[speciesID][2] + data.BreedStats[breed][2]) * 25 * ((data.RealRarityValues[4] - 0.5) * 2 + 1) - 0.5)
				local speed = ceil((data.BasePetStats[speciesID][3] + data.BreedStats[breed][3]) * 25 * ((data.RealRarityValues[4] - 0.5) * 2 + 1) - 0.5)
				tinsert(breeds,{breedText,health,power,speed})
			end
		end
	elseif rematch.breedSource=="LibPetBreedInfo-1.0" then
		local lib = rematch.breedLib
		local data = lib:GetAvailableBreeds(speciesID)
		if data then
			for _,breed in pairs(data) do
				tinsert(breeds,{lib:GetBreedName(breed),lib:GetPetPredictedStats(speciesID,breed,4,25)})
			end
		end
	elseif rematch.breedSource=="PetTracker_Breeds" then
		if PetTracker.Breeds[speciesID] then
			for _,breed in pairs(PetTracker.Breeds[speciesID]) do
				local health, power, speed = unpack(PetTracker.BreedStats[breed])
				health = health*50
				power = power*50
				speed = speed*50
				tinsert(breeds,{(PetTracker:GetBreedIcon(breed,.95)),health>0 and format("%d%%",health) or "-    ",power>0 and format("%d%%",power) or "-    ",speed>0 and format("%d%%",speed) or "-    "})
			end
		end
	end
end

-- after much trial and error, going for a brute force method of locking highlights for
-- pets that have the card locked: going through the PetPanel, QueuePanel, LoadoutPanel and
-- MiniPanel and locking/unlocking highlights in one pass
function card:UpdateHighlights()

	rematch.MiniPanel:UpdateHighlights()
	rematch.LoadoutPanel:UpdateHighlights()
	rematch:UpdatePetListHighlights(rematch.PetPanel.List.ScrollFrame)
	rematch:UpdatePetListHighlights(rematch.QueuePanel.List.ScrollFrame)

end

-- locks/unlocks highlights for petpanel and queuepanel list buttons
function rematch:SetPetListHighlight(button,lock)
	button.lockHighlight = lock or nil
	if lock then
		button.Backplate:SetColorTexture(0.25,0.5,0.75)
	elseif GetMouseFocus()~=button then
		button.Backplate:SetColorTexture(0.15,0.15,0.15)
	end
end

-- handles both left-click (linking ability) and right-click (find ability menu) on the pet card
function card:AbilityOnClick(button)
	if button=="RightButton" then
		rematch:SetMenuSubject(self.abilityID)
		rematch:ShowMenu("FindAbility","cursor",nil,nil,nil,nil,true)
	else
		rematch.ChatLinkAbility(self,button)
	end
end

function card:DesaturateAbility(button,enable)
	button.Icon:SetDesaturated(enable)
	button.IconBorder:SetDesaturated(enable)
	button.Type:SetDesaturated(enable)
	if enable then
		button.Name:SetTextColor(0.35,0.35,0.35)
		button.Icon:SetVertexColor(0.35,0.35,0.35)
		button.IconBorder:SetVertexColor(0.35,0.35,0.35)
		button:SetAlpha(0.75)
	else
		button.Name:SetTextColor(1,0.82,0.5)
		button.Icon:SetVertexColor(1,1,1)
		button.IconBorder:SetVertexColor(1,1,1)
		button:SetAlpha(1)
	end
end

-- from the "Search" stat on the pet card
function card:SearchStatOnClick()
	local petID = card.petID
	local idType = rematch:GetIDType(petID)
	local speciesID
	if idType=="pet" then
		speciesID = C_PetJournal.GetPetInfoByPetID(petID)
	elseif idType=="species" then
		speciesID = petID
	elseif idType=="table" then
		speciesID = petID.speciesID
	end
	if speciesID then
		card.keepOnScreen = true -- may need to reconfigure UI, flag will prevent hiding pet card during HideWidgets
		rematch:AutoShow()
		rematch:ShowPets()
		rematch:SearchForSpecies(speciesID)
		card.keepOnScreen = nil
	end
end

-- from the "Teams" stat on the pet card
function card:TeamsStatOnClick()
	local petID = card.petID
	local idType = rematch:GetIDType(petID)
	if idType=="pet" then
		rematch.TeamPanel:SetTeamSearch(petID)
	elseif idType=="species" then
		rematch.TeamPanel:SetTeamSearch(rematch:GetPetName(petID))
	else
		return
	end
	card.keepOnScreen = true
	rematch:AutoShow()
	rematch:ShowTeam()
	card.keepOnScreen = nil
end
