//////////////////////////////////////////////////////////////////////////////
//
// Axon_GS2_AnimPackage.cpp
//
// Copyright (C) 2009 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "AnimTemplates/Axon_GS2_AnimPackage.h"

// asura
#include "Animation/Asura_Animation.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"

// axon
#include "AnimTemplates/Axon_Gamescene_AnimTemplate_System.h"

#ifdef ASURA_TOOLS
#include "ChunkSystem/Asura_Chunk_Loaders.h"

#include "Hierarchy/Tools_Animation_Files.h"
#include "Misc/Tools_MessageLog.h"
#endif

//////////////////////////////////////////////////////////////////////////////
//
// Axon_GS2_AnimMapping
//
//////////////////////////////////////////////////////////////////////////////

void Axon_GS2_AnimMapping::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
	u_int uVersion;
	xStream >> uVersion;

	if ( uVersion == uCURRENT_CHUNK_VERSION )
	{
		xStream >> m_uAnimHashID;
		xStream >> m_uAnimFilenameHashID;
	}
	else
	{
		Asura_Assertf( false, ( "Axon_GS2_AnimMapping::ReadFromChunkStream - unhandled chunk version (%u)", uVersion ) );
	}
}

void Axon_GS2_AnimMapping::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
	xStream << uCURRENT_CHUNK_VERSION;

	xStream << m_uAnimHashID;
	xStream << m_uAnimFilenameHashID;
}

#ifdef ASURA_TOOLS
void Axon_GS2_AnimMapping::LoadAnims() const
{
	if ( GetAnimHashID() != ASURA_HASH_ID_UNSET && !Asura_Animation_System::GetAnimByHash( GetAnimHashID() ) )
	{
		const char* const szFilename = Asura_HashedFilename_System::GetFilename( GetAnimFilenameHashID() );
		if ( szFilename )
		{
			LoadAsuraFile( szFilename );
		}
	}
}

void Axon_GS2_AnimMapping::AddFilesToExportList( List< Asura_String >& xNameList ) const
{
	if ( GetAnimFilenameHashID() != ASURA_HASH_ID_UNSET )
	{
		Asura_String xFilename( Asura_HashedFilename_System::GetFilename( GetAnimFilenameHashID() ) );
		if ( !xFilename.IsBlank() )
		{
			Tools_Level_Export::AddFileToExportList( xNameList, xFilename, false );
		}
	}
}

bool Axon_GS2_AnimMapping::Verify( const Axon_GS2_AnimPackage& xParentPackage ) const
{
	if ( GetAnimHashID() != ASURA_HASH_ID_UNSET && GetAnimFilenameHashID() != ASURA_HASH_ID_UNSET )
	{
		const Asura_Hierarchy_Anim* pxAnim = Tools_Animation_Files::GetAnimFromID( GetAnimHashID(), GetAnimFilenameHashID() );
		if ( pxAnim )
		{
			return true;
		}
		else
		{
			Tools_MessageLog::AddMessage( Tools_MessageLog::VERIFICATION, "Anim Templates",
				"Could not find an animation for anim package '%s'. Has it been deleted?", xParentPackage.GetName() );
			return false;
		}
	}
	else
	{
		Tools_MessageLog::AddMessage( Tools_MessageLog::VERIFICATION, "Anim Templates",
			"Anim package '%s' has a mapping without an animation.", xParentPackage.GetName() );
		return false;
	}
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// Axon_GS2_AnimPackage
//
//////////////////////////////////////////////////////////////////////////////

Axon_GS2_AnimPackage::Axon_GS2_AnimPackage()
: m_uUniqueID( uUNSET_ID )
, m_xMappings()
#ifdef ASURA_TOOLS
, m_xName()
, m_xPath()
, m_bLocalOnlyAndWritable( false )
#endif
{
}

Axon_GS2_AnimPackage::~Axon_GS2_AnimPackage()
{
	for ( Asura_LinkList_It< Axon_GS2_AnimMapping* > xMappingIt( m_xMappings ); !xMappingIt.Done(); xMappingIt.Next() )
	{
		delete *xMappingIt.GetCurrent();
	}
	m_xMappings.Clear();
}

Asura_Hash_ID Axon_GS2_AnimPackage::GetAnim( const void* pMappingData /*= NULL*/, Asura_Hash_ID* puAnimFilenameHashID /*= NULL*/ )
{
	const Axon_GS2_AnimMapping* pxBestMapping = NULL;

	if ( pMappingData )
	{
		// If pMappingData has been provided we can evaluate all of the mappings.
		Asura_LinkList_ConstIt< Axon_GS2_AnimMapping* > xMappingIt( m_xMappings );
		// The first mapping is always the default.
		xMappingIt.Next();
		while ( !xMappingIt.Done() )
		{
			const Axon_GS2_AnimMapping* pxMapping = *xMappingIt.GetCurrent();
			if ( pxMapping->Matches( pMappingData ) )
			{
				pxBestMapping = pxMapping;
				break;
			}
			xMappingIt.Next();
		}
	}

	if ( !pxBestMapping )
	{
		// If no pMappingData has been provided or nothing matches we use the default mapping.
		pxBestMapping = m_xMappings.Front() ? m_xMappings.Front()->Data() : NULL;
	}

	if ( pxBestMapping )
	{
		if ( puAnimFilenameHashID )
		{
			*puAnimFilenameHashID = pxBestMapping->GetAnimFilenameHashID();
		}
		return pxBestMapping->GetAnimHashID();
	}
	else
	{
		if ( puAnimFilenameHashID )
		{
			*puAnimFilenameHashID = ASURA_HASH_ID_UNSET;
		}
		return ASURA_HASH_ID_UNSET;
	}
}

void Axon_GS2_AnimPackage::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
	u_int uVersion;
	xStream >> uVersion;

	if ( uVersion == uCURRENT_CHUNK_VERSION )
	{
		xStream >> m_uUniqueID;

		u_int uNumMappings;
		xStream >> uNumMappings;
		if ( uNumMappings )
		{
			for ( u_int u = 0; u < uNumMappings; ++u )
			{
				Axon_GS2_AnimMapping* pxMapping = CreateAnimMapping( false );
				pxMapping->ReadFromChunkStream( xStream );
				m_xMappings.Push_Back( pxMapping );
			}
		}

		#ifdef ASURA_TOOLS
		xStream >> m_xName;
		xStream >> m_xPath;
		#else
		Asura_String xDummy;
		xStream >> xDummy;
		xStream >> xDummy;
		#endif
	}
	else
	{
		Asura_Assertf( false, ( "Axon_GS2_AnimPackage::ReadFromChunkStream - unhandled chunk version (%u)", uVersion ) );
	}
}

#ifdef ASURA_TOOLS
void Axon_GS2_AnimPackage::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
	xStream << uCURRENT_CHUNK_VERSION;

	xStream << m_uUniqueID;
	xStream << m_xMappings.Size();
	for ( Asura_LinkList_ConstIt< Axon_GS2_AnimMapping* > xMappingIt( m_xMappings ); !xMappingIt.Done(); xMappingIt.Next() )
	{
		(*xMappingIt.GetCurrent())->WriteToChunkStream( xStream );
	}
	xStream << m_xName;
	xStream << m_xPath;
}

void Axon_GS2_AnimPackage::LoadAnims() const
{
	for ( Asura_LinkList_ConstIt< Axon_GS2_AnimMapping* > xMappingIter( m_xMappings ); !xMappingIter.Done(); xMappingIter.Next() )
	{
		(*xMappingIter.GetCurrent())->LoadAnims();
	}
}

void Axon_GS2_AnimPackage::AddFilesToExportList( List< Asura_String >& xNameList ) const
{
	for ( Asura_LinkList_ConstIt< Axon_GS2_AnimMapping* > xMappingIter( m_xMappings ); !xMappingIter.Done(); xMappingIter.Next() )
	{
		(*xMappingIter.GetCurrent())->AddFilesToExportList( xNameList );
	}
}

bool Axon_GS2_AnimPackage::Verify() const
{
	bool bOk = true;
	for ( Asura_LinkList_ConstIt< Axon_GS2_AnimMapping* > xMappingIter( m_xMappings ); !xMappingIter.Done(); xMappingIter.Next() )
	{
		bOk &= (*xMappingIter.GetCurrent())->Verify( *this );
	}
	return bOk;
}

void Axon_GS2_AnimPackage::AllocateUniqueID( const Asura_String& xName )
{
	u_int uUniqueID = Asura_GetHashID( xName.GetString() );
	// Make sure it really is unique.
	while ( Axon_Gamescene_AnimTemplate_System::GetAnimPackageByID( uUniqueID ) ) { ++uUniqueID; }
	m_uUniqueID = uUniqueID;
}

void Axon_GS2_AnimPackage::AddAnimMapping()
{
	m_xMappings.Push_Back( CreateAnimMapping( true ) );
}

void Axon_GS2_AnimPackage::DeleteAnimMapping( Axon_GS2_AnimMapping* pxMapping )
{
	// Mapping zero is the default anim mapping, which cannot be deleted.
	if ( m_xMappings.Size() == 1 ) { return; }
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////
