// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "ItemBase.h"
#include "BaseSkillObject.h"
#include "CharacterBase.h"

// Sets default values
AItemBase::AItemBase()
{
	// Create a mesh subcomponent without collision.
	Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
	RootComponent = Mesh;
	Mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}

void AItemBase::CreateItemsFromSkill(UWorld* world, class UBaseSkillObject* skillObject, class ACharacterBase* character)
{

	// Check if passed arguments are valid.
	if (world && skillObject && character)
	{
		for (size_t i = 0; i < skillObject->visibleItems.itemsToEquip.Num(); i++)
		{
			if (!skillObject->visibleItems.itemsToEquip[i].mesh)
			{
				TERROR("Skill item does not have a mesh attached to it!");
				continue;
			}
			
			// Get the Skeletal Mesh of the character.
			USkeletalMeshComponent* charMesh = character->GetMesh();

			// Check if the socket has already been taken by another item.
			bool hasBeenTaken = false;
			for (auto SceneComp : charMesh->AttachChildren)
			{
				AItemBase* item = Cast<AItemBase>(SceneComp->GetOwner());
				if (item)
				{
					if (item->type == skillObject->visibleItems.itemsToEquip[i].type)
					{
						hasBeenTaken = true;
						break;
					}
				}
			}
			if (!hasBeenTaken)
			{
				// Spawn a new item.
				AItemBase* createdItem = Cast<AItemBase>(world->SpawnActor(StaticClass()));
				// Set the item with the correct settings and mesh.
				createdItem->type = skillObject->visibleItems.itemsToEquip[i].type;
				createdItem->SetMesh(skillObject->visibleItems.itemsToEquip[i].mesh);
				createdItem->skillObject = skillObject;
				createdItem->AttachItemToCharacter(character);
			}
		}
		return;
	}
	TERROR("Either world (" + world + "), skillObject (" + skillObject + ") or character (" + character + ") passed to AItemBase::CreateItemFromSkill was a nullptr.");
}

AItemBase* AItemBase::CheckSlotOccupied(EItemTypeEnum slotType, class ACharacterBase* character)
{

	// Check if passed arguments are valid.
	if(character)
	{
		UWorld* world = character->GetWorld();

		// Get the Skeletal Mesh of the character.
		USkeletalMeshComponent* charMesh = character->GetMesh();
		// Check if the socket has already been taken by another item.
		bool hasBeenTaken = false;
		for(auto SceneComp : charMesh->AttachChildren)
		{
			AItemBase* item = Cast<AItemBase>(SceneComp->GetOwner());
			if (item)
			{
				if(item->type == slotType)
					return item;
			}
		}
	}
	return nullptr;
}

void AItemBase::Destroyed()
{
	ACharacterBase* attachedParent = Cast<ACharacterBase>(this->GetAttachParentActor());
	if(IsValid(attachedParent))
	{
		attachedParent->m_OnItemRemoved(this);
	}
	Super::Destroyed();
}

void AItemBase::SetMesh(USkeletalMesh* newMesh)
{
	Mesh->SetSkeletalMesh(newMesh);
}

bool AItemBase::AttachItemToCharacter(class ACharacterBase* networkCharacter)
{
	// Variable used to retrieve names of the EItemTypeEnum values.
	const static UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, TEXT("EItemTypeEnum"), true);
	// Retrieve the name of the type the item was assigned to. This is to attach the item to a socket.
	FName socketName = FName(*EnumPtr->GetEnumName((int32)type));
	// Get the Skeletal Mesh of the character.
	USkeletalMeshComponent* charMesh = networkCharacter->GetMesh();

	// Check if the socket actually exists.
	if(!charMesh->DoesSocketExist(socketName))
	{
		return false;
	}

	// Attach the item to the socket.
	RootComponent->AttachTo(charMesh, NAME_None, EAttachLocation::SnapToTargetIncludingScale);
	Mesh->SetMasterPoseComponent(charMesh);
	// Notify character
	networkCharacter->m_OnItemAdded(this);
	return true;
}
