//////////////////////////////////////////////////////////////////////////////
//
// Asura_Chunk_DSP.cpp
//
// Copyright (c) 2008 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

/******************************************************************************/
/* Included Files                                                             */
/******************************************************************************/

#include "Core/Asura.h"

#if defined ASURA_USE_AUDIO_SYSTEM

#include "ChunkSystem/Asura_Chunk_DSP.h"

// Asura Platform-independent
#include "ChunkSystem/Asura_Chunk_Loaders.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Core/Asura_String.h"
#include "Core/Memory/Asura_Mem.h"
#include "Sound/Asura_Audio_DSP.h"
#include "Sound/Asura_Audio_System.h"

// Tools
#if defined ASURA_TOOLS
	//#include "Sound/Tools_Audio_DSP.h"
	#include "Misc/Tools_Timed_Messages.h"
	#include "ChunkSystem/Asura_SaveBlock.h"
	#include "Sound/Tools_Audio_DSP.h"
#endif

#ifdef ASURA_TOOLS
static const char* g_szFilename = "Sounds\\DSP.asr";
#endif

/******************************************************************************/
/* Asura_Chunk_DSP Static Class Data                                          */
/******************************************************************************/

const int Asura_Chunk_DSP::iCURRENT_VERSION = 1;

/******************************************************************************/
/* Asura_Chunk_DSP Class Functions                                            */
/******************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// Asura_Chunk_DSP::Process()
//
// Processes a chunk containing DSP chain parameters
//
////////////////////////////////////////////////////////////////////////////////

bool Asura_Chunk_DSP::Process( const int iFileHandle )
{
	Asura_Assertf( Version >= 0 && Version <= iCURRENT_VERSION,
		("Invalid DSP chunk version %d. You may need new code.", Version) );

	if( Version <= 0 || Version > iCURRENT_VERSION ) return false;

	Asura_Chunk_File_Stream xStream( iFileHandle );

	u_int uNumChains;
	xStream >> uNumChains;

	for( u_int u = 0; u < uNumChains; ++u )
	{
		Asura_Audio_DSPChain xChain;

		xStream >> xChain.m_xName;
		const Asura_Hash_ID uChainHash = xChain.m_xName.GetHash();

		xStream >> xChain.m_uNumEffects;
		xChain.m_ppxEffects = new Asura_DSP_Params*[ xChain.m_uNumEffects ];

		Asura_Assert( xChain.m_ppxEffects, "Failed to allocate effect chain." );
		if( !xChain.m_ppxEffects ) return false;

		const size_t uSize = sizeof( Asura_DSP_Params* ) * xChain.m_uNumEffects;
		if( xChain.m_uNumEffects > 0 )
		{
			Asura_Mem::Set( xChain.m_ppxEffects, 0, uSize );
		}

		for( u_int uEffect = 0; uEffect < xChain.m_uNumEffects; ++uEffect )
		{
			u_int uDSPType;
			xStream >> uDSPType;

			Asura_DSP_Params* pxEffect = Asura_DSP_Params::CreateEffect( static_cast<Asura_Audio_DSPType>( uDSPType ) );

			if( pxEffect )
			{
				pxEffect->ReadFromChunkStream( xStream );

				xChain.m_ppxEffects[uEffect] = pxEffect;
			}
			else
			{
				break;
			}
		}

		Asura_Audio_System::AddDSPChain( uChainHash, &xChain );
	}

	return true;
}

#ifdef ASURA_TOOLS

void Asura_Chunk_DSP::Create( Asura_SaveBlock* pxSaveBlock )
{
	Asura_Chunk_SaveBlock_Stream xStream( pxSaveBlock );
	Create(xStream);
}


void Asura_Chunk_DSP::Create( Asura_Chunk_Stream& xStream )
{
	xStream.WriteChunk_Start( ASURA_CHUNK_DSP, Asura_Chunk_DSP::iCURRENT_VERSION, 0 );

	const int iNumChains = Asura_Audio_System::GetNumDSPChains();
	xStream << iNumChains;

	// Save each chain
	for( Asura_TemplateHashTree_SaveIterator xChainIter( iNumChains ); !xChainIter.Done(); xChainIter.Next() )
	{
		const int iChainIndex = xChainIter.GetCurrent();
		const Asura_Audio_DSPChain* const pxChain = Asura_Audio_System::GetDSPChainByIndex( iChainIndex );

		xStream << pxChain->m_xName;

		xStream << pxChain->m_uNumEffects;

		for( u_int uEffect = 0; uEffect < pxChain->m_uNumEffects; ++uEffect )
		{
			xStream << static_cast<u_int>( pxChain->m_ppxEffects[ uEffect ]->GetType() );

			pxChain->m_ppxEffects[ uEffect ]->WriteToChunkStream( xStream );
		}
	}

	// Write chunk footer
	xStream.WriteChunk_End();
}


bool Asura_Chunk_DSP::SaveToolsData()
{
	// Save to the tools file
	Asura_SaveBlock xSaveBlock;
	Asura_Chunk_SaveBlock_Stream xStream( &xSaveBlock );

	Create( xStream );

	xStream.WriteAsuraTerminator();

	// Save the file
	const char* const szFilename = GetFilename();

	if( xSaveBlock.SaveFile( szFilename, true ) )
	{
		Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_SUCCESS,	"Saved DSP chains successfully" );
		Tools_Audio_DSP::Modified() = false;
		return true;
	}
	else
	{
		Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR, "Failed to open '%s' for writing. Is it checked out?", szFilename );
		return false;
	}
}


const char* Asura_Chunk_DSP::GetFilename ()
{
	return g_szFilename;
}


#endif // ASURA_TOOLS

#endif // defined ASURA_USE_AUDIO_SYSTEM
