//
// AVP_Multiplayer_InverseSurvivorRank.cpp
//
// Created by JG - 30 June 2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Multiplayer/AVP_Multiplayer_InverseSurvivorRank.h"

// Project 
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"
#include "Multiplayer/AVP_Multiplayer_GameRules.h"

// Globals
Asura_LinkList<Asura_Guid>			AVP_Multiplayer_InverseSurvivorRank::s_xPlayersDeathOrder; 

void AVP_Multiplayer_InverseSurvivorRank::Reset()
{
	s_xPlayersDeathOrder.Clear();
}

void AVP_Multiplayer_InverseSurvivorRank::Create()
{
	Reset(); 
}

void AVP_Multiplayer_InverseSurvivorRank::Destroy()
{
	Reset(); 
}

int AVP_Multiplayer_InverseSurvivorRank::FindPlayerInverseRank( Asura_Guid uPlayerGuid )
{
	Asura_Assert(false, "FindPlayerInverseRank not implemented yet!");
	int iPlayerPosition = -1;
	return iPlayerPosition; 
}

void AVP_Multiplayer_InverseSurvivorRank::AddPlayerToInverseRank( Asura_Guid uPlayerGuid )
{
	// Survivor player rank should only live in the server
	if ( !Asura_Network::IsServer() )
	{
		Asura_Assert( false, "Trying to add player to inverse Survivor rank but this is not the host, invalid" ); 
		return; 
	}

	s_xPlayersDeathOrder.Push_Back(uPlayerGuid);
}

void AVP_Multiplayer_InverseSurvivorRank::UpdatePlayersScoreOnRoundEnd()
{
	// Survivor player rank should only live in the server
	if ( !Asura_Network::IsServer() )
	{
		Asura_Assert( false, "Trying to add player to inverse Survivor rank but this is not the host, invalid" ); 
		return; 
	}

	// Survivor players score based on how long they survived

	// Any survivors?
	const Asura_Hashed_List<AVP_ServerEntity_PlayerInfo>* pxPlayerInfoList = AVP_ServerEntity_PlayerInfo::GetList(); 
	
	u_int uFinalNumberOfPlayers = pxPlayerInfoList->GetNumEntries(); 
#ifdef ASURA_ASSERT
	u_int uPredictedNumberOfHunters = s_xPlayersDeathOrder.Size() + 1; // Every death player became a hunter + the initial hunter
	u_int uPredictedNumberOfSurvivors = uFinalNumberOfPlayers - uPredictedNumberOfHunters; 
#endif
	Asura_Hashed_List_It<AVP_ServerEntity_PlayerInfo> xPlayerInfoListIt( pxPlayerInfoList );
	
	u_int uRealNumberOfHunters = 0;
	u_int uRealNumberOfSurvivors = 0;
	u_int uCurrentRank = 1;				// All survivors score as winners

	while (!xPlayerInfoListIt.Done())
	{
		AVP_ServerEntity_PlayerInfo* pxCurrentPlayerInfo = xPlayerInfoListIt.GetCurrent();
		if (pxCurrentPlayerInfo->GetMultiplayerRole() == AVP_Settings::AVP_ROLE_PREY)
		{
			// Max score for surviving
			AVP_Multiplayer_PlayerScore& xCurrentPlayerScore = pxCurrentPlayerInfo->GetPlayerScore(); 
			int iCurrentPlayerScore = 2 * uFinalNumberOfPlayers - (2 * (uCurrentRank - 1));
			xCurrentPlayerScore.SetIndividualScore( xCurrentPlayerScore.GetIndividualScore() + iCurrentPlayerScore ); 

			++uRealNumberOfSurvivors;
		}
		else if (pxCurrentPlayerInfo->GetMultiplayerRole() == AVP_Settings::AVP_ROLE_HUNTER)
		{
			// Another hunter, count it
			++uRealNumberOfHunters; 
		}
		else
		{
			// Shouldn't get here
			Asura_Assert( false, "Unexpected role found during Survivor score calculations, please report as multiplayer bug" ); 
		}
	
		xPlayerInfoListIt.Next();
	}

	// Sanity checks
	Asura_Assert( uRealNumberOfHunters <= uPredictedNumberOfHunters, "Too many hunters at the end of the round");
	Asura_Assert( uRealNumberOfHunters >= uPredictedNumberOfHunters, "Some hunters have vanished, did players quit / disconnected from the game?");
	Asura_Assert( uRealNumberOfSurvivors == uPredictedNumberOfSurvivors, "Some survivors have vanished, please report as multiplayer bug");

	// Skip all players who have actually scored as survivors
	uCurrentRank += uRealNumberOfSurvivors; 

	while (uCurrentRank < 5)
	{
		// Next player, last to be killed last round
		Asura_ListElt<Asura_Guid>* pxLastPlayerKilledGuid = s_xPlayersDeathOrder.Back();

		if (pxLastPlayerKilledGuid)
		{
			AVP_ServerEntity_PlayerInfo* pxCurrentPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity(pxLastPlayerKilledGuid->Data());
			
			if (pxCurrentPlayerInfo)
			{
				AVP_Multiplayer_PlayerScore& xCurrentPlayerScore = pxCurrentPlayerInfo->GetPlayerScore(); 
				int iCurrentPlayerScore = 2 * uFinalNumberOfPlayers - (2 * (uCurrentRank - 1));
				++uCurrentRank;
				xCurrentPlayerScore.SetIndividualScore( xCurrentPlayerScore.GetIndividualScore() + iCurrentPlayerScore ); 
			}
			else
			{
				// This player didn't finish the round, it will be ignored for score calculations
			}

			s_xPlayersDeathOrder.PopBack();
			
		}
		else
		{
			// Very few players finished the game or all survived. Either way is fine
			break;
		}
	}

	// Reset the ranks
	Reset(); 
}
