///////////////////////////////////////////////////////////////////////////////
//
// File: AVP_ServerEntity_Container.h
//
// Created by Martin G.Harris (20/8/2008)
// 
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
// Project-specific server entity that manages a container instance.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __AVP_SERVERENTITY_CONTAINER_H__
#define __AVP_SERVERENTITY_CONTAINER_H__

#ifdef ASURA_USE_CONTAINER_SYSTEM

// Includes
#include "Entity/Container/Asura_ServerEntity_Container.h"

// Forward declarations
class AVP_EntityDamage_RequestVictim;
class Asura_ClientContainerInstance;

////////////////////////////////
// AVP_ServerEntity_Container //
////////////////////////////////
class AVP_ServerEntity_Container : public Asura_ServerEntity_Container
{
	typedef Asura_ServerEntity_Container PARENT;

public:
	explicit AVP_ServerEntity_Container(Asura_Guid uGuid);
	virtual ~AVP_ServerEntity_Container();

	virtual void Update();

	virtual bool HandleMessage(const Asura_Message* pxMessage);

	// Apply damage.
	void TakeDamageExtended(const AVP_EntityDamage_RequestVictim& xDamage, const bool bForceFatal, const bool bSendMessageToClient=true);

    // Reads this entity from the specified chunk-stream.
	virtual	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);

    // Writes this entity to the specified chunk-stream.
	virtual	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;

	// Get a bounding box and rough luminance value for the lights in the container.
	// Used to calculate the effect of lighting on waypoints.
	void SetLightingBB( Asura_Bounding_Box& xBB ) const;
	float GetContainerLuminance(const Asura_Vector_3& xPosition, const Asura_Vector_3& xNormal) const;

	void InvalidateLightingBB();

	bool SetIgnoredForSurfaceReorientation(bool bIgnore);
	bool IsIgnoredForSurfaceReorientation() const { return m_bIgnoreForSurfaceReorientation; }

	// Number of project-specific bytes to append to create message.
	virtual u_int GetNumBytesForProjectCreateMessageData() const { return 1; }

	// Fill in the specified number of bytes of project-specific data.
	virtual void FillProjectCreateMessageData(void* pData) const;

	// Find the blueprint in the root collection of the entity with the specified Guid.
	// If uBlueprintTypeHash != ASURA_HASH_ID_UNSET, then only return blueprints of the specified type.
	// Returns NULL if no relevant blueprint found.
	static const Asura_Container_Blueprint* FindBlueprintFromGuid(Asura_Guid uGuid, Asura_Hash_ID uBlueprintTypeHash);

protected:
	virtual void OnEntityActivateMessage();
	virtual void OnEntityDeactivateMessage();

	// Called on state change caused by receiving a state-change or activate message, or due to damage.
	virtual void PreStateChange();
	virtual void PostStateChange();

	void InitLightingBB() const;
	void UpdateLightingBB() const;
	void SendLightChangeMessage() const;

private:
	// Flags
	union
	{
		u_int m_uProjectFlags;	// Flags are saved out in chunk so don't reorder.

		struct
		{
			u_int m_bIgnoreForSurfaceReorientation	: 1;	// Should ignore this entity for surface reorientation?

			// Cached data concerning the lighting BB. Saved out in chunk, but ignored upon loading.
			mutable u_int m_bInitialisedLightingBB	: 1;	// Has initialised the lighting BB yet?
			mutable u_int m_bHasLights				: 1;	// Are any lights (photons or projectors) currently active?
			mutable u_int m_bPreviousHasLights		: 1;	// Were there any lights (photons or projectors) in the previous state?
		};
	};
	
	// Store a BB for the volume affected by the change in lighting (photons and projectors).
	// This is roughly a union of the BB for the current lighting and that for the previous state's lighting.
	mutable Asura_Bounding_Box m_xLightingBB;
	mutable Asura_Bounding_Box m_xPrevLightingBB;

	float m_fLightingTimer;
	Asura_Quat m_xOldOrientation;
	Asura_Vector_3 m_xOldPosition;

public:
	// Static members
	static AVP_ServerEntity_Container* FindEntity( Asura_Guid uGuid )
	{
		return static_cast<AVP_ServerEntity_Container*>(PARENT::FindEntity(uGuid)); 
	}

	// Friends
	friend class ToolsAVP_Entity_Container;
};

#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM

#endif //__AVP_SERVERENTITY_CONTAINER_H__

