/*
* 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.Collision.Shapes{




import classes.Box2D.Common.Math.*;
import classes.Box2D.Common.*;
import classes.Box2D.Dynamics.*;
import classes.Box2D.Collision.*;



/// A shape is used for collision detection. Shapes are created in b2World.
/// You can use shape for collision detection before they are attached to the world.
/// @warning you cannot reuse shapes.
public class b2Shape
{
	/// Get the type of this shape. You can use this to down cast to the concrete shape.
	/// @return the shape type.
	public function GetType() : int{
		return m_type;
	}

	/// Is this shape a sensor (non-solid)?
	/// @return the true if the shape is a sensor.
	public function IsSensor() : Boolean{
		return m_isSensor;
	}

	/// Set the contact filtering data. You must call b2World::Refilter to correct
	/// existing contacts/non-contacts.
	public function SetFilterData(filter:b2FilterData) : void
	{
		m_filter = filter.Copy();
	}

	/// Get the contact filtering data.
	public function GetFilterData() : b2FilterData
	{
		return m_filter.Copy();
	}

	/// Get the parent body of this shape. This is NULL if the shape is not attached.
	/// @return the parent body.
	public function GetBody() : b2Body{
		return m_body;
	}

	/// Get the next shape in the parent body's shape list.
	/// @return the next shape.
	public function GetNext() : b2Shape{
		return m_next;
	}

	/// Get the user data that was assigned in the shape definition. Use this to
	/// store your application specific data.
	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;
	}

	/// Test a point for containment in this shape. This only works for convex shapes.
	/// @param xf the shape world transform.
	/// @param p a point in world coordinates.
	public virtual function TestPoint(xf:b2XForm, p:b2Vec2) : Boolean {return false};

	/// Perform a ray cast against this shape.
	/// @param xf the shape world transform.
	/// @param lambda returns the hit fraction. You can use this to compute the contact point
	/// p = (1 - lambda) * segment.p1 + lambda * segment.p2.
	/// @param normal returns the normal at the contact point. If there is no intersection, the normal
	/// is not set.
	/// @param segment defines the begin and end point of the ray cast.
	/// @param maxLambda a number typically in the range [0,1].
	/// @return true if there was an intersection.
	public virtual function  TestSegment(xf:b2XForm,
								lambda:Array, // float pointer
								normal:b2Vec2, // pointer
								segment:b2Segment,
								maxLambda:Number) : Boolean {return false};

	/// Given a transform, compute the associated axis aligned bounding box for this shape.
	/// @param aabb returns the axis aligned box.
	/// @param xf the world transform of the shape.
	public virtual function  ComputeAABB(aabb:b2AABB, xf:b2XForm) : void {};

	/// Given two transforms, compute the associated swept axis aligned bounding box for this shape.
	/// @param aabb returns the axis aligned box.
	/// @param xf1 the starting shape world transform.
	/// @param xf2 the ending shape world transform.
	public virtual function  ComputeSweptAABB(	aabb:b2AABB,
									xf1:b2XForm,
									xf2:b2XForm) : void {};

	/// Compute the mass properties of this shape using its dimensions and density.
	/// The inertia tensor is computed about the local origin, not the centroid.
	/// @param massData returns the mass data for this shape.
	public virtual function  ComputeMass(massData:b2MassData) : void {};

	/// Get the maximum radius about the parent body's center of mass.
	public function GetSweepRadius() : Number
	{
		return m_sweepRadius;
	}

	/// Get the coefficient of friction.
	public function GetFriction() : Number
	{
		return m_friction;
	}

	/// Get the coefficient of restitution.
	public function GetRestitution() : Number
	{
		return m_restitution;
	}
	
	//--------------- Internals Below -------------------

	static public function Create(def:b2ShapeDef, allocator:*) : b2Shape
	{
		switch (def.type)
		{
		case e_circleShape:
			{
				//void* mem = allocator->Allocate(sizeof(b2CircleShape));
				return new b2CircleShape(def);
			}
		
		case e_polygonShape:
			{
				//void* mem = allocator->Allocate(sizeof(b2PolygonShape));
				return new b2PolygonShape(def);
			}
		
		default:
			//b2Settings.b2Assert(false);
			return null;
		}
	}
	
	static public function Destroy(shape:b2Shape, allocator:*) : void
	{
		/*switch (s.m_type)
		{
		case e_circleShape:
			//s->~b2Shape();
			//allocator->Free(s, sizeof(b2CircleShape));
			break;
		
		case e_polygonShape:
			//s->~b2Shape();
			//allocator->Free(s, sizeof(b2PolygonShape));
			break;
		
		default:
			//b2Settings.b2Assert(false);
		}*/
	}

	public function b2Shape(def:b2ShapeDef){
		
		m_userData = def.userData;
		m_friction = def.friction;
		m_restitution = def.restitution;
		m_density = def.density;
		m_body = null;
		m_sweepRadius = 0.0;
		
		m_next = null;
		
		m_proxyId = b2Pair.b2_nullProxy;
		
		m_filter = def.filter.Copy();
		
		m_isSensor = def.isSensor;
		
	}
	
	//virtual ~b2Shape();

	//
	static private var s_proxyAABB:b2AABB = new b2AABB();
	public function CreateProxy(broadPhase:b2BroadPhase, transform:b2XForm) : void{
		
		//b2Settings.b2Assert(m_proxyId == b2_nullProxy);
		
		var aabb:b2AABB = s_proxyAABB;
		ComputeAABB(aabb, transform);
		
		var inRange:Boolean = broadPhase.InRange(aabb);
		
		// You are creating a shape outside the world box.
		//b2Settings.b2Assert(inRange);
		
		if (inRange)
		{
			m_proxyId = broadPhase.CreateProxy(aabb, this);
		}
		else
		{
			m_proxyId = b2Pair.b2_nullProxy;
		}
		
	}
	
	public function DestroyProxy(broadPhase:b2BroadPhase) : void{
		
		if (m_proxyId != b2Pair.b2_nullProxy)
		{
			broadPhase.DestroyProxy(m_proxyId);
			m_proxyId = b2Pair.b2_nullProxy;
		}
		
	}
	
	//
	static private var s_syncAABB:b2AABB = new b2AABB();
	//
	public function Synchronize(broadPhase:b2BroadPhase, transform1:b2XForm, transform2:b2XForm) : Boolean{
		
		if (m_proxyId == b2Pair.b2_nullProxy)
		{	
			return false;
		}
		
		// Compute an AABB that covers the swept shape (may miss some rotation effect).
		var aabb:b2AABB = s_syncAABB;
		ComputeSweptAABB(aabb, transform1, transform2);
		
		if (broadPhase.InRange(aabb))
		{
			broadPhase.MoveProxy(m_proxyId, aabb);
			return true;
		}
		else
		{
			return false;
		}
		
	}
	
	static private var s_resetAABB:b2AABB = new b2AABB();
	public function RefilterProxy(broadPhase:b2BroadPhase, transform:b2XForm) : void{
		
		if (m_proxyId == b2Pair.b2_nullProxy)
		{
			return;
		}
		
		broadPhase.DestroyProxy(m_proxyId);
		
		var aabb:b2AABB = s_resetAABB;
		ComputeAABB(aabb, transform);
		
		var inRange:Boolean = broadPhase.InRange(aabb);
		
		if (inRange)
		{
			m_proxyId = broadPhase.CreateProxy(aabb, this);
		}
		else
		{
			m_proxyId = b2Pair.b2_nullProxy;
		}
		
	}

	public virtual function UpdateSweepRadius(center:b2Vec2) : void{};

	public var m_type:int;
	public var m_next:b2Shape;
	public var m_body:b2Body;

	// Sweep radius relative to the parent body's center of mass.
	public var m_sweepRadius:Number;

	public var m_density:Number;
	public var m_friction:Number;
	public var m_restitution:Number;

	public var m_proxyId:uint;
	public var m_filter:b2FilterData;

	public var m_isSensor:Boolean;

	public var m_userData:*;

	
	
	
	/// The various collision shape types supported by Box2D.
	//enum b2ShapeType
	//{
		static public const e_unknownShape:int = 	-1;
		static public const e_circleShape:int = 	0;
		static public const e_polygonShape:int = 	1;
		static public const e_shapeTypeCount:int = 	2;
	//};
	
	
	
};

	
}
