//
// Asura_Shard_System.cpp
//
// Created by Andrew Weinkove - 03/12/02 
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "SpecialFX/Asura_Shard_System.h"

#include "SpecialFX/Asura_Shard_Effect.h"
#include "Debugging/Asura_Assert.h"
#include "Core/Asura_Mempool.h"

static const u_int ASURA_NUMBER_OF_SHARDS_PER_POOL = 64;

int												Asura_Shard_System::s_iNumberOfActiveShards;
Asura_ResizingMempool*							Asura_Shard_System::s_pxShardPool;
Asura_TrackingHandlePool<Asura_Shard_Effect>*	Asura_Shard_System::s_pxShardEffectList;

void Asura_Shard_System::Initialise(void)
{
	s_iNumberOfActiveShards = 0;
	s_pxShardPool = new Asura_ResizingMempool(ASURA_NUMBER_OF_SHARDS_PER_POOL, sizeof(Asura_Shard), __FILE__, __LINE__);
	s_pxShardEffectList = new Asura_TrackingHandlePool<Asura_Shard_Effect>(8);
}

void Asura_Shard_System::Shutdown(void)
{
	delete s_pxShardEffectList;
    s_pxShardEffectList = NULL;

	s_iNumberOfActiveShards = 0;
	
    delete s_pxShardPool;
    s_pxShardPool = NULL;
}


void Asura_Shard_System::Reset(void)
{
// (MH - 15.12.2002) avoid fragmentation
//	Shutdown();
//	Initialise();
    s_pxShardEffectList->Reset();
    Asura_Assert(!s_iNumberOfActiveShards, "MH");
    s_iNumberOfActiveShards = 0;
    s_pxShardPool->Reset();
}

void Asura_Shard_System::Render(void)
{
	Platform_BeginRender();
	s_pxShardEffectList->Traverse(RenderCallback);
	Platform_EndRender();
}

void Asura_Shard_System::RenderCallback(Asura_Shard_Effect *pxShardEffect)
{
	if (pxShardEffect->IsReadyToBeDestroyed())
	{
		DestroyShardEffect(pxShardEffect);
	}
	else
	{
		pxShardEffect->Render();
	}
}

void Asura_Shard_System::Update(void)
{
	s_pxShardEffectList->Traverse(UpdateCallback);
}

void Asura_Shard_System::UpdateCallback(Asura_Shard_Effect *pxShardEffect)
{
	if (!pxShardEffect->IsReadyToBeDestroyed())
	{
		pxShardEffect->Update();
	}
}

Asura_Shard* Asura_Shard_System::AllocateShard(void)
{
	s_iNumberOfActiveShards++;
	Asura_Shard* pxShard = (Asura_Shard*)s_pxShardPool->Allocate();

	return pxShard;
}

void Asura_Shard_System::DeallocateShard(Asura_Shard *pxShard)
{
	s_pxShardPool->Deallocate(pxShard);
	s_iNumberOfActiveShards--;
}

Asura_Shard_Effect* Asura_Shard_System::CreateShardEffect(void)
{
	Asura_Handle iHandle = s_pxShardEffectList->Allocate();
	if (iHandle == ASURA_INVALID_HANDLE)
	{
		return NULL;
	}
	Asura_Shard_Effect* pxEffect = s_pxShardEffectList->GetPointer(iHandle);
	pxEffect->m_iHandle = iHandle;
	return pxEffect;
}

void Asura_Shard_System::DestroyShardEffect(const Asura_Shard_Effect* pxEffect)
{
	Asura_Assert( pxEffect != NULL, "Invalid pointer!" );
	
#ifdef ASURA_ASSERT
	Asura_Handle iHandle = pxEffect->m_iHandle;
	Asura_Assert( iHandle != ASURA_INVALID_HANDLE, "invalid handle" );
	Asura_Shard_Effect* pxEffectTest = s_pxShardEffectList->GetPointer(iHandle);
	Asura_Assert( pxEffectTest == pxEffect, "pointer mismatch" );
#endif

	s_pxShardEffectList->Deallocate( pxEffect->m_iHandle );
}
