// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "MenuGameMode.h"
#include "MenuController.h"
#include "DefaultGameInstance.h"
#include "MapData.h"
#include "GameStateBase.h"
#include "PlayerStateBase.h"
#include "PlayerControllerBase.h"

AMenuGameMode::AMenuGameMode()
{
	static ConstructorHelpers::FClassFinder<APawn> MenuPawnCF(TEXT("/Game/Assets/Blueprints/BP_MenuPawn"));

	PlayerControllerClass = AMenuController::StaticClass();
	DefaultPawnClass = MenuPawnCF.Class;
	GameStateClass = AGameStateBase::StaticClass();
	PlayerStateClass = APlayerStateBase::StaticClass();

	bUseSeamlessTravel = true;
}
void AMenuGameMode::PreInitializeComponents()
{
	Super::PreInitializeComponents();
	GWPRINT(L"Menu arguments = " + OptionsString);

	AGameStateBase* gameState = GetGameState<AGameStateBase>();
	check(gameState);

	// Set initial map
	UWorld* world = GetWorld();
	if(world)
	{
		UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());
		if(inst->maps.Num() > 0)
		{
			m_mapData = inst->maps[0];
			m_mapPath = gameState->mapPath = m_mapData->pathToAsset;
			GPRINT("Setting default map to \"" + m_mapData->friendlyName + "\" [" + m_mapPath + "]");
			gameState->m_LoadActiveMapInfo();
		}
	}
}
void AMenuGameMode::BeginPlay()
{
	Super::BeginPlay();
	UWorld* world = GetWorld();
	m_lobbyState = world->SpawnActor<ALobbyState>(ALobbyState::StaticClass());
}

void AMenuGameMode::GetSeamlessTravelActorList(bool bToEntry, TArray<AActor*>& ActorList)
{
	Super::GetSeamlessTravelActorList(bToEntry, ActorList);
	ActorList.Add(m_lobbyState);
}

APlayerController* AMenuGameMode::Login(class UPlayer* NewPlayer, ENetRole InRemoteRole, const FString& Portal, const FString& Options, const TSharedPtr<const FUniqueNetId>& UniqueId, FString& ErrorMessage)
{
	// Aquire the player controller by calling the super function
	APlayerController* player = Super::Login(NewPlayer, InRemoteRole, Portal, Options, UniqueId, ErrorMessage);
	APlayerControllerBase* pc = Cast<APlayerControllerBase>(player);

	// Update persona
	APlayerStateBase* state = Cast<APlayerStateBase>(pc->PlayerState);
	FString name = "<unknown>";
	if(state)
	{
		state->UpdatePersona();
		name = state->nickname;
	}

	GWARNING("Player " + name + " logged in [options=" + Options + "][portal=" + Portal + "]");
	return player;
}
FString AMenuGameMode::InitNewPlayer(class APlayerController* NewPlayerController, const TSharedPtr<const FUniqueNetId>& UniqueId, const FString& Options, const FString& Portal /* = TEXT("") */)
{
	FString r = Super::InitNewPlayer(NewPlayerController, UniqueId, Options, Portal);
	return r;
}

void AMenuGameMode::Logout(AController* existing)
{
	// Get name of disconnected player
	APlayerStateBase* state = Cast<APlayerStateBase>(existing->PlayerState);
	FString name = "<unknown>";
	if(state)
		name = state->nickname;
	GWARNING("Player " + name + " left the game");

	// Deregister the player
	APlayerControllerBase* pc = Cast<APlayerControllerBase>(existing);
	Cast<AGameStateBase>(GameState)->DeregisterPlayer(pc);

	Super::Logout(existing);
}

void AMenuGameMode::PostLogin(APlayerController* NewPlayer)
{
	Super::PostLogin(NewPlayer);
	AGameStateBase* gs = GetGameState<AGameStateBase>();
	APlayerControllerBase* pc = Cast<APlayerControllerBase>(NewPlayer);

	// Register the player
	Cast<AGameStateBase>(GameState)->RegisterPlayer(pc);
}

void AMenuGameMode::SetMap(FString mapPath)
{
	m_mapPath = mapPath;
	Cast<AGameStateBase>(GameState)->mapPath = m_mapPath;
}
bool AMenuGameMode::StartGame()
{
	UWorld* world = GetWorld();
	if(!world)
	{
		GERROR("No world, cant start game");
		return false;
	}

	UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());
	m_mapData = inst->GetMapData(m_mapPath);
	if(!m_mapData)
	{
		GERROR("Can't start game, no map data found for map [" + m_mapPath + "]");
		return false;
	}

	// Inject all the players into the lobby state
	AGameStateBase* state = Cast<AGameStateBase>(GameState);
	m_lobbyState->players.SetNum(0);
	for(APlayerState* ps : state->PlayerArray)
	{
		APlayerStateBase* psb = Cast<APlayerStateBase>(ps);
		if(psb)
		{
			FLobbyStatePlayer lsp;
			lsp.netID = psb->UniqueId.GetUniqueNetId();
			lsp.team = psb->GetTeam();
			m_lobbyState->players.Add(lsp);
		}
	}

	GWARNING("Performing server travel to " + m_mapPath);
	world->ServerTravel(m_mapPath, true);
	return true;
}

void AMenuGameMode::AssignMapData(class UMapData* mapData)
{
	if(!mapData)
	{
		GERROR("Invalid map passed to AssignMapData");
		return;
	}
	AGameStateBase* gameState = GetGameState<AGameStateBase>();
	gameState->mapPath = m_mapPath = mapData->pathToAsset;
	gameState->m_LoadActiveMapInfo();
}
