// Fill out your copyright notice in the Description page of Project Settings.


#include "TangibleManager.h"
#include "Tangible.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetRegistry/ARFilter.h"

void UlxTangibleManager::Initialize(FSubsystemCollectionBase& Collection) {
	Super::Initialize(Collection);
	PossessedTangible = nullptr;
}

UlxTangible* UlxTangibleManager::GetTangible(int64 id) const {
	UlxTangible*const* p = IdToTangible.Find(id);
	if (p == nullptr) {
		return nullptr;
	} else {
		return *p;
	}
}

#pragma optimize("", off)
UlxTangible* UlxTangibleManager::MakeTangible(int64 id) {
	check(id > 0);
	UlxTangible*& t = IdToTangible.FindOrAdd(id);
	if (t == nullptr) {
		t = NewObject<UlxTangible>(this);
		t->Init(this, id);
	}
	return t;
}

void UlxTangibleManager::DeleteTangible(int64 id) {
	// IMPLEMENT ME
}

UlxTangibleManager::TanArray UlxTangibleManager::GetAllTangibles() const {
	TanArray result;
	result.SetNum(IdToTangible.Num());
	int next = 0;
	for (auto& pair : IdToTangible) {
		result[next++] = pair.Value;
	}
	return result;
}

#pragma optimize("", off)
void UlxTangibleManager::UpdateNearAccordingToLuprex(IdView near) {
	// Clear all the 'NearAccordingToLuprex' flags.
	for (const auto& pair : IdToTangible) {
		pair.Value->NearAccordingToLuprex = false;
	}
	// For every ID on the list, create it if it doesn't exist,
	// mark it, and return it.
	for (int64 id : near) {
		UlxTangible* tan = MakeTangible(id);
		tan->NearAccordingToLuprex = true;
	}
}

#pragma optimize("", off)
void UlxTangibleManager::RecalcNearAccordingToUnreal(int64 player, double radius) {
	UlxTangible *p = GetTangible(player);
	check (p != nullptr);
	FVector playerpos = p->CurrentActor->GetActorLocation();
	FName playerplane = p->Plane;
	double radiussq = radius * radius;
	for (const auto& pair : IdToTangible) {
		UlxTangible *tan = pair.Value;
		if (tan->Plane != playerplane) {
			tan->NearAccordingToUnreal = false;
		} else {
			FVector pos = tan->GetLocation();
			double distsq = FVector::DistSquared(pos, playerpos);
			tan->NearAccordingToUnreal = (distsq <= radiussq);
		}
	}
}

void UlxTangibleManager::DeleteFarawayTangibles() {
	// Make a list of tangibles that need to be deleted.
	TanArray faraway;
	for (const auto& pair : IdToTangible) {
		UlxTangible *tan = pair.Value;
		if (!(tan->NearAccordingToLuprex || tan->NearAccordingToUnreal)) {
			faraway.Add(tan);
		}
	}

	for (UlxTangible *tan : faraway) {
		IdToTangible.Remove(tan->TangibleId);
		tan->Destroy(); // Remove the actor from the scene.
	}
}

UlxTangibleManager::IdArray UlxTangibleManager::GetIds(const TanArray &arr) {
	IdArray result;
	result.SetNum(arr.Num());
	for (int i = 0; i < arr.Num(); i++) {
		result[i] = arr[i]->TangibleId;
	}
	return result;
}

