//
// Asura_Physics_Constraint.cpp
//
// Created by KJFL - 4 July 2007
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#ifdef ASURA_PHYSICS_SUPPORT_CONSTRAINTS

#include "Core/Asura.h"

// This file's header.
#include "Physics/Constraints/Asura_Physics_Constraint.h"

#include "Debugging/Asura_Assert.h"
#include "Physics/Asura_Physics_RigidBody.h"

Asura_Physics_Constraint::Asura_Physics_Constraint( Asura_Physics_RigidBodyInstance* pxBody1, Asura_Physics_RigidBodyInstance* pxBody2 )
: m_pxBody1( pxBody1 )
, m_pxBody2( pxBody2 )
{
	Asura_Assert( pxBody1, "Code Bug: there must be at least one body in a constraint" );

	// register this constraint with the bodies
	if (m_pxBody1) m_pxBody1->AddConstraint( this );
	if (m_pxBody2) m_pxBody2->AddConstraint( this );
}

Asura_Physics_Constraint::~Asura_Physics_Constraint()
{
	// unregister the constraint with the bodies
	if (m_pxBody1) m_pxBody1->RemoveConstraint( this );
	if (m_pxBody2) m_pxBody2->RemoveConstraint( this );
}


// Reset the body pointer and invalidate the constraint: called when one
// of the bodies in question is destroyed and the pointer becomes invalid.
void Asura_Physics_Constraint::RemoveBody( Asura_Physics_RigidBodyInstance* pxBody )
{
	if ( m_pxBody1 == pxBody )
	{
		m_pxBody1 = 0;
	}
	else if ( m_pxBody2 == pxBody )
	{
		m_pxBody2 = 0;
	}
	else
	{
		Asura_Assert( false, "Code Bug: invalid body for this constraint" );
	}
}

void Asura_Physics_Constraint_List::Add( Asura_Physics_Constraint* pxConstraint )
{
	// create a new node to hold the constraint, and add it to the head of the list
	Asura_Physics_Constraint_Node* pxNode = new Asura_Physics_Constraint_Node();

	pxNode->m_pxConstaint = pxConstraint;
	pxNode->m_pxNext = m_pxHeadOfList;

	m_pxHeadOfList = pxNode;
}

void Asura_Physics_Constraint_List::Remove( Asura_Physics_Constraint* pxConstraint )
{
	// remove a node, assert if not found

	Asura_Physics_Constraint_Node** ppxNextNode = &m_pxHeadOfList;

	// is there a non-null 'next pointer'?
	while ( ppxNextNode )
	{
		// access the node
		Asura_Physics_Constraint_Node* pxNode = *(ppxNextNode);

		// is this the one to remove?
		if (pxNode->GetConstraint() == pxConstraint )
		{
			// make the previous 'next pointer' point to the node following this one
			*ppxNextNode = pxNode->m_pxNext;

			// and destroy the node
			delete pxNode;

			return;
		}
		else
		{
			// move along to next node then
			ppxNextNode = &(pxNode->m_pxNext);
		}
	}

	Asura_Assert( false, "Code bug: constraint not found" );

}



void Asura_Physics_Constraint_List::ClearNodes( void )
{
	// delete any outstanding nodes
	Asura_Physics_Constraint_Node* pxNode = m_pxHeadOfList;

	while ( pxNode )
	{
		Asura_Physics_Constraint_Node* pxNextNode = pxNode->m_pxNext;
		delete pxNode;
		pxNode = pxNextNode;
	}

	m_pxHeadOfList = 0;
}


#endif

