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


#include "CharacterPartsDataAsset.h"

namespace
{
	/**
	 * Rendue par GetParts quand la categorie n'existe pas, pour que l'appelant
	 * n'ait jamais a tester un pointeur.
	 *
	 * Le nom porte le prefixe du fichier : le build unity concatene les .cpp du
	 * module et un namespace anonyme n'isole plus rien. Une constante nommee
	 * "EmptyParts" tout court finirait par entrer en collision -- invisible en
	 * build incremental, elle ne sortirait qu'au premier -Rebuild.
	 */
	const TArray<FCharacterPartEntry> CharacterPartsEmptyList;

	/** Borne un index de piece OBLIGATOIRE : hors bornes, on retombe sur 0. */
	void ClampRequiredIndex(uint8& Index, int32 Count)
	{
		if (Count <= 0 || Index >= Count)
		{
			Index = 0;
		}
	}

	/** Borne un index de piece FACULTATIVE : hors bornes, on retire la piece. */
	void ClampOptionalIndex(uint8& Index, int32 Count)
	{
		if (Index == FCharacterAppearance::NoPart)
		{
			return;
		}

		if (Count <= 0 || Index >= Count)
		{
			Index = FCharacterAppearance::NoPart;
		}
	}
}

const FCharacterBodySet* UCharacterPartsDataAsset::GetBodySet(ECharacterBodyType BodyType) const
{
	const int32 Index = static_cast<int32>(BodyType);
	return BodySets.IsValidIndex(Index) ? &BodySets[Index] : nullptr;
}

const TArray<FCharacterPartEntry>& UCharacterPartsDataAsset::GetParts(ECharacterBodyType BodyType, ECharacterPartCategory Category) const
{
	const FCharacterBodySet* Set = GetBodySet(BodyType);
	if (!Set)
	{
		return CharacterPartsEmptyList;
	}

	switch (Category)
	{
	case ECharacterPartCategory::Head:      return Set->Heads;
	case ECharacterPartCategory::Hair:      return Set->Hairstyles;
	case ECharacterPartCategory::Eyebrows:  return Set->Eyebrows;
	case ECharacterPartCategory::Beard:     return Set->Beards;
	case ECharacterPartCategory::Mustache:  return Set->Mustaches;
	default:                                return CharacterPartsEmptyList;
	}
}

int32 UCharacterPartsDataAsset::GetPartCount(ECharacterBodyType BodyType, ECharacterPartCategory Category) const
{
	return GetParts(BodyType, Category).Num();
}

void UCharacterPartsDataAsset::Sanitize(FCharacterAppearance& InOut) const
{
	// La silhouette d'abord : tout le reste est indexe DANS son jeu de pieces,
	// donc la borner apres ne servirait a rien.
	if (static_cast<uint8>(InOut.BodyType) >= BodySets.Num())
	{
		InOut.BodyType = ECharacterBodyType::BodyA;
	}

	ClampRequiredIndex(InOut.HeadIndex, GetPartCount(InOut.BodyType, ECharacterPartCategory::Head));
	ClampRequiredIndex(InOut.EyebrowsIndex, GetPartCount(InOut.BodyType, ECharacterPartCategory::Eyebrows));

	// Cheveux, barbe et moustache sont facultatifs : un crane rase est un choix,
	// pas une erreur.
	ClampOptionalIndex(InOut.HairIndex, GetPartCount(InOut.BodyType, ECharacterPartCategory::Hair));
	ClampOptionalIndex(InOut.BeardIndex, GetPartCount(InOut.BodyType, ECharacterPartCategory::Beard));
	ClampOptionalIndex(InOut.MustacheIndex, GetPartCount(InOut.BodyType, ECharacterPartCategory::Mustache));

	ClampRequiredIndex(InOut.EyesIndex, EyeMaterials.Num());

	ClampRequiredIndex(InOut.SkinColorIndex, SkinColors.Num());
	ClampRequiredIndex(InOut.HairColorIndex, HairColors.Num());
	ClampRequiredIndex(InOut.EyeColorIndex, EyeColors.Num());
	ClampRequiredIndex(InOut.UnderwearColorIndex, UnderwearColors.Num());
}
