//
// Asura_Chunk_Fragment.cpp
//
// Created by Richard Rice - 02/12/2002
// 
// Copyright (C) 2002 Rebellion, All Rights Reserved.
//


#include "Core/Asura.h"

#include "ChunkSystem/Asura_Chunk_Fragment.h"

#include "ChunkSystem/Asura_Chunk_Loaders.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Core/Memory/Asura_ResourceAllocator.h"
#include "Debugging/Asura_Assert.h"
#include "FileAccess/Asura_FileAccess.h"
#include "SpecialFX/Asura_Fragment_System.h"

#define ASURA_CHUNK_FRAGMENT_VERSION 0


#if defined(ASURA_TOOLS)

void Asura_Chunk_Fragment::Create (const Asura_FragmentType* pxFragmentType,
								   Asura_Chunk_Stream& xStream)
{
	Asura_Assert(pxFragmentType,"");

	const int	iFlags	= (pxFragmentType->m_bAnimatedFragment)
						? ChunkFlag_AnimatedFragment
						: 0;

	// Write the data...
	xStream.WriteChunk_Start	(ASURA_CHUNK_FRAGMENT, ASURA_CHUNK_FRAGMENT_VERSION, iFlags);

	xStream << pxFragmentType->m_uFragmentHash;
	xStream << pxFragmentType->m_iNumberOfFragments;

	for(int i=0;i<pxFragmentType->m_iNumberOfFragments;i++)
	{
		const Asura_Fragment*	pxFragment	= &pxFragmentType->m_pxFragments [i];

		xStream << pxFragment->m_uShapeHash;
		xStream << pxFragment->m_xPosition;
		xStream << pxFragment->m_uFlags;
		xStream << pxFragment->m_iQuantity;
	}

	xStream.WriteChunk_End	();
}

void Asura_Chunk_Fragment::Create(const class Asura_FragmentType* pxFragmentType , class Asura_SaveBlock* pxSaveBlock)
{
#if 0
	Asura_Assert(pxFragmentType,"");

	//work out the chunk size
	int iChunkSize = sizeof(Asura_Chunk_Fragment);
	iChunkSize += sizeof(Asura_Hash_ID)+sizeof(int); //fragment hash id , and number of fragments
	iChunkSize += pxFragmentType->m_iNumberOfFragments *
				  (sizeof (Asura_Hash_ID) + //m_uShapeHash
				   sizeof (Asura_Vector_3) + // m_xPosition
				   sizeof (unsigned) + //m_uFlags
				   sizeof (int)); //m_iQuantity

	Asura_Chunk_Fragment* pxChunk = (Asura_Chunk_Fragment*) pxSaveBlock->GetAccessPointer(iChunkSize);
	pxChunk->ID = ASURA_CHUNK_FRAGMENT;
	ASURA_CHUNK_VERIFY(pxChunk->ID, int);
	pxChunk->Size = iChunkSize;
	ASURA_CHUNK_VERIFY(pxChunk->Size, int);
	pxChunk->Version = ASURA_CHUNK_FRAGMENT_VERSION;
	ASURA_CHUNK_VERIFY(pxChunk->Version, int);
	pxChunk->Flags = 0;
	if(pxFragmentType->m_bAnimatedFragment) pxChunk->Flags |= ChunkFlag_AnimatedFragment;
	ASURA_CHUNK_VERIFY(pxChunk->Flags, int);


	char* pcBuffer = (char*)(pxChunk+1);

	ASURA_CHUNK_FILLANDVERIFY(pcBuffer,pxFragmentType->m_uFragmentHash,Asura_Hash_ID)
	ASURA_CHUNK_FILLANDVERIFY(pcBuffer,pxFragmentType->m_iNumberOfFragments,int)

	for(int i=0;i<pxFragmentType->m_iNumberOfFragments;i++)
	{
		const Asura_Fragment* pxFragment = &pxFragmentType->m_pxFragments[i];
		ASURA_CHUNK_FILLANDVERIFY(pcBuffer,pxFragment->m_uShapeHash,Asura_Hash_ID)
		ASURA_CHUNK_ARRAY_FILLANDVERIFY(pcBuffer,pxFragment->m_xPosition,Asura_Vector_3, float, 3)
		ASURA_CHUNK_FILLANDVERIFY(pcBuffer,pxFragment->m_uFlags,unsigned)
		ASURA_CHUNK_FILLANDVERIFY(pcBuffer,pxFragment->m_iQuantity,int)
	}

	Asura_Assert((long)pcBuffer-(long)pxChunk == iChunkSize,"Incorrect chunk size");
#else
	Asura_Chunk_SaveBlock_Stream	xStream (pxSaveBlock);

	// Call the other version...
	Create	(pxFragmentType, xStream);
#endif
}

#endif	//defined(ASURA_TOOLS)


bool Asura_Chunk_Fragment::Process (Asura_Chunk_Stream& xStream) const
{
	Asura_FragmentType*	pxFragmentType	= NULL;

	Asura_Hash_ID		uHash;

	//get the hash id for this fragment type
	Asura_Assert(Version<=ASURA_CHUNK_FRAGMENT_VERSION,"Unknown chunk version");
	xStream >> uHash;

	//and allocate the fragment type
	if(!Asura_Fragment_System::NewFragmentType(uHash,pxFragmentType))
	{
#if  defined(ASURA_ASSERT) && defined(ASURA_ENABLE_HASH_TO_FILENAME_LOOKUPS)
		const char* szFragmentName = Asura_HashedFilename_System::GetFilename(uHash);
		Asura_Assertf(0,("Fragment type '%s' already exists - Skipping",szFragmentName ? szFragmentName : "<unknown>"));
#endif
		return false;
	}
	else if(Flags & ChunkFlag_AnimatedFragment)
	{
		pxFragmentType->m_bAnimatedFragment = true;
	}

	xStream >> pxFragmentType->m_iNumberOfFragments;
	if(pxFragmentType->m_iNumberOfFragments)
	{
		Asura_ResourcePushType(ASURA_RESOURCE_FRAGMENT);
		{
			Asura_ResourceAllocateArray(pxFragmentType->m_pxFragments, pxFragmentType->m_iNumberOfFragments);

			for(int i=0;i<pxFragmentType->m_iNumberOfFragments;i++)
			{
				Asura_Fragment* pxFragment = &pxFragmentType->m_pxFragments[i];

				xStream >> pxFragment->m_uShapeHash;
				xStream >> pxFragment->m_xPosition;
				xStream >> pxFragment->m_uFlags;
				xStream >> pxFragment->m_iQuantity;
			}
		}
		Asura_ResourcePopType();
	}

	return true;
}

bool Asura_Chunk_Fragment::Process(Asura_Handle iFileHandle) const
{
#if 0
	Asura_Assert(Version<=ASURA_CHUNK_FRAGMENT_VERSION,"Unknown chunk version");

	//get the hash id for this fragment type
	Asura_Hash_ID uHash;
	ASURA_CHUNK_FILEEXTRACT(iFileHandle,uHash,Asura_Hash_ID)

	//and allocate the fragment type
	Asura_FragmentType* pxFragmentType = 0;
	if(!Asura_Fragment_System::NewFragmentType(uHash,pxFragmentType))
	{
		#if  defined(ASURA_ASSERT) && defined(ASURA_ENABLE_HASH_TO_FILENAME_LOOKUPS)
		const char* szFragmentName = Asura_HashedFilename_System::GetFilename(uHash);
		Asura_Assertf(0,("Fragment type '%s' already exists - Skipping",szFragmentName ? szFragmentName : "<unknown>"));
		#endif
		return false;
	}
	if(Flags & ChunkFlag_AnimatedFragment)
	{
		pxFragmentType->m_bAnimatedFragment = true;
	}


	ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFragmentType->m_iNumberOfFragments,int)
	if(pxFragmentType->m_iNumberOfFragments)
	{
		Asura_ResourcePushType(ASURA_RESOURCE_FRAGMENT);
		{
			Asura_ResourceAllocateArray(pxFragmentType->m_pxFragments, pxFragmentType->m_iNumberOfFragments);

			for(int i=0;i<pxFragmentType->m_iNumberOfFragments;i++)
			{
				Asura_Fragment* pxFragment = &pxFragmentType->m_pxFragments[i];
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFragment->m_uShapeHash,Asura_Hash_ID);
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFragment->m_xPosition,Asura_Vector_3);
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFragment->m_uFlags,unsigned);
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFragment->m_iQuantity,int);
			}
		}
		Asura_ResourcePopType();
	}

	return true;
#else
	Asura_Chunk_File_Stream	xStream (iFileHandle);

	// Call the stream version of the function...
	return	(Process(xStream));
#endif
}
