///////////////////////////////////////////////////////////////////////////////
//
// File: Asura_ClientEntity_CameraVolume.h
//
// 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.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_CLIENT_ENTITY_CAMERA_VOLUME_H__
#define __ASURA_CLIENT_ENTITY_CAMERA_VOLUME_H__

#ifdef ASURA_USE_CAMERA_VOLUME

// Includes
#include "Entity/Triggers/Asura_ClientEntity_Activatable.h"
#include "Core/Asura_OrientedVolume.h"

// Forward declarations
class Asura_Message;
class Tools_EntityTemplateInstance;

// Constants
const int iASURA_CAMERA_VOLUME_DEFAULT_PRIORITY = 50;

/////////////////////////////
// Asura_CameraMultiVolume //
/////////////////////////////
// Multi-volume consisting of a number of orientated BB.
class Asura_CameraMultiVolume
{
public:
	Asura_CameraMultiVolume();
	virtual ~Asura_CameraMultiVolume();

	// Accessors
	int GetNumVolumes() const { return m_iNumOBB; }
	int GetPriority() const   { return m_iPriority; }

	const Asura_OrientedVolume* GetVolume(const int iIndex) const
	{
		return (iIndex>=0 && iIndex<m_iNumOBB) ? &m_pxVolumes[iIndex] : 0;
	}

	Asura_OrientedVolume* GetVolume(const int iIndex)
	{
		return (iIndex>=0 && iIndex<m_iNumOBB) ? &m_pxVolumes[iIndex] : 0;
	}

	// Displace all the boxes by the specified offset.
	void Displace(const Asura_Vector_3& xMove);

	// Assignment
	Asura_CameraMultiVolume& operator=(const Asura_CameraMultiVolume& xOther);

	// Does the multi-volume contain the specified point?
	bool Contains(const Asura_Vector_3& xPosition) const;

	// chunk stream functions
	virtual	void ReadFromChunkStream( Asura_Chunk_Stream& xStream );
	virtual	void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;

	// Chunk buffer functions
	int	 GetChunkBufferSize() const;
	void FillInChunkBuffer(char*& pcChunkBuffer);
	void InitialiseFromChunkBuffer(const char*& pcChunkBuffer);

	// Fallback code for when the client entity is missing (ie chunk data version = 0).
	static void FillInChunkBuffer_V0(char*& pcChunkBuffer);
	static int GetChunkBufferSize_V0();

	// Allow server entities to skip the relevant number of bytes.
	static void SkipChunkStream( Asura_Chunk_Stream& xStream );
	static void SkipChunk(const char*& pcChunkBuffer);

	// Tools functions
#ifdef ASURA_TOOLS
	void AddVolume(); // Add a new volume at the end, with default values.
	void DeleteVolume(const int iIndex); // Delete the specified volume.
	void SetPriority(int iPriority) { m_iPriority = iPriority; }
	void ApplyChangesForTemplateInstance(Tools_EntityTemplateInstance* pxInstance);
#endif //ASURA_TOOLS

private:
	// private member data
	int m_iNumOBB;
	Asura_OrientedVolume* m_pxVolumes;
	int m_iPriority; // Priority 0-100

	// private static data
	static const int s_iCurrentChunkVersion;
};

/////////////////////////////////////
// Asura_ClientEntity_CameraVolume //
/////////////////////////////////////
class Asura_ClientEntity_CameraVolume : public Asura_ClientEntity_Activatable
{
	typedef Asura_ClientEntity_Activatable PARENT;

public:
	virtual ~Asura_ClientEntity_CameraVolume();

	virtual	void ReadFromChunkStream( Asura_Chunk_Stream& xStream );
	virtual bool HandleMessage(const Asura_Message* pxMessage);

	virtual void Update(); // Unused

#ifdef ASURA_TOOLS
	virtual void ApplyChangesForTemplateInstance(Tools_EntityTemplateInstance* pxInstance);
#endif //ASURA_TOOLS

	const Asura_CameraMultiVolume& GetMultiVolume() const { return m_xVolume; }

	virtual void SetOwnerGuid(const Asura_Guid uOwnerGuid) { m_uOwnerGuid = uOwnerGuid; }
	virtual Asura_Guid GetOwnerGuid() { return m_uOwnerGuid; }

	// Static members
	static Asura_ClientEntity_CameraVolume* FindEntity(Asura_Guid uGuid) { return s_xList.FindEntity(uGuid); }

	static const Asura_Hashed_List<Asura_ClientEntity_CameraVolume>* GetList() { return &s_xList; }

	// Find the most relevant camera volume, given the position and previous camera volume.
	// Note that this might return null if no volumes are found.
	static const Asura_ClientEntity_CameraVolume* FindVolume(const Asura_Vector_3& xPosition, const Asura_Guid uPreviousVolume, const Asura_Guid uGuidRequesting);

protected:
	Asura_ClientEntity_CameraVolume(Asura_Guid uGuid);
	Asura_ClientEntity_CameraVolume(Asura_Guid uGuid, const char*& pcChunkBuffer);

	// If the entity is active, the position is within the multi-volume and has higher priority
	// then update the priority and return true.
	virtual bool CheckVolume(const Asura_Vector_3& xPosition, int& iPriority, Asura_Guid uGuidRequesting = ASURA_GUID_UNREGISTERED) const;

	Asura_CameraMultiVolume m_xVolume; // Multi-volume data.

	// In some situations, when a player has activated a camera volume we want to forbid another player from triggering the same.
	// If this is ASURA_GUID_UNREGISTERED, the camera volume is assumed to apply to all of them.
	Asura_Guid m_uOwnerGuid;

private:	
	// Static data
	static Asura_Hashed_List<Asura_ClientEntity_CameraVolume> s_xList;

	static const int s_iCurrentChunkVersion;

	// Friends
	friend class Asura_ServerEntity_CameraVolume;
	friend class Tools_CameraVolume_VolumeEdit_Controller;
	friend class Tools_Entity_CameraVolume;
};
#endif //ASURA_USE_CAMERA_VOLUME

#endif //__ASURA_CLIENT_ENTITY_CAMERA_VOLUME_H__

