/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

package classes.Box2D.Dynamics{


import classes.Box2D.Dynamics.*;
import classes.Box2D.Dynamics.Joints.*;
import classes.Box2D.Dynamics.Contacts.*;
import classes.Box2D.Collision.Shapes.*;
import classes.Box2D.Common.Math.*;
import classes.Box2D.Common.*;



/// A rigid body.
public class b2Body
{
	/// Creates a shape and attach it to this body.
	/// @param shapeDef the shape definition.
	/// @warning This function is locked during callbacks.
	public function CreateShape(def:b2ShapeDef) : b2Shape{
		//b2Settings.b2Assert(m_world.m_lock == false);
		if (m_world.m_lock == true)
		{
			return null;
		}
		
		var s:b2Shape = b2Shape.Create(def, m_world.m_blockAllocator);
		
		s.m_next = m_shapeList;
		m_shapeList = s;
		++m_shapeCount;
		
		s.m_body = this;
		
		// Add the shape to the world's broad-phase.
		s.CreateProxy(m_world.m_broadPhase, m_xf);
		
		// Compute the sweep radius for CCD.
		s.UpdateSweepRadius(m_sweep.localCenter);
		
		return s;
	}

	/// Destroy a shape. This removes the shape from the broad-phase and
	/// therefore destroys any contacts associated with this shape. All shapes
	/// attached to a body are implicitly destroyed when the body is destroyed.
	/// @param shape the shape to be removed.
	/// @warning This function is locked during callbacks.
	public function DestroyShape(s:b2Shape) : void{
		//b2Settings.b2Assert(m_world.m_lock == false);
		if (m_world.m_lock == true)
		{
			return;
		}
		
		//b2Settings.b2Assert(s.m_body == this);
		s.DestroyProxy(m_world.m_broadPhase);
		
		//b2Settings.b2Assert(m_shapeCount > 0);
		//b2Shape** node = &m_shapeList;
		var node:b2Shape = m_shapeList;
		var ppS:b2Shape = null; // Fix pointer-pointer stuff
		var found:Boolean = false;
		while (node != null)
		{
			if (node == s)
			{
				if (ppS)
					ppS.m_next = s.m_next;
				else
					m_shapeList = s.m_next;
				//node = s.m_next;
				found = true;
				break;
			}
			
			ppS = node;
			node = node.m_next;
		}
		
		// You tried to remove a shape that is not attached to this body.
		//b2Settings.b2Assert(found);
		
		s.m_body = null;
		s.m_next = null;
		
		--m_shapeCount;
		
		b2Shape.Destroy(s, m_world.m_blockAllocator);
	}

	/// Set the mass properties. Note that this changes the center of mass position.
	/// If you are not sure how to compute mass properties, use SetMassFromShapes.
	/// The inertia tensor is assumed to be relative to the center of mass.
	/// @param massData the mass properties.
	public function SetMass(massData:b2MassData) : void{
		var s:b2Shape;
		
		//b2Settings.b2Assert(m_world.m_lock == false);
		if (m_world.m_lock == true)
		{
			return;
		}
		
		m_invMass = 0.0;
		m_I = 0.0;
		m_invI = 0.0;
		
		m_mass = massData.mass;
		
		if (m_mass > 0.0)
		{
			m_invMass = 1.0 / m_mass;
		}
		
		if ((m_flags & b2Body.e_fixedRotationFlag) == 0)
		{
			m_I = massData.I;
		}
		
		if (m_I > 0.0)
		{
			m_invI = 1.0 / m_I;
		}
		
		// Move center of mass.
		m_sweep.localCenter.SetV(massData.center);
		//m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
		//b2MulMV(m_xf.R, m_sweep.localCenter);
		var tMat:b2Mat22 = m_xf.R;
		var tVec:b2Vec2 = m_sweep.localCenter;
		// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
		m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
		// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
		m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
		//return T.position + b2Mul(T.R, v);
		m_sweep.c.x += m_xf.position.x;
		m_sweep.c.y += m_xf.position.y;
		//m_sweep.c0 = m_sweep.c
		m_sweep.c0.SetV(m_sweep.c);
		
		// Update the sweep radii of all child shapes.
		for (s = m_shapeList; s; s = s.m_next)
		{
			s.UpdateSweepRadius(m_sweep.localCenter);
		}

		var oldType:int = m_type;
		if (m_invMass == 0.0 && m_invI == 0.0)
		{
			m_type = e_staticType;
		}
		else
		{
			m_type = e_dynamicType;
		}
	
		// If the body type changed, we need to refilter the broad-phase proxies.
		if (oldType != m_type)
		{
			for (s = m_shapeList; s; s = s.m_next)
			{
				s.RefilterProxy(m_world.m_broadPhase, m_xf);
			}
		}
	}

	/// Compute the mass properties from the attached shapes. You typically call this
	/// after adding all the shapes. If you add or remove shapes later, you may want
	/// to call this again. Note that this changes the center of mass position.
	static private var s_massData:b2MassData = new b2MassData();
	public function SetMassFromShapes() : void{
		
		var s:b2Shape;
		
		//b2Settings.b2Assert(m_world.m_lock == false);
		if (m_world.m_lock == true)
		{
			return;
		}
		
		// Compute mass data from shapes. Each shape has its own density.
		m_mass = 0.0;
		m_invMass = 0.0;
		m_I = 0.0;
		m_invI = 0.0;
		
		//b2Vec2 center = b2Vec2_zero;
		var centerX:Number = 0.0;
		var centerY:Number = 0.0;
		var massData:b2MassData = s_massData;
		for (s = m_shapeList; s; s = s.m_next)
		{
			s.ComputeMass(massData);
			m_mass += massData.mass;
			//center += massData.mass * massData.center;
			centerX += massData.mass * massData.center.x;
			centerY += massData.mass * massData.center.y;
			m_I += massData.I;
		}
		
		// Compute center of mass, and shift the origin to the COM.
		if (m_mass > 0.0)
		{
			m_invMass = 1.0 / m_mass;
			centerX *= m_invMass;
			centerY *= m_invMass;
		}
		
		if (m_I > 0.0 && (m_flags & e_fixedRotationFlag) == 0)
		{
			// Center the inertia about the center of mass.
			//m_I -= m_mass * b2Dot(center, center);
			m_I -= m_mass * (centerX * centerX + centerY * centerY);
			//b2Settings.b2Assert(m_I > 0.0);
			m_invI = 1.0 / m_I;
		}
		else
		{
			m_I = 0.0;
			m_invI = 0.0;
		}
		
		// Move center of mass.
		m_sweep.localCenter.Set(centerX, centerY);
		//m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
		//b2MulMV(m_xf.R, m_sweep.localCenter);
		var tMat:b2Mat22 = m_xf.R;
		var tVec:b2Vec2 = m_sweep.localCenter;
		// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
		m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
		// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
		m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
		//return T.position + b2Mul(T.R, v);
		m_sweep.c.x += m_xf.position.x;
		m_sweep.c.y += m_xf.position.y;
		//m_sweep.c0 = m_sweep.c
		m_sweep.c0.SetV(m_sweep.c);
		
		// Update the sweep radii of all child shapes.
		for (s = m_shapeList; s; s = s.m_next)
		{
			s.UpdateSweepRadius(m_sweep.localCenter);
		}
		
		var oldType:int = m_type;
		if (m_invMass == 0.0 && m_invI == 0.0)
		{
			m_type = e_staticType;
		}
		else
		{
			m_type = e_dynamicType;
		}
		
		// If the body type changed, we need to refilter the broad-phase proxies.
		if (oldType != m_type)
		{
			for (s = m_shapeList; s; s = s.m_next)
			{
				s.RefilterProxy(m_world.m_broadPhase, m_xf);
			}
		}
	}

	/// Set the position of the body's origin and rotation (radians).
	/// This breaks any contacts and wakes the other bodies.
	/// @param position the new world position of the body's origin (not necessarily
	/// the center of mass).
	/// @param angle the new world rotation angle of the body in radians.
	/// @return false if the movement put a shape outside the world. In this case the
	/// body is automatically frozen.
	public function SetXForm(position:b2Vec2, angle:Number) : Boolean{
		
		var s:b2Shape;
		
		//b2Settings.b2Assert(m_world.m_lock == false);
		if (m_world.m_lock == true)
		{
			return true;
		}
		
		if (IsFrozen())
		{
			return false;
		}
		
		m_xf.R.Set(angle);
		m_xf.position.SetV(position);
		
		//m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
		//b2MulMV(m_xf.R, m_sweep.localCenter);
		var tMat:b2Mat22 = m_xf.R;
		var tVec:b2Vec2 = m_sweep.localCenter;
		// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
		m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
		// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
		m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
		//return T.position + b2Mul(T.R, v);
		m_sweep.c.x += m_xf.position.x;
		m_sweep.c.y += m_xf.position.y;
		//m_sweep.c0 = m_sweep.c
		m_sweep.c0.SetV(m_sweep.c);
		
		m_sweep.a0 = m_sweep.a = angle;
		
		var freeze:Boolean = false;
		for (s = m_shapeList; s; s = s.m_next)
		{
			var inRange:Boolean = s.Synchronize(m_world.m_broadPhase, m_xf, m_xf);
			
			if (inRange == false)
			{
				freeze = true;
				break;
			}
		}
		
		if (freeze == true)
		{
			m_flags |= e_frozenFlag;
			m_linearVelocity.SetZero();
			m_angularVelocity = 0.0;
			for (s = m_shapeList; s; s = s.m_next)
			{
				s.DestroyProxy(m_world.m_broadPhase);
			}
			
			// Failure
			return false;
		}
		
		// Success
		m_world.m_broadPhase.Commit();
		return true;
		
	}

	/// Get the body transform for the body's origin.
	/// @return the world transform of the body's origin.
	public function GetXForm() : b2XForm{
		return m_xf;
	}

	/// Get the world body origin position.
	/// @return the world position of the body's origin.
	public function GetPosition() : b2Vec2{
		return m_xf.position;
	}

	/// Get the angle in radians.
	/// @return the current world rotation angle in radians.
	public function GetAngle() : Number{
		return m_sweep.a;
	}

	/// Get the world position of the center of mass.
	public function GetWorldCenter() : b2Vec2{
		return m_sweep.c;
	}

	/// Get the local position of the center of mass.
	public function GetLocalCenter() : b2Vec2{
		return m_sweep.localCenter;
	}

	/// Set the linear velocity of the center of mass.
	/// @param v the new linear velocity of the center of mass.
	public function SetLinearVelocity(v:b2Vec2) : void{
		m_linearVelocity.SetV(v);
	}

	/// Get the linear velocity of the center of mass.
	/// @return the linear velocity of the center of mass.
	public function GetLinearVelocity() : b2Vec2{
		return m_linearVelocity;
	}

	/// Set the angular velocity.
	/// @param omega the new angular velocity in radians/second.
	public function SetAngularVelocity(omega:Number) : void{
		m_angularVelocity = omega;
	}

	/// Get the angular velocity.
	/// @return the angular velocity in radians/second.
	public function GetAngularVelocity() : Number{
		return m_angularVelocity;
	}

	/// Apply a force at a world point. If the force is not
	/// applied at the center of mass, it will generate a torque and
	/// affect the angular velocity. This wakes up the body.
	/// @param force the world force vector, usually in Newtons (N).
	/// @param point the world position of the point of application.
	public function ApplyForce(force:b2Vec2, point:b2Vec2) : void{
		if (IsSleeping())
		{
			WakeUp();
		}
		//m_force += force;
		m_force.x += force.x;
		m_force.y += force.y;
		//m_torque += b2Cross(point - m_sweep.c, force);
		m_torque += ((point.x - m_sweep.c.x) * force.y - (point.y - m_sweep.c.y) * force.x);
	}

	/// Apply a torque. This affects the angular velocity
	/// without affecting the linear velocity of the center of mass.
	/// This wakes up the body.
	/// @param torque about the z-axis (out of the screen), usually in N-m.
	public function ApplyTorque(torque:Number) : void{
		if (IsSleeping())
		{
			WakeUp();
		}
		m_torque += torque;
	}

	/// Apply an impulse at a point. This immediately modifies the velocity.
	/// It also modifies the angular velocity if the point of application
	/// is not at the center of mass. This wakes up the body.
	/// @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
	/// @param point the world position of the point of application.
	public function ApplyImpulse(impulse:b2Vec2, point:b2Vec2) : void{
		if (IsSleeping())
		{
			WakeUp();
		}
		//m_linearVelocity += m_invMass * impulse;
		m_linearVelocity.x += m_invMass * impulse.x;
		m_linearVelocity.y += m_invMass * impulse.y;
		//m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse);
		m_angularVelocity += m_invI * ((point.x - m_sweep.c.x) * impulse.y - (point.y - m_sweep.c.y) * impulse.x);
	}

	/// Get the total mass of the body.
	/// @return the mass, usually in kilograms (kg).
	public function GetMass() : Number{
		return m_mass;
	}

	/// Get the central rotational inertia of the body.
	/// @return the rotational inertia, usually in kg-m^2.
	public function GetInertia() : Number{
		return m_I;
	}

	/// Get the world coordinates of a point given the local coordinates.
	/// @param localPoint a point on the body measured relative the the body's origin.
	/// @return the same point expressed in world coordinates.
	public function GetWorldPoint(localPoint:b2Vec2) : b2Vec2{
		//return b2Math.b2MulX(m_xf, localPoint);
		var A:b2Mat22 = m_xf.R;
		var u:b2Vec2 = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, 
								  A.col1.y * localPoint.x + A.col2.y * localPoint.y);
		u.x += m_xf.position.x;
		u.y += m_xf.position.y;
		return u;
	}

	/// Get the world coordinates of a vector given the local coordinates.
	/// @param localVector a vector fixed in the body.
	/// @return the same vector expressed in world coordinates.
	public function GetWorldVector(localVector:b2Vec2) : b2Vec2{
		return b2Math.b2MulMV(m_xf.R, localVector);
	}

	/// Gets a local point relative to the body's origin given a world point.
	/// @param a point in world coordinates.
	/// @return the corresponding local point relative to the body's origin.
	public function GetLocalPoint(worldPoint:b2Vec2) : b2Vec2{
		return b2Math.b2MulXT(m_xf, worldPoint);
	}

	/// Gets a local vector given a world vector.
	/// @param a vector in world coordinates.
	/// @return the corresponding local vector.
	public function GetLocalVector(worldVector:b2Vec2) : b2Vec2{
		return b2Math.b2MulTMV(m_xf.R, worldVector);
	}
	
	/// Get the world linear velocity of a world point attached to this body.
	/// @param a point in world coordinates.
	/// @return the world velocity of a point.
	public function GetLinearVelocityFromWorldPoint(worldPoint:b2Vec2) : b2Vec2
	{
		//return          m_linearVelocity   + b2Cross(m_angularVelocity,   worldPoint   - m_sweep.c);
		return new b2Vec2(	m_linearVelocity.x -         m_angularVelocity * (worldPoint.y - m_sweep.c.y), 
							m_linearVelocity.y +         m_angularVelocity * (worldPoint.x - m_sweep.c.x));
	}
	
	/// Get the world velocity of a local point.
	/// @param a point in local coordinates.
	/// @return the world velocity of a point.
	public function GetLinearVelocityFromLocalPoint(localPoint:b2Vec2) : b2Vec2
	{
		//return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));
		var A:b2Mat22 = m_xf.R;
		var worldPoint:b2Vec2 = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, 
								  A.col1.y * localPoint.x + A.col2.y * localPoint.y);
		worldPoint.x += m_xf.position.x;
		worldPoint.y += m_xf.position.y;
		return new b2Vec2(m_linearVelocity.x +         m_angularVelocity * (worldPoint.y - m_sweep.c.y), 
		                  m_linearVelocity.x -         m_angularVelocity * (worldPoint.x - m_sweep.c.x));
	}
	
	/// Is this body treated like a bullet for continuous collision detection?
	public function IsBullet() : Boolean{
		return (m_flags & e_bulletFlag) == e_bulletFlag;
	}

	/// Should this body be treated like a bullet for continuous collision detection?
	public function SetBullet(flag:Boolean) : void{
		if (flag)
		{
			m_flags |= e_bulletFlag;
		}
		else
		{
			m_flags &= ~e_bulletFlag;
		}
	}

	/// Is this body static (immovable)?
	public function IsStatic() : Boolean{
		return m_type == e_staticType;
	}

	/// Is this body dynamic (movable)?
	public function IsDynamic() :Boolean{
		return m_type == e_dynamicType;
	}

	/// Is this body frozen?
	public function IsFrozen() : Boolean{
		return (m_flags & e_frozenFlag) == e_frozenFlag;
	}

	/// Is this body sleeping (not simulating).
	public function IsSleeping() : Boolean{
		return (m_flags & e_sleepFlag) == e_sleepFlag;
	}

	/// You can disable sleeping on this body.
	public function AllowSleeping(flag:Boolean) : void{
		if (flag)
		{
			m_flags |= e_allowSleepFlag;
		}
		else
		{
			m_flags &= ~e_allowSleepFlag;
			WakeUp();
		}
	}

	/// Wake up this body so it will begin simulating.
	public function WakeUp() : void{
		m_flags &= ~e_sleepFlag;
		m_sleepTime = 0.0;
	}

	/// Put this body to sleep so it will stop simulating.
	/// This also sets the velocity to zero.
	public function PutToSleep() : void
	{
		m_flags |= e_sleepFlag;
		m_sleepTime = 0.0;
		m_linearVelocity.SetZero();
		m_angularVelocity = 0.0;
		m_force.SetZero();
		m_torque = 0.0;
	}

	/// Get the list of all shapes attached to this body.
	public function GetShapeList() : b2Shape{
		return m_shapeList;
	}

	/// Get the list of all joints attached to this body.
	public function GetJointList() : b2JointEdge{
		return m_jointList;
	}

	/// Get the next body in the world's body list.
	public function GetNext() : b2Body{
		return m_next;
	}

	/// Get the user data pointer that was provided in the body definition.
	public function GetUserData() : *{
		return m_userData;
	}

	/// Set the user data. Use this to store your application specific data.
	public function SetUserData(data:*) : void
	{
		m_userData = data;
	}

	/// Get the parent world of this body.
	public function GetWorld(): b2World
	{
		return m_world;
	}

	//--------------- Internals Below -------------------

	
	// Constructor
	public function b2Body(bd:b2BodyDef, world:b2World){
		//b2Settings.b2Assert(world.m_lock == false);
		
		m_flags = 0;
		
		if (bd.isBullet)
		{
			m_flags |= e_bulletFlag;
		}
		if (bd.fixedRotation)
		{
			m_flags |= e_fixedRotationFlag;
		}
		if (bd.allowSleep)
		{
			m_flags |= e_allowSleepFlag;
		}
		if (bd.isSleeping)
		{
			m_flags |= e_sleepFlag;
		}
		
		m_world = world;
		
		m_xf.position.SetV(bd.position);
		m_xf.R.Set(bd.angle);
		
		m_sweep.localCenter.SetV(bd.massData.center);
		m_sweep.t0 = 1.0;
		m_sweep.a0 = m_sweep.a = bd.angle;
		
		//m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
		//b2MulMV(m_xf.R, m_sweep.localCenter);
		var tMat:b2Mat22 = m_xf.R;
		var tVec:b2Vec2 = m_sweep.localCenter;
		// (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y)
		m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
		// (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y)
		m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
		//return T.position + b2Mul(T.R, v);
		m_sweep.c.x += m_xf.position.x;
		m_sweep.c.y += m_xf.position.y;
		//m_sweep.c0 = m_sweep.c
		m_sweep.c0.SetV(m_sweep.c);
		
		m_jointList = null;
		m_contactList = null;
		m_prev = null;
		m_next = null;
		
		m_linearDamping = bd.linearDamping;
		m_angularDamping = bd.angularDamping;
		
		m_force.Set(0.0, 0.0);
		m_torque = 0.0;
		
		m_linearVelocity.SetZero();
		m_angularVelocity = 0.0;
		
		m_sleepTime = 0.0;
		
		m_invMass = 0.0;
		m_I = 0.0;
		m_invI = 0.0;
		
		m_mass = bd.massData.mass;
		
		if (m_mass > 0.0)
		{
			m_invMass = 1.0 / m_mass;
		}
		
		if ((m_flags & b2Body.e_fixedRotationFlag) == 0)
		{
			m_I = bd.massData.I;
		}
		
		if (m_I > 0.0)
		{
			m_invI = 1.0 / m_I;
		}
		
		if (m_invMass == 0.0 && m_invI == 0.0)
		{
			m_type = e_staticType;
		}
		else
		{
			m_type = e_dynamicType;
		}
	
		m_userData = bd.userData;
		
		m_shapeList = null;
		m_shapeCount = 0;
	}
	
	// Destructor
	//~b2Body();

	//
	static private var s_xf1:b2XForm = new b2XForm();
	//
	public function SynchronizeShapes() : Boolean{
		
		var xf1:b2XForm = s_xf1;
		xf1.R.Set(m_sweep.a0);
		//xf1.position = m_sweep.c0 - b2Mul(xf1.R, m_sweep.localCenter);
		var tMat:b2Mat22 = xf1.R;
		var tVec:b2Vec2 = m_sweep.localCenter;
		xf1.position.x = m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
		xf1.position.y = m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
		
		var s:b2Shape;
		
		var inRange:Boolean = true;
		for (s = m_shapeList; s; s = s.m_next)
		{
			inRange = s.Synchronize(m_world.m_broadPhase, xf1, m_xf);
			if (inRange == false)
			{
				break;
			}
		}
		
		if (inRange == false)
		{
			m_flags |= e_frozenFlag;
			m_linearVelocity.SetZero();
			m_angularVelocity = 0.0;
			for (s = m_shapeList; s; s = s.m_next)
			{
				s.DestroyProxy(m_world.m_broadPhase);
			}
			
			// Failure
			return false;
		}
		
		// Success
		return true;
		
	}

	public function SynchronizeTransform() : void{
		m_xf.R.Set(m_sweep.a);
		//m_xf.position = m_sweep.c - b2Mul(m_xf.R, m_sweep.localCenter);
		var tMat:b2Mat22 = m_xf.R;
		var tVec:b2Vec2 = m_sweep.localCenter;
		m_xf.position.x = m_sweep.c.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
		m_xf.position.y = m_sweep.c.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
	}

	// This is used to prevent connected bodies from colliding.
	// It may lie, depending on the collideConnected flag.
	public function IsConnected(other:b2Body) : Boolean{
		for (var jn:b2JointEdge = m_jointList; jn; jn = jn.next)
		{
			if (jn.other == other)
				return jn.joint.m_collideConnected == false;
		}
		
		return false;
	}

	public function Advance(t:Number) : void{
		// Advance to the new safe time.
		m_sweep.Advance(t);
		m_sweep.c.SetV(m_sweep.c0);
		m_sweep.a = m_sweep.a0;
		SynchronizeTransform();
	}

	public var m_flags:uint;
	public var m_type:int;

	public var m_xf:b2XForm = new b2XForm();		// the body origin transform

	public var m_sweep:b2Sweep = new b2Sweep();	// the swept motion for CCD

	public var m_linearVelocity:b2Vec2 = new b2Vec2();
	public var m_angularVelocity:Number;

	public var m_force:b2Vec2 = new b2Vec2();
	public var m_torque:Number;

	public var m_world:b2World;
	public var m_prev:b2Body;
	public var m_next:b2Body;

	public var m_shapeList:b2Shape;
	public var m_shapeCount:int;

	public var m_jointList:b2JointEdge;
	public var m_contactList:b2ContactEdge;

	public var m_mass:Number, m_invMass:Number;
	public var m_I:Number, m_invI:Number;

	public var m_linearDamping:Number;
	public var m_angularDamping:Number;

	public var m_sleepTime:Number;

	public var m_userData:*;
	
	
	// m_flags
	//enum
	//{
		static public var e_frozenFlag:uint			= 0x0002;
		static public var e_islandFlag:uint			= 0x0004;
		static public var e_sleepFlag:uint			= 0x0008;
		static public var e_allowSleepFlag:uint		= 0x0010;
		static public var e_bulletFlag:uint			= 0x0020;
		static public var e_fixedRotationFlag:uint	= 0x0040;
	//};

	// m_type
	//enum
	//{
		static public var e_staticType:uint 	= 1;
		static public var e_dynamicType:uint 	= 2;
		static public var e_maxTypes:uint 		= 3;
	//};
	
};

}
