//
// Asura_ServerEntity_Activatable.cpp
//
// Created by Richard Rice - 18/09/2002
// 
// Copyright (C) 2002 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Entity/Triggers/Asura_ServerEntity_Activatable.h"

// Engine independent.
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#ifdef ASURA_SUPPORT_ENTITYWATCH
#include "Entity/Asura_EntityWatch_System.h"
#endif
#include "Debugging/Asura_Assert.h"
#include "Network/Asura_Message.h"

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

////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------------**
** Asura_ServerEntity_Activatable **
**--------------------------------*/

static const int iASURA_SERVERENTITY_ACTIVATABLE_VERSION_NUMBER	= 3;


Asura_ServerEntity_Activatable::Asura_ServerEntity_Activatable(bool bActive /*= true*/)
#if defined(ASURA_TOOLS)
: Asura_Entity_Server(Asura_Entity_System::GetCreatedByToolsGuid())
#else
: Asura_Entity_Server(ASURA_GUID_UNREGISTERED)
#endif	// defined(ASURA_TOOLS)
{
	SetInternalActiveFlag(bActive);
	SetNeverUpdateClient();
}

Asura_ServerEntity_Activatable::Asura_ServerEntity_Activatable(Asura_Guid uGuid,const char*& pcChunkBuffer)
:Asura_Entity_Server(uGuid)
{
    bool bActive;
    ParseChunkBuffer(pcChunkBuffer, &bActive, this);

	SetInternalActiveFlag(bActive);
	SetNeverUpdateClient();
}

Asura_ServerEntity_Activatable::Asura_ServerEntity_Activatable(Asura_Guid uGuid)
:Asura_Entity_Server(uGuid)
{
	SetInternalActiveFlag(true);
	SetNeverUpdateClient();
}

int Asura_ServerEntity_Activatable::GetChunkBufferSize()
{
	return Asura_Entity_Server::GetChunkBufferSize() 
			+sizeof(int)
			+sizeof(unsigned int);//version number+initially active
}

void Asura_ServerEntity_Activatable::FillInChunkBuffer(char*& pcChunkBuffer)
{

	int iVersion = iASURA_SERVERENTITY_ACTIVATABLE_VERSION_NUMBER;
	ASURA_CHUNK_FILLANDVERIFY( pcChunkBuffer, iVersion,int);

	Asura_Entity_Server::FillInChunkBuffer(pcChunkBuffer);

	unsigned int uActive = IsActive();
	ASURA_CHUNK_FILLANDVERIFY( pcChunkBuffer, uActive,unsigned int);
}

void Asura_ServerEntity_Activatable::WriteToChunkStream (Asura_Chunk_Stream& xStream) const
{
	const u_int	uActive	= IsActive();


	// Write the data...

	xStream << iASURA_SERVERENTITY_ACTIVATABLE_VERSION_NUMBER;
	Asura_Entity_Server::WriteToChunkStream(xStream);

	xStream << uActive;
}


void Asura_ServerEntity_Activatable::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	u_int	uActive;

	// Read the data...
	int iVersion;
	xStream >> iVersion;
	Asura_Assertf(iVersion <= iASURA_SERVERENTITY_ACTIVATABLE_VERSION_NUMBER,("Unknown chunk version %d for Asura_ServerEntity_Activatable",iVersion));

	if(iVersion >= 3)
	{
		Asura_Entity_Server::ReadFromChunkStream(xStream);
	}

	xStream >> uActive;
	SetInternalActiveFlag( uActive == 0 ? false : true );

}


// non-virtual function used to cope with Asura_ClientEntity_SoundController
// being derived from Asura_Entity_Client instead of a client equivalent of this
// class. This allows the chunk buffer to be read in order to move the chunk data
// pointer past the data and to extract any useful info, e.g. bInitiallyActive
void Asura_ServerEntity_Activatable::ParseChunkBuffer(const char*& pcChunkBuffer, 
                                                      bool* pbActive,
                                                      Asura_Entity_Server* pxServerEntity)
{
	Asura_Chunk_ChunkBuffer_Stream xStream(pcChunkBuffer);
	ParseChunkStream(xStream, pbActive, pxServerEntity);
}

void Asura_ServerEntity_Activatable::ParseChunkStream(Asura_Chunk_Stream& xStream, 
                                                      bool* pbActive,
                                                      Asura_Entity_Server* pxServerEntity)
{
	//check the version
	int iVersion;
	xStream >> iVersion;
	if(iVersion==1)
	{
		//Version 1 is used by the trigger strategy before this class was inserted as a parent.
		//Unfortunately there isn't any way to move backwards in a general chunk stream , we are a bit
		//stuck here.
		//However this should only affect entities that haven't been saved since 2002
		//So this ought be okay...
		//RAR 12/11/2007
		Asura_Assert(0,"Ancient activatable entity.... loading will be screwed up.");
		return;
	}
	Asura_Assert(iVersion >= 2 && iVersion <= iASURA_SERVERENTITY_ACTIVATABLE_VERSION_NUMBER,"");

	if(iVersion >= 3)
	{
		//skip/parse parent class data as needed
		if(pxServerEntity)
		{
			pxServerEntity->Asura_Entity_Server::ReadFromChunkStream(xStream);
		}
		else
		{
			Asura_Entity_Server::SkipDataInChunkStream(xStream);
		}
	}


	unsigned int uActive;
	xStream >> uActive;

    *pbActive = uActive != 0;
}


void Asura_ServerEntity_Activatable::InitialiseFromChunkBuffer(const char*& pcChunkBuffer)
{
    bool bActive;
    ParseChunkBuffer(pcChunkBuffer, &bActive, this);

	SetInternalActiveFlag(bActive);
}

bool Asura_ServerEntity_Activatable::HandleMessage(const Asura_Message* pxMessage)
{
    if( IsDestroyed() ) { return true; } // ignore all further messages?

	if (pxMessage)
	{
		switch (pxMessage->GetMsgID())
		{
			default:
			{
				break;
			}

			case ASURA_MSG_DESTRUCT:
			{
				OnDestruction();
				SetInternalActiveFlag(false);

				Asura_Assert(IsDestroyed(), "Destroy message hasn't destroyed this activatable object. Check the OnDestruction function calls the parent or consider changing the message handling to always set as destroyed.");

				return true;
			}
			case ASURA_MSG_ACTIVATE:
			{
				if (!IsActive())
				{
					OnActivation();
					SetInternalActiveFlag(true);
				}
				return true;
			}
			case ASURA_MSG_DEACTIVATE:
			{
				if (IsActive())
				{
					OnDeactivation();
					SetInternalActiveFlag(false);
				}
				return true;
			}
			case ASURA_MSG_TRIGGER:
			{
				if (IsActive())
				{
					OnTrigger();
				}
				return true;
			}
			case ASURA_MSG_UNTRIGGER:
			{
				if (IsActive())
				{
					OnUnTrigger();
				}
				return true;
			}
		}
	}

	return PARENT::HandleMessage(pxMessage);
}



void Asura_ServerEntity_Activatable::OnActivation()
{
	SetInternalActiveFlag(true);
}

void Asura_ServerEntity_Activatable::OnDeactivation()
{
	SetInternalActiveFlag(false);
}


void Asura_ServerEntity_Activatable::OnDestruction()
{
	SetAsDestroyed();
	SetInternalActiveFlag(false);
}


#ifdef ASURA_SUPPORT_ENTITYWATCH
void Asura_ServerEntity_Activatable::DisplayEntityWatchText()
{
	Asura_EntityWatch_System::PrintText(16,"Active : %s",IsActive() ? "Yes" : "No");
}
#endif //ASURA_SUPPORT_ENTITYWATCH

////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------------------------------**
** Asura_ServerEntity_ActivatableWithPosition **
**--------------------------------------------*/

Asura_Hashed_List<Asura_ServerEntity_ActivatableWithPosition> Asura_ServerEntity_ActivatableWithPosition::s_xList(4);
static const int iASURA_SERVERENTITY_ACTIVATABLEWITHPOSITION_VERSION_NUMBER	= 0;

Asura_ServerEntity_ActivatableWithPosition::Asura_ServerEntity_ActivatableWithPosition(Asura_Guid uGuid /*= ASURA_GUID_UNREGISTERED*/)
:Asura_ServerEntity_Activatable(uGuid)
{
	m_xPosition.Zero();
	m_xOrientation.Identity();

	s_xList.AddToList(this);
}

Asura_ServerEntity_ActivatableWithPosition::~Asura_ServerEntity_ActivatableWithPosition()
{
	s_xList.RemoveFromList(this);
}

Asura_ServerEntity_ActivatableWithPosition::Asura_ServerEntity_ActivatableWithPosition(Asura_Guid uGuid,const char*& pcChunkBuffer)
:Asura_ServerEntity_Activatable(uGuid,pcChunkBuffer)
{
	//check the version
	int iVersion;
	ASURA_CHUNK_EXTRACT( pcChunkBuffer, iVersion,int);
	Asura_Assert(iVersion <= iASURA_SERVERENTITY_ACTIVATABLEWITHPOSITION_VERSION_NUMBER, "FATAL ERROR: unknown version number for Asura_ServerEntity_ActivatableWithPosition");

	ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_xPosition,Asura_Vector_3);
	ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_xOrientation,Asura_Matrix_3x3);

	s_xList.AddToList(this);
}

void Asura_ServerEntity_ActivatableWithPosition::InitialiseFromChunkBuffer(const char*& pcChunkBuffer)
{
	Asura_ServerEntity_Activatable::InitialiseFromChunkBuffer(pcChunkBuffer);

	//check the version
	int iVersion;
	ASURA_CHUNK_EXTRACT( pcChunkBuffer, iVersion,int);
	Asura_Assert(iVersion <= iASURA_SERVERENTITY_ACTIVATABLEWITHPOSITION_VERSION_NUMBER, "FATAL ERROR: unknown version number for Asura_ServerEntity_ActivatableWithPosition");

	ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_xPosition,Asura_Vector_3);
	ASURA_CHUNK_EXTRACT(pcChunkBuffer,m_xOrientation,Asura_Matrix_3x3);
}



int Asura_ServerEntity_ActivatableWithPosition::GetChunkBufferSize()
{
	return Asura_ServerEntity_Activatable::GetChunkBufferSize() 
		   + sizeof(int)//version
		   + sizeof(Asura_Vector_3)
		   + sizeof(Asura_Matrix_3x3);

}

void Asura_ServerEntity_ActivatableWithPosition::FillInChunkBuffer(char*& pcChunkBuffer)
{
	/*
	This entity type can be used in template files , so any changes to FillInChunkBuffer may
	require ApplyChangesForTemplateInstance() to be updated as well.
	Please see the comment at the top of Tools/EntityTemplate/Tools_EntityTemplate_System.h before 
	making any changes.
	RAR 29/04/2004
	*/
	Asura_ServerEntity_Activatable::FillInChunkBuffer(pcChunkBuffer);

	int iVersion = iASURA_SERVERENTITY_ACTIVATABLEWITHPOSITION_VERSION_NUMBER;
	
	ASURA_CHUNK_FILLANDVERIFY(pcChunkBuffer, iVersion, int);
	ASURA_CHUNK_ARRAY_FILLANDVERIFY(pcChunkBuffer, m_xPosition, Asura_Vector_3, float, 3);
	ASURA_CHUNK_ARRAY_FILLANDVERIFY(pcChunkBuffer,m_xOrientation,Asura_Matrix_3x3, float, 9);
}


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ServerEntity_ActivatableWithPosition::WriteToChunkStream
// Author       : Andy Tate
// Date         : 1-Sep-2005
//
// Description  : Writes this entity to the specified chunk-stream.
//
// Parameters   : A reference to the chunk-stream to write to.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_ServerEntity_ActivatableWithPosition::WriteToChunkStream (Asura_Chunk_Stream& xStream) const
{
	// Call the base-function...

	Asura_ServerEntity_Activatable::WriteToChunkStream	(xStream);


	// Write the data...

	xStream << iASURA_SERVERENTITY_ACTIVATABLEWITHPOSITION_VERSION_NUMBER;
	xStream << m_xPosition;
	xStream << m_xOrientation;
}

void Asura_ServerEntity_ActivatableWithPosition::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	Asura_ServerEntity_Activatable::ReadFromChunkStream(xStream);

	// Read the data...
	int iVersion;
	xStream >> iVersion;
	Asura_Assertf(iVersion <= iASURA_SERVERENTITY_ACTIVATABLEWITHPOSITION_VERSION_NUMBER,("Unknown chunk version %d for Asura_ServerEntity_Activatable",iVersion));

	xStream >> m_xPosition;
	xStream >> m_xOrientation;
}

/// End of function 'Asura_ServerEntity_ActivatableWithPosition::WriteToChunkStream'. ///

#ifdef ASURA_TOOLS

void Asura_ServerEntity_ActivatableWithPosition::ApplyChangesForTemplateInstance( Tools_EntityTemplateInstance* pxInstance )
{
	Asura_ServerEntity_Activatable::ApplyChangesForTemplateInstance(pxInstance);

	m_xPosition = pxInstance->TransformPosition( m_xPosition );
	m_xOrientation = pxInstance->TransformMatrix( m_xOrientation );
}

#endif

/// End of file. ///
