////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2005.
// -------------------------------------------------------------------------
//  File name:   ProximityTriggerSystem.h
//  Version:     v1.00
//  Created:     5/12/2005 by Timur.
//  Compilers:   Visual Studio.NET 2003
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef __ProximityTriggerSystem_h__
#define __ProximityTriggerSystem_h__
#pragma once

class CTriggerProxy;
class RadixSort;

//////////////////////////////////////////////////////////////////////////
struct SProximityElement
{
	//////////////////////////////////////////////////////////////////////////
	EntityId id;
	AABB aabb;
	uint32 bActivated : 1;
	DynArray<SProximityElement*> inside;

	SProximityElement()
	{
		id = 0;
		bActivated = 0;
	}
	~SProximityElement()
	{
	}
	bool AddInside( SProximityElement *elem )
	{
		// Sorted add.
		return stl::binary_insert_unique( inside,elem );
	}
	bool RemoveInside( SProximityElement *elem )
	{
		// sorted remove.
		return stl::binary_erase( inside,elem );
	}
	bool IsInside( SProximityElement *elem )
	{
		return std::binary_search(inside.begin(),inside.end(),elem );
	}

	//////////////////////////////////////////////////////////////////////////
	// Custom new/delete for pool allocator.
	//////////////////////////////////////////////////////////////////////////
	ILINE void* operator new( size_t nSize );
	ILINE void operator delete( void *ptr );
};

//////////////////////////////////////////////////////////////////////////
struct SProximityEvent
{
	bool bEnter; // Enter/Leave.
	EntityId entity;
	SProximityElement *pTrigger;
};

//////////////////////////////////////////////////////////////////////////
class CProximityTriggerSystem
{
public:
	CProximityTriggerSystem();
	~CProximityTriggerSystem();

	SProximityElement* CreateTrigger();
	void RemoveTrigger( SProximityElement *pTrigger );
	void MoveTrigger( SProximityElement *pTrigger,const AABB &aabb, bool invalidateCachedAABB=false);

	SProximityElement* CreateEntity( EntityId id );
	void MoveEntity( SProximityElement *pEntity,const Vec3 &pos );
	void RemoveEntity( SProximityElement *pEntity );

	void Update();
	void Reset();

private:
	void CheckIfLeavingTrigger( SProximityElement *pEntity );
	void ProcessOverlap( SProximityElement *pEntity,SProximityElement *pTrigger );
	void RemoveFromTriggers( SProximityElement *pEntity );
	void PurgeRemovedTriggers();
	void SortTriggers();
	void SendEvents();

private:
	typedef DynArray<SProximityElement*> Elements;

	Elements m_triggers;
	Elements m_triggersToRemove;
	bool m_bTriggerMoved;

	std::vector<SProximityElement*> m_entities;
	std::vector<AABB> m_triggersAABB;

	std::vector<SProximityEvent> m_events;

	RadixSort *m_pTriggerSorter;
	RadixSort *m_pEntitySorter;

	std::vector<float> m_minPosList0;
	std::vector<float> m_minPosList1;
	const uint32* m_Sorted0;
	const uint32* m_Sorted1;

public:
	typedef stl::PoolAllocatorNoMT<sizeof(SProximityElement)> ProximityElement_PoolAlloc;
	static ProximityElement_PoolAlloc* g_pProximityElement_PoolAlloc;
};

//////////////////////////////////////////////////////////////////////////
inline void* SProximityElement::operator new( size_t nSize )
{
	void *ptr = CProximityTriggerSystem::g_pProximityElement_PoolAlloc->Allocate();
	if (ptr)
		memset( ptr,0,nSize ); // Clear objects memory.
	return ptr;
}
//////////////////////////////////////////////////////////////////////////
inline void SProximityElement::operator delete( void *ptr )
{
	if (ptr)
		CProximityTriggerSystem::g_pProximityElement_PoolAlloc->Deallocate(ptr);
}


#endif // __ProximityTriggerSystem_h__
