//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include "prop_portal_shared.h"
#include "portal_collideable_enumerator.h"

#define PORTAL_TELEPORTATION_PLANE_OFFSET 7.0f

CPortalCollideableEnumerator::CPortalCollideableEnumerator( const CProp_Portal *pAssociatedPortal )
{
	Assert( pAssociatedPortal );
	m_hTestPortal = pAssociatedPortal;

	pAssociatedPortal->GetVectors( &m_vPlaneNormal, NULL, NULL );

	m_ptForward1000 = pAssociatedPortal->GetAbsOrigin();
	m_ptForward1000 += m_vPlaneNormal * PORTAL_TELEPORTATION_PLANE_OFFSET;
	m_fPlaneDist = m_vPlaneNormal.Dot( m_ptForward1000 );

	m_ptForward1000 += m_vPlaneNormal * 1000.0f;

	m_iHandleCount = 0;
}

IterationRetval_t CPortalCollideableEnumerator::EnumElement( IHandleEntity *pHandleEntity )
{
	EHANDLE hEnt = pHandleEntity->GetRefEHandle();
	
	CBaseEntity *pEnt = hEnt.Get();
	if( pEnt == NULL ) //I really never thought this would be necessary
		return ITERATION_CONTINUE;
	
	if( hEnt == m_hTestPortal )
		return ITERATION_CONTINUE; //ignore this portal

	/*if( staticpropmgr->IsStaticProp( pHandleEntity ) )
	{
		//we're dealing with a static prop, which unfortunately doesn't have everything I want to use for checking
		
		ICollideable *pCollideable = pEnt->GetCollideable();

		Vector vMins, vMaxs;
		pCollideable->WorldSpaceSurroundingBounds( &vMins, &vMaxs );

		Vector ptTest( (m_vPlaneNormal.x > 0.0f)?(vMaxs.x):(vMins.x),
						(m_vPlaneNormal.y > 0.0f)?(vMaxs.y):(vMins.y),
						(m_vPlaneNormal.z > 0.0f)?(vMaxs.z):(vMins.z) );
	
		float fPtPlaneDist = m_vPlaneNormal.Dot( ptTest ) - m_fPlaneDist;
		if( fPtPlaneDist <= 0.0f )
			return ITERATION_CONTINUE;
	}
	else*/
	{
		//not a static prop, w00t
		CCollisionProperty *pEntityCollision = pEnt->CollisionProp();

		if( !pEntityCollision->IsSolid() )
			return ITERATION_CONTINUE; //not solid

		Vector ptEntCenter = pEntityCollision->WorldSpaceCenter();

		float fBoundRadius = pEntityCollision->BoundingRadius();
		float fPtPlaneDist = m_vPlaneNormal.Dot( ptEntCenter ) - m_fPlaneDist;

		if( fPtPlaneDist < -fBoundRadius )
			return ITERATION_CONTINUE; //object wholly behind the portal

		if( !(fPtPlaneDist > fBoundRadius) && (fPtPlaneDist > -fBoundRadius) ) //object is not wholly in front of the portal, but could be partially in front, do more checks
		{
			Vector ptNearest;
			pEntityCollision->CalcNearestPoint( m_ptForward1000, &ptNearest );
			fPtPlaneDist = m_vPlaneNormal.Dot( ptNearest ) - m_fPlaneDist;
			if( fPtPlaneDist < 0.0f )
				return ITERATION_CONTINUE; //closest point was behind the portal plane, we don't want it
		}


	}

	//if we're down here, this entity needs to be added to our enumeration
	Assert( m_iHandleCount < 1024 );
	if( m_iHandleCount < 1024 ) 
		m_pHandles[m_iHandleCount] = pHandleEntity;
	++m_iHandleCount;

	return ITERATION_CONTINUE;
}