///////////////////////////////////////////////////////////////////////////////
//
// File: Asura_ServerEntity_CameraVolume.cpp
//
// Created by Martin G.Harris (4/9/2006)
// 
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
// Activatable volume that has a set of project specific camera properties associated with it.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Entity/Asura_Entity_Classification.h"
#include "Entity/Triggers/Asura_ClientEntity_CameraVolume.h"
#include "Network/Asura_Message.h"
#include "Network/Asura_Network.h"

#ifdef ASURA_USE_CAMERA_VOLUME
/////////////////////////////////////
// Asura_ServerEntity_CameraVolume //
/////////////////////////////////////
int Asura_ServerEntity_CameraVolume::s_iCurrentChunkVersion(0);

Asura_ServerEntity_CameraVolume::Asura_ServerEntity_CameraVolume(bool bActive /*=true*/)
: PARENT(bActive)
{
	Classification = AsuraEntityClass_CameraVolume;
	SetNeverUpdates(true); // Doesn't need to call Update()
}

Asura_ServerEntity_CameraVolume::Asura_ServerEntity_CameraVolume(Asura_Guid uGuid)
: PARENT(uGuid)
{
	Classification = AsuraEntityClass_CameraVolume;
	SetNeverUpdates(true);  // Doesn't need to call Update()
}

Asura_ServerEntity_CameraVolume::~Asura_ServerEntity_CameraVolume()
{}

void Asura_ServerEntity_CameraVolume::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
	int iChunkVersion(0);

	xStream >> iChunkVersion;

	Asura_Assertf( iChunkVersion <= s_iCurrentChunkVersion,("Chunk version '%i' not yet supported",iChunkVersion) );

	PARENT::ReadFromChunkStream( xStream );

	SetNeverUpdates(true);	
	
	// ignore client specific Asura_CameraMultiVolume data stored in stream
	Asura_CameraMultiVolume::SkipChunkStream( xStream );
}

void Asura_ServerEntity_CameraVolume::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
	xStream << s_iCurrentChunkVersion;

	// Parent must come first.It contains the active flag.
	PARENT::WriteToChunkStream( xStream );

	Asura_ClientEntity_CameraVolume* pxClient( Asura_ClientEntity_CameraVolume::FindEntity(Guid) );

	if( pxClient )
	{
		// All the volume data is stored in the client entity.
		pxClient->m_xVolume.WriteToChunkStream( xStream );
	}
	else
	{
		Asura_Assert( false,"Error: Asura_ServerEntity_CameraVolume couldn't find client" );

		// Write a zero version number to mark that there is no volume data.
		xStream << 0;
	}
}

////////////////////////
// GetChunkBufferSize //
////////////////////////
int Asura_ServerEntity_CameraVolume::GetChunkBufferSize()
{
	u_int uSize = 0;
	const Asura_ClientEntity_CameraVolume* pxClient = Asura_ClientEntity_CameraVolume::FindEntity(Guid);
	if (pxClient)
	{
		uSize = pxClient->m_xVolume.GetChunkBufferSize();
	}
	else
	{
		// Couldn't find the client entity; fallback is to write a version-zero chunk.
		uSize = Asura_CameraMultiVolume::GetChunkBufferSize_V0();
	}

	return PARENT::GetChunkBufferSize() + uSize;
}

///////////////////////
// FillInChunkBuffer //
///////////////////////
void Asura_ServerEntity_CameraVolume::FillInChunkBuffer(char*& pcChunkBuffer)
{
	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer, s_iCurrentChunkVersion, int);

	// Parent must come first.It contains the active flag.
	PARENT::FillInChunkBuffer(pcChunkBuffer);

	Asura_ClientEntity_CameraVolume* pxClient = Asura_ClientEntity_CameraVolume::FindEntity(Guid);
	if (pxClient)
	{
		// All the volume data is stored in the client entity.
		pxClient->m_xVolume.FillInChunkBuffer(pcChunkBuffer);
	}
	else
	{
		Asura_Assert(0, "Error: Asura_ServerEntity_CameraVolume couldn't find client");

		// Write a zero version number to mark that there is no volume data.
		Asura_CameraMultiVolume::FillInChunkBuffer_V0(pcChunkBuffer);
	}
}

///////////////////////////////
// InitialiseFromChunkBuffer //
///////////////////////////////
void Asura_ServerEntity_CameraVolume::InitialiseFromChunkBuffer(const char*& pcChunkBuffer)
{
	int iChunkVersion(0);
	ASURA_CHUNK_EXTRACT(pcChunkBuffer,iChunkVersion,int);

	Asura_Assertf( iChunkVersion<=s_iCurrentChunkVersion,("Chunk version '%i' not yet supported",iChunkVersion) );

	// Load the active flag.
	PARENT::InitialiseFromChunkBuffer(pcChunkBuffer);
	SetNeverUpdates(true); // Reset this as it has been stomped on by the parent.

	// Check the version and skip the appropriate number of bytes. All the volume data is
	// stored in the client entity.
	Asura_CameraMultiVolume::SkipChunk(pcChunkBuffer);
}

////////////
// Update //
////////////
void Asura_ServerEntity_CameraVolume::Update()
{
	// MGH 5/9/2006: Camera volumes never need to be updated.
	// Don't add them to the updateable list as it is a waste of CPU time.
	Asura_Assert(0, "CameraVolume shouldn't be in update list");
}

///////////////////
// HandleMessage //
///////////////////
bool Asura_ServerEntity_CameraVolume::HandleMessage(const Asura_Message* pxMessage)
{
	if (!pxMessage) return false;

	if ( IsDestroyed() )
	{
		// MGH 5/9/2006: This shouldn't happen as we aren't allowing camera volumes to be
		// destroyed except when we are unloading a zone/level. However I'll leave it here in
		// case someone changes the behaviour later.
		return true; // ignore all further messages?
	}

	switch (pxMessage->GetMsgID())
	{
		default:
			Asura_Assert(0, "Unhandled message for server CameraVolume!");
			break;

		case ASURA_MSG_ACTIVATE:
		{
			if (!IsActive())
			{
				OnActivation();
			}
			return true;
		}
		case ASURA_MSG_DEACTIVATE:
		{
			if (IsActive())
			{
				OnDeactivation();
			}
			return true;
		}
	}

	return false;
}

//////////////////////////////////
// SetActiveFlagAndUpdateClient //
//////////////////////////////////
void Asura_ServerEntity_CameraVolume::SetActiveFlagAndUpdateClient(bool bActive)
{
	// Change the active flag, but don't add this entity to the updateable list.
	SetInternalActiveFlag_WithoutChangingUpdateList(bActive);

	// Send a message to the client informing it that the active status has changed.
	const u_short uMsgID = static_cast<u_short>(bActive ? ASURA_MSG_ACTIVATE : ASURA_MSG_DEACTIVATE);
	Asura_Message* pxMessage = Asura_Network::CreateMessage(uMsgID);
	if (pxMessage)
	{
		pxMessage->To = ASURA_GUID_MY_CLIENT_ENTITIES;
		pxMessage->From = Guid;
		pxMessage->UseGuaranteedDelivery();
		Asura_Network::Send(pxMessage);
	}
}

#endif //#ifdef ASURA_USE_CAMERA_VOLUME
