/**
*
* \file Asura_ServerEntity_MultiDamageVolume.cpp
*
* Created by Andrew Weinkove - 06/02/2004
*
* Copyright (C) 2004 Rebellion, All Rights Reserved.
*
* A damage volume with multiple, orientable bounding boxes and optional dynamics.
* Based heavily on the implementation of advanced volume triggers.
* Because the volumes can have dynamics, this class checks against bounding boxes, 
* NOT points.
*
**/

#include "Core/Asura.h"
#include "Entity/Triggers/Asura_ServerEntity_MultiDamageVolume.h"

// Engine independent.
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Debugging/Asura_Assert.h"
#include "Dynamics/Asura_Collision_Object.h"
#include "Physics/Asura_Physics_Object.h"
#include "Entity/Asura_Entity_Classification.h"
#include "Entity/Triggers/Asura_ServerEntity_AdvancedVolumeTrigger.h"
#include "Volume/Asura_VolumeGroup.h"
#include "Volume/Asura_Volume_Cuboid.h"

#ifdef ASURA_TOOLS
#include "EntityTemplate/Tools_EntityTemplate_System.h"
#endif


const int Asura_ServerEntity_MultiDamageVolume::s_iMaxNumberOfLists = 32;

// constructor for loading from a stream, does not create any volumes as these are done in ReadFromChunkStream
Asura_ServerEntity_MultiDamageVolume::Asura_ServerEntity_MultiDamageVolume( Asura_Guid uGuid ) 
: Asura_ServerEntity_Activatable(uGuid)
{
	Classification			= AsuraEntityClass_MultiDamageVolume;
	m_uFlags				= 0;
	m_iListFlags			= 0;
	
	m_pxVolumeGroup = new Asura_VolumeGroup;

//	m_ppxDynamicObjects = NULL;
//	m_ppxCollisionBoxes = NULL;
	m_fDamageRate = 0.0f;
}

Asura_ServerEntity_MultiDamageVolume::Asura_ServerEntity_MultiDamageVolume(Asura_Bounding_Box& xBox, bool bInitiallyActive ) 
: Asura_ServerEntity_Activatable(bInitiallyActive)
{
	Classification         = AsuraEntityClass_MultiDamageVolume;
	m_iListFlags           = 0;

	m_pxVolumeGroup = new Asura_VolumeGroup;
	Asura_Volume_Cuboid* pxVolume = new Asura_Volume_Cuboid(xBox, Asura_Maths::IdentityQuat);
	m_pxVolumeGroup->AddVolume(pxVolume);

//	m_ppxDynamicObjects = NULL;
//	m_ppxCollisionBoxes = NULL;
	m_fDamageRate = 0.0f;
	m_uFlags = 0;
}

Asura_ServerEntity_MultiDamageVolume::Asura_ServerEntity_MultiDamageVolume(Asura_Guid uGuid,const char*& pcChunkBuffer)
:Asura_ServerEntity_Activatable(uGuid)
{
	Classification = AsuraEntityClass_MultiDamageVolume;
	m_iListFlags           = 0;

	m_pxVolumeGroup = new Asura_VolumeGroup;

//	m_ppxDynamicObjects = NULL;
//	m_ppxCollisionBoxes = NULL;
	m_fDamageRate = 0.0f;
	m_uFlags = 0;

	Asura_Chunk_ChunkBuffer_Stream xStream(pcChunkBuffer);
	Asura_ServerEntity_MultiDamageVolume::ReadFromChunkStream(xStream);

	SynchroniseDynamicObjects();
}

Asura_ServerEntity_MultiDamageVolume::~Asura_ServerEntity_MultiDamageVolume()
{
	delete m_pxVolumeGroup;
	m_pxVolumeGroup = NULL;
	DeleteDynamicObjects();
}

void Asura_ServerEntity_MultiDamageVolume::DeleteDynamicObjects()
{

	//if (m_ppxCollisionBoxes)
	//{
	//	for (int i=0;i<m_iNumberOfVolumes;i++)
	//	{
	//		delete m_ppxCollisionBoxes[i];
	//	}
	//	delete[]m_ppxCollisionBoxes;
	//	m_ppxCollisionBoxes = 0;
	//}
	//if (m_ppxDynamicObjects)
	//{
	//	for (int i=0;i<m_iNumberOfVolumes;i++)
	//	{
	//		Asura_Physics_Object::Destroy( m_ppxDynamicObjects[i] );
	//	}
	//	delete[]m_ppxDynamicObjects;
	//	m_ppxDynamicObjects = 0;
	//}

}


void Asura_ServerEntity_MultiDamageVolume::SynchroniseDynamicObjects()
{
	// (AW - 06.02.2004) - This function makes sure that the dynamic and collision objects are 
	// in sync with the orientated volumes.
	// (AW - 06.02.2004) - This function may be called lots from tools but is only called once  
	// on creation in game, so this doesn't create fragmentation issues.
	
	//RAR 21/02/2008 Disabled ,since this hasn't worked in ages. 
	
	//DeleteDynamicObjects();
	//if (m_bUsesDynamicsWhenActive &&
	//	m_iNumberOfVolumes)
	//{
	//	// (AW - 06.02.2004) - Create the dynamic objects and collision boxes.
	//	m_ppxDynamicObjects = new Asura_Physics_Object*[m_iNumberOfVolumes];
	// 
	//	m_ppxCollisionBoxes = new Asura_Collision_Box*[m_iNumberOfVolumes];
	//	for (int i=0;i<m_iNumberOfVolumes;i++)
	//	{
	//		Asura_Vector_3 xBBCentre = m_pxVolumes[i].CalculateCentre();
	//		Asura_Bounding_Box xDynamicsBox = m_pxVolumes[i].m_xBox;
	//		xDynamicsBox.Displace(-xBBCentre);
	//		m_ppxCollisionBoxes[i] = new Asura_Collision_Box(xDynamicsBox);
	//		m_ppxDynamicObjects[i] = NULL;
	//  
	//		// PHYSICSTODO 
	//		m_ppxDynamicObjects[i] = Asura_Physics_Object::Create();
	//	
	//	}
	//}
}

void Asura_ServerEntity_MultiDamageVolume::OnActivation()
{
	
	//if (m_bUsesDynamicsWhenActive)
	//{
	//	Asura_Assert(m_ppxDynamicObjects, "There should be some dynamic objects allocated.");
	//	for (int i=0;i<m_iNumberOfVolumes;i++)
	//	{
	//		if (m_ppxDynamicObjects[i])
	//		{
	//			m_ppxDynamicObjects[i]->SetIgnore(false);
	//		}
	//	}
	//}
	
	Asura_ServerEntity_Activatable::OnActivation();
}

void Asura_ServerEntity_MultiDamageVolume::OnDeactivation()
{
	//if (m_bUsesDynamicsWhenActive)
	//{
	//	Asura_Assert(m_ppxDynamicObjects, "There should be some dynamic objects allocated.");
	//	for (int i=0;i<m_iNumberOfVolumes;i++)
	//	{
	//		if (m_ppxDynamicObjects[i])
	//		{
	//			m_ppxDynamicObjects[i]->SetIgnore(true);
	//		}
	//	}
	//	m_bDoneTestWhenUsingDynamics = false;
	//}  
	
	Asura_ServerEntity_Activatable::OnDeactivation();
}

void Asura_ServerEntity_MultiDamageVolume::ApplyDamage()
{
	// (AW - 06.02.2004) - Override this function for functionality.
}

void Asura_ServerEntity_MultiDamageVolume::Update()
{
	// (AW - 09.02.2004) - Don't bother testing multiple times if we are using dynamics. If
	// someone was in there, they are already dead, if noone was in there then dynamics should
	// prevent them from getting in.
	Asura_Assert(!m_bUsesDynamicsWhenActive || m_bInstantDeath, "Instant death must be on if dynamics are on.");
	if (IsActive() &&
		(m_bUsesDynamicsWhenActive == false || 
		 m_bDoneTestWhenUsingDynamics == false))
	{
		ApplyDamage();
	}
}

bool Asura_ServerEntity_MultiDamageVolume::Overlaps(const Asura_Bounding_Box& xBox)
{
	return m_pxVolumeGroup->Overlaps(xBox);
}

bool Asura_ServerEntity_MultiDamageVolume::Contains(const Asura_Vector_3& xPos) const
{
	return m_pxVolumeGroup->Contains(xPos);
}


int Asura_ServerEntity_MultiDamageVolume::GetChunkBufferSize()
{
	Asura_Chunk_Dummy_Stream xStream;
	Asura_ServerEntity_MultiDamageVolume::WriteToChunkStream(xStream);

	return xStream.GetPosition();
}

void Asura_ServerEntity_MultiDamageVolume::FillInChunkBuffer(char*& pcChunkBuffer)
{
	Asura_Chunk_ChunkBuffer_Stream xStream(pcChunkBuffer);
	Asura_ServerEntity_MultiDamageVolume::WriteToChunkStream(xStream);
}

////////////////////////////////////////////////////////////////////
// Function		:	WriteToChunkStream
// Author		:	Chris Wallace
// Description	:	Function to write volume data to a chunk stream
////////////////////////////////////////////////////////////////////

void Asura_ServerEntity_MultiDamageVolume::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	Asura_WriteToStream_Bitfield_Wrapper<u_int>	xFlagsBitfield (m_uFlags);

	xFlagsBitfield.Add	(m_bUsesDynamicsWhenActive,			1);
	xFlagsBitfield.Add	(m_bVolumesBlockWaypointCreation,	1);
	xFlagsBitfield.Add	(m_bInstantDeath,					1);
	xFlagsBitfield.Add	(m_bDoneTestWhenUsingDynamics,		1);
	
	//fill in base class
	Asura_ServerEntity_Activatable::WriteToChunkStream( xStream );

	int iVersion = ChunkData::CURRENT_VERSION;
	xStream << iVersion;

	xStream << m_iListFlags;
	xStream << xFlagsBitfield;
	xStream << m_fDamageRate;

	m_pxVolumeGroup->WriteToChunkStream(xStream);
}

///////////////////////////////////////////////////////////////////////
// Function		:	ReadFromChunkStream
// Author		:	Chris Wallace
// Description	:	Function read the volume data from a chunk stream
///////////////////////////////////////////////////////////////////////

void Asura_ServerEntity_MultiDamageVolume::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion;
	Asura_ReadFromStream_Bitfield_Wrapper<u_int> xBitfield(m_uFlags);

	PARENT::ReadFromChunkStream(xStream);

	xStream >> iVersion;

	xStream >> m_iListFlags;
	xStream >> xBitfield;

	int iNumberOfVolumes = 0;
	if(iVersion == 0)
	{
		xStream >> iNumberOfVolumes;
	}
	xStream >> m_fDamageRate;


	if(iVersion == 0)
	{
		//convert old format to volume groups
		m_pxVolumeGroup->ReadOrientedVolumeArrayFromChunkStream(xStream,iNumberOfVolumes);
	}
	else
	{
		m_pxVolumeGroup->ReadFromChunkStream(xStream);
	}

	if(iVersion == 0)
	{
		//reset a couple of flags that haven't been operational for a few years
		//RAR 21/02/2008
		m_bUsesDynamicsWhenActive = 0;
		m_bVolumesBlockWaypointCreation = 0;

	}
}

#ifdef ASURA_TOOLS
void Asura_ServerEntity_MultiDamageVolume::ApplyChangesForTemplateInstance(Tools_EntityTemplateInstance* pxInstance)
{
	Asura_ServerEntity_Activatable::ApplyChangesForTemplateInstance(pxInstance);

	m_pxVolumeGroup->ApplyChangesForTemplateInstance(pxInstance);

}
#endif // ASURA_TOOLS




