//
// Asura_Chunk_HierarchyBodyPart.cpp
//
// Created by Richard Rice - 9/10/02
// 
// Copyright (C) 2002 Rebellion, All Rights Reserved.
//


#include "Core/Asura.h"

#include "ChunkSystem/Asura_Chunk_HierarchyBodyPart.h"

#include "Animation/Asura_Hierarchy_BodyPart_System.h"
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Core/Asura_NameTree.h"
#include "Core/Memory/Asura_ResourceAllocator.h"
#include "Debugging/Asura_Assert.h"
#include "FileAccess/Asura_FileAccess.h"


#define ASURA_CHUNK_HIERARCHYBODYPART_VERSION 0
#define ASURA_CHUNK_DEATHANIMFILENAMES_VERSION 0

//////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------------**
** Asura_Chunk_DeathAnimFilenames **
**--------------------------------*/
#ifdef ASURA_TOOLS
void Asura_Chunk_DeathAnimFilenames::Create(Asura_SaveBlock& xSaveBlock)
{
	const Asura_NameTree* pxTree = Asura_Hierarchy_BodyPart_System::s_pxAnimationTree;
	Asura_Assert(pxTree,"");

	int iNumberOfAnims = pxTree->GetNumberOfNodes();
	if(!iNumberOfAnims) return;

    int iChunkSize = sizeof(Asura_Chunk_DeathAnimFilenames);
		
	iChunkSize += pxTree->GetSizeOfNamesInIntChunks();
	
	Asura_Chunk_DeathAnimFilenames* pxChunk = (Asura_Chunk_DeathAnimFilenames*)xSaveBlock.GetAccessPointer(iChunkSize);

	pxChunk->ID = ASURA_CHUNK_DEATHANIMFILENAMES;
	pxChunk->Size = iChunkSize;
	pxChunk->Version = ASURA_CHUNK_DEATHANIMFILENAMES_VERSION;
	pxChunk->Flags = 0;

	pxChunk->m_iNumberOfAnims = iNumberOfAnims;
	
	int* dest = (int*)(pxChunk+1);

	const Asura_String** ppxNameList = new const Asura_String*[iNumberOfAnims];
	pxTree->MakeNameList(ppxNameList);

	for (int i=0; i<iNumberOfAnims; i++)
	{
        const Asura_String* pxName = ppxNameList[i];
		dest = pxName->IntCopy(dest);
	}
	
	delete [] ppxNameList;
}
#endif  // ASURA_TOOLS

bool Asura_Chunk_DeathAnimFilenames::Process(Asura_Handle iFileHandle) const
{
	Asura_Assert(Version<=ASURA_CHUNK_DEATHANIMFILENAMES_VERSION,"");

	Asura_NameTree* pxTree = Asura_Hierarchy_BodyPart_System::s_pxAnimationTree;
	Asura_Assert(pxTree,"");


	for(int index = 0; index < m_iNumberOfAnims; index++)
	{
		int iJunkIndex;
        const Asura_Char* pszFilename = Asura_FileAccess::ReadString(iFileHandle);
        pxTree->FindNodeIndexByName(pszFilename,true,iJunkIndex);
	}

	return true;
}


//////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Asura_Chunk_HierarchyBodyPart **
**-------------------------------*/


bool Asura_Chunk_HierarchyBodyPart::Process(Asura_Handle iFileHandle)
{
	Asura_Assert(Version<=ASURA_CHUNK_HIERARCHYBODYPART_VERSION,"Unknown chunk version");

	//read in the rest of the chunk
	int iSize = Size - sizeof(Asura_Chunk_HierarchyBodyPart);
	char* pcChunkBuffer = new char[iSize];
	const char* pcChunkBufferCopy = pcChunkBuffer;
	Asura_FileAccess::ReadData(iFileHandle,pcChunkBuffer,iSize);

	Asura_Hierarchy_BodyPart_System::LoadFromChunk(this,pcChunkBufferCopy);

	Asura_Assert(pcChunkBufferCopy-pcChunkBuffer == iSize,"");

	delete [] pcChunkBuffer;

	return true;
}

#ifdef ASURA_TOOLS
void Asura_Chunk_HierarchyBodyPart::Create(Asura_SaveBlock& xSaveBlock)
{
	int iChunkSize = Asura_Hierarchy_BodyPart_System::GetChunkBufferSize();
	if(!iChunkSize) return;
	iChunkSize += sizeof(Asura_Chunk_HierarchyBodyPart);

	Asura_Chunk_HierarchyBodyPart* pxChunk = (Asura_Chunk_HierarchyBodyPart*)xSaveBlock.GetAccessPointer(iChunkSize);

	//fill in the common chunk details
	pxChunk->ID = ASURA_CHUNK_HIERARCHYBODYPART;
	pxChunk->Size = iChunkSize;
	pxChunk->Version = ASURA_CHUNK_HIERARCHYBODYPART_VERSION;
	pxChunk->Flags = 0;

	char* pcChunkBuffer = (char*)(pxChunk+1);
	Asura_Hierarchy_BodyPart_System::FillInChunkBuffer(pcChunkBuffer);

	Asura_Assert(int(pcChunkBuffer - (char*)(pxChunk))==iChunkSize,"GetChunkBufferSize returned incorrect value");
}
#endif  // ASURA_TOOLS

//////////////////////////////////////////////////////////////////////////////////////////////
/*---------------------------------**
** Asura_Hierarchy_BodyPart_System **
**---------------------------------*/

void Asura_Hierarchy_BodyPart_System::LoadFromChunk(const class Asura_Chunk_Header* pxChunk,const char*& pcChunkBuffer)
{
	Asura_ResourcePushType(ASURA_RESOURCE_ANIMATION);
	{
		if(s_iNumberOfBodyTypes)
		{
			Asura_Assert(0,"Hierarchy body part data already exists");
			Reset();
		}
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,s_iNumberOfBodyTypes,int);
		Asura_ResourceAllocateArray(s_pxBodyTypes, s_iNumberOfBodyTypes);

		for(int i=0;i<s_iNumberOfBodyTypes;i++)
		{
			s_pxBodyTypes[i].LoadFromChunk(pxChunk,pcChunkBuffer);
		}
	}
	Asura_ResourcePopType();
}

void Asura_Hierarchy_BodyPart_System::FillInChunkBuffer(char*& pcChunkBuffer)
{
	int	iNumberOfBodyTypes	= s_iNumberOfBodyTypes;

	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iNumberOfBodyTypes,int);
	for(int i=0;i<s_iNumberOfBodyTypes;i++)
	{
		s_pxBodyTypes[i].FillInChunkBuffer(pcChunkBuffer);
	}
}

int Asura_Hierarchy_BodyPart_System::GetChunkBufferSize()
{
	int iChunkSize = sizeof(int);
	for(int i=0;i<s_iNumberOfBodyTypes;i++)
	{
		iChunkSize += s_pxBodyTypes[i].GetChunkBufferSize();
	}
	return iChunkSize;
}


//////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------**
** Asura_Hierarchy_BodyType **
**--------------------------*/

void Asura_Hierarchy_BodyType::LoadFromChunk(const class Asura_Chunk_Header* pxChunk,const char*& pcChunkBuffer)
{
	Asura_ResourcePushType(ASURA_RESOURCE_ANIMATION);
	{
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_iNumberOfSkins,int);
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_iNumberOfBodyParts,int);

		Asura_ResourceAllocateArray(m_puSkins, m_iNumberOfSkins);
		Asura_ResourceAllocateArray(m_pxBodyParts, m_iNumberOfBodyParts);

		for(int i=0;i<m_iNumberOfSkins;i++)
		{
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_puSkins[i],Asura_Hash_ID);
		}

		for(int i=0;i<m_iNumberOfBodyParts;i++)
		{
			m_pxBodyParts[i].LoadFromChunk(pxChunk,pcChunkBuffer);
		}
	}
	Asura_ResourcePopType();
}

void Asura_Hierarchy_BodyType::FillInChunkBuffer(char*& pcChunkBuffer)
{
	int	iNumberOfSkins		= m_iNumberOfSkins;
	int	iNumberOfBodyParts	= m_iNumberOfBodyParts;

	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iNumberOfSkins,int);
	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iNumberOfBodyParts,int);
	
	for(int i=0;i<m_iNumberOfSkins;i++)
	{
		Asura_Hash_ID	uHashID	= m_puSkins[i];

		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,uHashID,Asura_Hash_ID);
	}

	for(int i=0;i<m_iNumberOfBodyParts;i++)
	{
		m_pxBodyParts[i].FillInChunkBuffer(pcChunkBuffer);
	}
}

int Asura_Hierarchy_BodyType::GetChunkBufferSize()
{
	int iChunkSize = 2*sizeof(int);
	iChunkSize += m_iNumberOfSkins*sizeof(Asura_Hash_ID);
	
	for(int i=0;i<m_iNumberOfBodyParts;i++)
	{
		iChunkSize += m_pxBodyParts[i].GetChunkBufferSize();
	}
	return iChunkSize;
}



//////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------**
** Asura_Hierarchy_BodyPart **
**--------------------------*/

void Asura_Hierarchy_BodyPart::LoadFromChunk(const class Asura_Chunk_Header* pxChunk,const char*& pcChunkBuffer)
{
	Asura_ResourcePushType(ASURA_RESOURCE_ANIMATION);
	{
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_iBodyPartType,int);
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_iNumberOfSections,int);
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_iNumberOfDeathTypes,int);

		Asura_ResourceAllocateArray(m_puSections, m_iNumberOfSections);
		Asura_ResourceAllocateArray(m_pxDeathTypes, m_iNumberOfDeathTypes);

		for(int i=0;i<m_iNumberOfSections;i++)
		{
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_puSections[i],Asura_Hash_ID);
		}

		for(int i=0;i<m_iNumberOfDeathTypes;i++)
		{
			m_pxDeathTypes[i].LoadFromChunk(pxChunk,pcChunkBuffer);
		}
	}
	Asura_ResourcePopType();
}

void Asura_Hierarchy_BodyPart::FillInChunkBuffer(char*& pcChunkBuffer)
{
	int	iBodyPartType		= m_iBodyPartType;
	int	iNumberOfSections	= m_iNumberOfSections;
	int	iNumberOfDeathTypes	= m_iNumberOfDeathTypes;

	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iBodyPartType,int);
	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iNumberOfSections,int);
	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iNumberOfDeathTypes,int);
	
	for(int i=0;i<m_iNumberOfSections;i++)
	{
		Asura_Hash_ID	uHashID	= m_puSections[i];

		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,uHashID,Asura_Hash_ID);
	}

	for(int i=0;i<m_iNumberOfDeathTypes;i++)
	{
		m_pxDeathTypes[i].FillInChunkBuffer(pcChunkBuffer);
	}
}

int Asura_Hierarchy_BodyPart::GetChunkBufferSize()
{
	int iChunkSize = 3*sizeof(int);
	iChunkSize += m_iNumberOfSections*sizeof(Asura_Hash_ID);
	
	for(int i=0;i<m_iNumberOfDeathTypes;i++)
	{
		iChunkSize += m_pxDeathTypes[i].GetChunkBufferSize();
	}
	return iChunkSize;
}

//////////////////////////////////////////////////////////////////////////////////////////////
/*---------------------------**
** Asura_Hierarchy_DeathType **
**---------------------------*/

void Asura_Hierarchy_DeathType::LoadFromChunk(const class Asura_Chunk_Header* pxChunk,const char*& pcChunkBuffer)
{
	Asura_ResourcePushType(ASURA_RESOURCE_ANIMATION);
	{
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_iDeathType,int);
		ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_iNumberOfAnimations,int);

		Asura_ResourceAllocateArray(m_puAnimations, m_iNumberOfAnimations);

		for(int i=0;i<m_iNumberOfAnimations;i++)
		{
			ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_puAnimations[i],Asura_Hash_ID);
		}
	}
	Asura_ResourcePopType();
}

void Asura_Hierarchy_DeathType::FillInChunkBuffer(char*& pcChunkBuffer)
{
	int	iDeathType			= m_iDeathType;
	int	iNumberOfAnimations	= m_iNumberOfAnimations;

	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iDeathType,int);
	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,iNumberOfAnimations,int);
	
	for(int i=0;i<m_iNumberOfAnimations;i++)
	{
		Asura_Hash_ID	uHashID	= m_puAnimations[i];

		ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer,uHashID,Asura_Hash_ID);
	}
}

int Asura_Hierarchy_DeathType::GetChunkBufferSize()
{
	int iChunkSize = 2*sizeof(int);
	iChunkSize += m_iNumberOfAnimations*sizeof(Asura_Hash_ID);
	
	return iChunkSize;
}
