//===========================================================================//
// File:	collasst.cc                                                         //
// Project: MUNGA           Brick: Collision											  //
// Contents: 																					  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 02/17/95	 ECH	Initial coding															  //
//---------------------------------------------------------------------------//
// Copyright (C) 1994, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include <munga.hpp>
#pragma hdrstop

#if !defined(COLLASST_HPP)
#	include <collasst.hpp>
#endif

#if !defined(MOVER_HPP)
#	include <mover.hpp>
#endif

#if !defined(APP_HPP)
	#include <app.hpp>
#endif

#if !defined(INTEREST_HPP)
	#include <interest.hpp>
#endif

//
//#############################################################################
// Make
//#############################################################################
//
CollisionAssistant*
	CollisionAssistant::Make(Mover *mover)
{
	Check(mover);

   //
	// Create the collision assistant
	//
   CollisionAssistant *collision_assistant;

   collision_assistant = new CollisionAssistant(mover->GetInterestZoneID());
   Check(collision_assistant);
   return collision_assistant;
}

//
//#############################################################################
// CollisionAssistant
//#############################################################################
//
CollisionAssistant::CollisionAssistant(InterestZoneID interest_zone_ID):
   collisionOriginSocket(NULL)
{
	Verify(interest_zone_ID != NullInterestZoneID);
	currentInterestZoneID = interest_zone_ID;
	LinkToInterestZone(interest_zone_ID);
}

//
//#############################################################################
// ~CollisionAssistant
//#############################################################################
//
CollisionAssistant::~CollisionAssistant()
{
}

//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
	CollisionAssistant::TestInstance() const
{
	Node::TestInstance();
   Verify(currentInterestZoneID != NullInterestZoneID);
   Check(&collisionOriginSocket);
	return True;
}

//
//#############################################################################
// Update
//#############################################################################
//
void
	CollisionAssistant::Update(InterestZoneID interest_zone_ID)
{
	Check(this);
   Verify(interest_zone_ID != NullInterestZoneID);

   if (interest_zone_ID == currentInterestZoneID)
   	return;
   currentInterestZoneID = interest_zone_ID;

	//
   // Remove current collision origin and link to new one
	//
   if (collisionOriginSocket.GetCurrent() != NULL)
   {
   	collisionOriginSocket.Remove();
   }
	LinkToInterestZone(interest_zone_ID);
}

//
//#############################################################################
// LinkToInterestZone
//#############################################################################
//
void
	CollisionAssistant::LinkToInterestZone(InterestZoneID interest_zone_ID)
{
	Check(this);
	Verify(interest_zone_ID != NullInterestZoneID);

	//
	//--------------------------------------------------------------------------
   // Does the interest zone have a collision origin?
   //--------------------------------------------------------------------------
   //
   InterestZone *interest_zone;
   CollisionOrigin *collision_origin;

   Check(application);
   Check(application->GetInterestManager());
   interest_zone =
		application->GetInterestManager()->GetInterestZone(interest_zone_ID);
	Check(interest_zone);

	collision_origin = interest_zone->GetCollisionOrigin();
	if (collision_origin == NULL)
   {
      //
      // It does not, so create one
      //
      collision_origin = new CollisionOrigin(interest_zone_ID);
      Register_Object(collision_origin);
      interest_zone->AdoptCollisionOrigin(collision_origin);

      application->GetInterestManager()->AdoptInterestOrigin(collision_origin);
   }
   Check(collision_origin);

   //
   // link to the collision origin
   //
   collisionOriginSocket.Add(collision_origin);
}

//~~~~~~~~~~~~~~~~~ CollisionAssistant__MovingEntityIterator ~~~~~~~~~~~~~~~~~~

CollisionAssistant__MovingEntityIterator::
	CollisionAssistant__MovingEntityIterator(
		CollisionAssistant *collision_assistant
   ):
	CollisionOrigin__MovingEntityIterator(
   	collision_assistant->collisionOriginSocket.GetCurrent()
   )
{
}

CollisionAssistant__MovingEntityIterator::
	~CollisionAssistant__MovingEntityIterator()
{
}

#if 0
//
//#############################################################################
// Make
//#############################################################################
//
CollisionAssistant*
	CollisionAssistant::Make(Mover *mover)
{
	Check(mover);

   //
	//-----------------------------------------------------------------------
	// Create the collision assistant
	//-----------------------------------------------------------------------
	//
   CollisionAssistant *collision_assistant;

   Check(application);
   collision_assistant = new CollisionAssistant(
   	application->GetApplicationLoopFrameRate()
   );
   Check(collision_assistant);

   //
	//-----------------------------------------------------------------------
	// Prime the collision assistant
	//-----------------------------------------------------------------------
	//
	collision_assistant->LinkToMover(mover);
	collision_assistant->LoadMission(NULL); // JM - This should work...

   return collision_assistant;
}

//
//#############################################################################
// CollisionAssistant
//#############################################################################
//
CollisionAssistant::CollisionAssistant(RendererRate render_rate):
	Renderer(
		render_rate,
		MaxRendererComplexity,
		DefaultRendererPriority,
		CollisionInterestType,
		DefaultInterestDepth,
		CollisionAssistantClassID
	),
   movingEntitySocket(NULL)
{
}

//
//#############################################################################
// ~CollisionAssistant
//#############################################################################
//
CollisionAssistant::~CollisionAssistant()
{
   Suspend();
   UnlinkFromEntity();
   Shutdown();
}

//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
	CollisionAssistant::TestInstance() const
{
	Renderer::TestInstance();
   Check(&movingEntitySocket);
	return True;
}

//
//#############################################################################
// LinkToEntity
//#############################################################################
//
void
	CollisionAssistant::LinkToMover(Mover *mover)
{
	Check(this);
	Check(mover);

	//
	// Call inherited method
	//
	Renderer::LinkToEntity(mover);

   //
   //-----------------------------------------------------------------
   // Tell the entity that is collisionable here ...
   //-----------------------------------------------------------------
	//
}

//
//#############################################################################
// NotifyOfNewInterestingEntity
//#############################################################################
//
void
	CollisionAssistant::NotifyOfNewInterestingEntity(
		Entity *interesting_entity
	)
{
	Check(this);
	Check(interesting_entity);

	//
	//-------------------------------------------------------------------------
	// Make sure that we don't check against ourself our against something that
	// doesn't move
	//-------------------------------------------------------------------------
	//
	if (
		interesting_entity != GetLinkedEntity()
		 && interesting_entity->IsDynamic()
	)
	{

		//
		//-------------------------------------------------------------
		// If it is a mover and tangible, or a door, add it to our list
		//-------------------------------------------------------------
		//
		if (interesting_entity->IsDerivedFrom(Mover::ClassDerivations))
		{
			Mover *mover = Cast_Object(Mover*, interesting_entity);
			if (mover->IsTangible())
			{
				goto Add_Entity;
			}
		}
		else if (interesting_entity->IsDerivedFrom(DoorFrame::ClassDerivations))
		{
Add_Entity:
			movingEntitySocket.Add(interesting_entity);
		}
	}
}

//
//#############################################################################
// NotifyOfBecomingUninterestingEntity
//#############################################################################
//
void
	CollisionAssistant::NotifyOfBecomingUninterestingEntity(
		Entity *uninteresting_entity
	)
{
	//
	// HACK - ECH The following may not be a legitimate assertion
	//
	#if DEBUG_LEVEL>0 && 0
	{
		SChainIteratorOf<Mover*> iterator(&movingEntitySocket);
		Verify(iterator.IsPlugMember(uninteresting_entity) == True);
	}
	#endif

	//
	// Remove from socket
	//
	PlugIterator iterator(uninteresting_entity);

	iterator.RemoveSocket(&movingEntitySocket);
}

//
//#############################################################################
// GetCollisionRoot
//#############################################################################
//
BoxedSolidTree*
   CollisionAssistant::GetCollisionRoot()
{
	Check(GetInterestOrigin());
	Check(GetInterestOrigin()->GetInterestArena());
	return GetInterestOrigin()->GetInterestArena()->GetCollisionRoot();
}

//
//#############################################################################
// ExecuteImplementation
//#############################################################################
//
void
	CollisionAssistant::ExecuteImplementation(
		RendererComplexity,
		InterestOrigin::InterestingEntityIterator*
	)
{
}

//~~~~~~~~~~~~~~~~~ CollisionAssistant__MovingEntityIterator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

CollisionAssistant__MovingEntityIterator::
	CollisionAssistant__MovingEntityIterator(
		CollisionAssistant *collision_assistant
   ):
	SChainIteratorOf<Entity*>(collision_assistant->movingEntitySocket)
{
}

CollisionAssistant__MovingEntityIterator::
	~CollisionAssistant__MovingEntityIterator()
{
}
#endif
