
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Xna.Framework;

using GE.Physics.Shapes;
using GE.World.Entities;

namespace GE.Physics
{
    class Physics
    {
        #region Variables

        /// <summary>
        /// singleton variable
        /// </summary>
        static Physics m_instance = new Physics();

        /// <summary>
        /// array to store physics entity
        /// </summary>
        List<Shapes.Shape> m_listOfShape;

        /// <summary>
        /// the shape id used for the checkAllCollision
        /// </summary>
        int m_idShapeForCheckAllCollision;

        #endregion

        #region Singleton, Constructor & Reset

        /// <summary>
        /// get the instance of physics
        /// </summary>
        public static Physics Instance
        {
            get
            {
                return m_instance;
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        private Physics()
        {
            m_listOfShape = new List<GE.Physics.Shapes.Shape>();
            m_idShapeForCheckAllCollision = -1;
        }

        /// <summary>
        /// Reset the Physic component
        /// </summary>
        public void reset()
        {
            m_listOfShape.Clear();
            m_idShapeForCheckAllCollision = -1;
        }

        #endregion

        #region CreateXXX

        /// <summary>
        /// Create a physics entity with a rectangular shape
        /// </summary>
        /// <param name="width">rectangle's width</param>
        /// <param name="height">rectangle's height</param>
        /// <returns>The created shape</returns>
	    public DynamicShapeRectangle createDynamicRectangle(int width, int height, Vector2 rotationCenter, WorldEntity refToOwner)
        {
            //create the rectangle shape
            DynamicShapeRectangle newShape = new DynamicShapeRectangle(m_listOfShape.Count, width, height, rotationCenter, refToOwner);

            newShape._bCollisionEnable = true;

	        //calculate the bounding box
	        newShape.computeBoundingBox();

	        //store the shape in the vector
	        m_listOfShape.Add(newShape);

	        //return th shape
	        return newShape;
        }

        /// <summary>
        /// Create a new static rectangle and add it to the collection of physics shape.
        /// </summary>
        /// <param name="width">Rectangle's width</param>
        /// <param name="height">Rectangle's height</param>
        /// <param name="rotationCenter">Point used as reference</param>
        /// <param name="position">Position in the world</param>
        /// <param name="orientation">Orientation used in the world</param>
        /// <param name="owner">Owner of the shape</param>
        /// <returns></returns>
        public StaticShapeRectangle createStaticRectangle(int width, int height, Vector2 rotationCenter, Vector2 position, float orientation,
            WorldEntity owner)
        {
            StaticShapeRectangle newShape = new StaticShapeRectangle(m_listOfShape.Count, width, height, rotationCenter, position, orientation, owner);
            m_listOfShape.Add(newShape);
            return newShape;
        }

        /// <summary>
        /// Create a physics entity with a circle shape
        /// </summary>
        /// <param name="radius">radius of the circle</param>
        /// <returns>The shape entity</returns>
	    public Shapes.Shape createCircle(int radius, WorldEntity refToOwner)
        {
            //create the circle shape
            ShapeCircle newShape = new ShapeCircle(m_listOfShape.Count);
            newShape._typeOfShape = eTypeShape.eCircleShape;
            newShape._refToOwner = refToOwner;
            newShape.m_radius = radius;

            //store the shape
            m_listOfShape.Add(newShape);

            //return the shape
	        return newShape;
        }

        #endregion

        #region Add

        /// <summary>
        /// Add manually a shape to the array of shape
        /// </summary>
        /// <param name="newShape"></param>
        public void addShape(Shapes.Shape newShape)
        {
            m_listOfShape.Add(newShape);
        }

        #endregion

        #region Collision

        /// <summary>
        /// Check collision between an unregistered shape and all the others registered shapes.
        /// </summary>
        /// <param name="s">An unregistered shape</param>
        /// <param name="group">A group of shape. -1 to test with everything</param>
        /// <returns>a reference to the entity it collided with or null</returns>
        public WorldEntity checkUnregisteredCollision(Shape s, int group)
        {
            Shape res = null;
            if (group == -1)
                res = checkCollisionWithUnregisteredShape(s);
            else
                res = checkCollisionWithUnregisteredShape(s, group);

            if (res == null) return null;

            return res._refToOwner;
        }

        /// <summary>
        /// Check collision between a shape registered in the Physics component and all other registered shapes in the Physics component.
        /// </summary>
        /// <param name="entity">the entity</param>
        /// <returns>a reference to the entity it collided with or null</returns>
        public WorldEntity checkRegisteredCollision(Shape entity)
        {
            Shape s = checkCollisionWithRegisteredShape(entity);
            if (s == null)
                return null;

            return s._refToOwner;
        }

        /// <summary>
        /// Check collision between a shape registered in the Physics component and all other registered shapes in 
        /// the Physics component.
        /// </summary>
        /// <param name="entity">the shape</param>
        /// <returns>Null if no collision or a CollisionResult object filled with info about the collision</returns>
        public CollisionResult checkRegisteredCollisionEx(Shape entity)
        {

            Shape s = checkCollisionWithRegisteredShape(entity);
            if (s == null)
                return null;

            Vector2 overlap = Vector2.Zero;
            eCollisionSide side = eCollisionSide.eNone;
            getCollisionOverlap((ShapeRectangle)s, (ShapeRectangle)entity, ref overlap, ref side);
            return new CollisionResult(s._refToOwner, overlap, side);
        }

        /// <summary>
        /// Check collision against all the shape from the group and return a CollisionResult object with the overlap.
        /// The entity and side are null
        /// </summary>
        /// <param name="s"></param>
        /// <param name="group"></param>
        /// <returns></returns>
        public CollisionResult checkAllRegisteredCollisionEx(Shape s, int group)
        {
            //create a collision result object
            CollisionResult cres = new CollisionResult(null, Vector2.Zero, eCollisionSide.eNone);
            bool bCollision = false;

            //for every entity
            foreach (Shape iteratorShape in m_listOfShape)
            {
                //if entity and iterator are the same or collision disable or not in the group
                if (s.Id == iteratorShape.Id || !iteratorShape._bCollisionEnable || (iteratorShape._iGroup & group) == 0)
                    continue;

                //result of the collision check
                bool res = false;

                if (s._typeOfShape == eTypeShape.eRectangleShape)
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//rectangle/rectangle
                        res = checkCollisionBetweenRectangle((ShapeRectangle)s, (ShapeRectangle)iteratorShape);
                    else//rectangle/circle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)s, (ShapeCircle)iteratorShape);

                }
                else // circle
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//circle rectangle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)iteratorShape, (ShapeCircle)s);
                    else //circle circle
                        res = checkCollisionBetweenCircles((ShapeCircle)iteratorShape, (ShapeCircle)s);
                }

                //if there is a collision
                if (res)
                {
                    Vector2 newOverlap = Vector2.Zero;
                    eCollisionSide side = eCollisionSide.eNone;
                    getCollisionOverlap((ShapeRectangle)iteratorShape, (ShapeRectangle)s, ref newOverlap, ref side);
                    cres.Overlap += newOverlap;
                    bCollision = true;
                }
            }
            if (bCollision)
                return cres;
            else
                return null;
        }

        /// <summary>
        /// Check collision between a shape registered in the Physics component and all other registered shapes in 
        /// the Physics component.
        /// </summary>
        /// <param name="entity">the shape</param>
        /// <param name="group">the group to test. Use bitwise or to test with several groups</param>
        /// <returns>Null if no collision or a CollisionResult object filled with info about the first collision detected</returns>
        public CollisionResult checkFirstRegisteredCollisionEx(Shape entity, int group)
        {
            Shape s = checkCollisionWithRegisteredShape(entity, group);
            if (s == null)
                return null;

            Vector2 overlap = Vector2.Zero;
            eCollisionSide side = eCollisionSide.eNone;
            getCollisionOverlap((ShapeRectangle)s, (ShapeRectangle)entity, ref overlap, ref side);
            return new CollisionResult(s._refToOwner, overlap, side);
        }

        /// <summary>
        /// check collision between two shapes
        /// </summary>
        /// <param name="s1">shape 1</param>
        /// <param name="s2">shape 2</param>
        /// <returns>true if collision or else false</returns>
        public bool collision(ShapeRectangle s1, ShapeRectangle s2)
        {
            return checkCollisionBetweenRectangle(s1, s2);
        }

        /// <summary>
        /// Check and return the entity that collided with the shape. If we recall it, it will
        /// return the next object collided.
        /// </summary>
        /// <param name="entity">the shape to test</param>
        /// <returns>a reference to the entity or null</returns>
        public Shape checkAllCollision(Shape entity)
        {
            m_idShapeForCheckAllCollision++;
            //for every entity
            //foreach (Shape.Shape s in m_listOfShape)
            while(m_idShapeForCheckAllCollision<m_listOfShape.Count)
            {
                //get the current shape
                Shape s = m_listOfShape[m_idShapeForCheckAllCollision];

                //if entity and iterator are the same
                if (entity == s || !s._bCollisionEnable)
                {
                    m_idShapeForCheckAllCollision++;
                    continue;
                }

                //if the two object are rectangle
                bool res = false;

                if (entity._typeOfShape == eTypeShape.eRectangleShape)
                {
                    if (s._typeOfShape == eTypeShape.eRectangleShape)//rectangle/rectangle
                    {
                        //check collision
                        res = checkCollisionBetweenRectangle((ShapeRectangle)entity, (ShapeRectangle)s);
                        if (res)
                            return s;
                    }
                    else//rectangle/circle
                    {
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)entity, (ShapeCircle)s);
                        if (res)
                            return s;
                    }
                }
                else // circle
                {
                    if (s._typeOfShape == eTypeShape.eRectangleShape)//circle rectangle
                    {
                        //check collision
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)s, (ShapeCircle)entity);
                        if (res)
                            return s;
                    }
                    else //circle circle
                    {
                        res = checkCollisionBetweenCircles((ShapeCircle)s, (ShapeCircle)entity);
                        if (res)
                            return s;
                    }
                }

                m_idShapeForCheckAllCollision++;
            }
            m_idShapeForCheckAllCollision = -1;
            return null;
        }

        #endregion

        /// <summary>
        /// Get the overlap vector between two shapes. The overlap vector is the displacement to apply to the
        /// dynamic shape to make it not collide with the static shape
        /// </summary>
        /// <param name="staticShape"></param>
        /// <param name="dynamicShape"></param>
        /// <returns></returns>
        public void getCollisionOverlap(ShapeRectangle staticShape, ShapeRectangle dynamicShape, ref Vector2 overlap, 
            ref eCollisionSide side)
        {
            Vector2[] obbStatic = staticShape.getOrientedBoundingBox();
            Vector2[] obbDynamic = dynamicShape.getOrientedBoundingBox();

            float diffX1 = obbStatic[0].X - obbDynamic[1].X; //right
            float diffX2 = obbStatic[1].X - obbDynamic[0].X; //left
            float diffY1 = obbStatic[2].Y - obbDynamic[0].Y; //top
            float diffY2 = obbStatic[0].Y - obbDynamic[2].Y; //bottom

            //float minX = (float)System.Math.Abs(diffX1) < (float)System.Math.Abs(diffX2) ? diffX1 : diffX2;
            float minX = 0;
            eCollisionSide sideX = eCollisionSide.eNone;
            if (System.Math.Abs(diffX1) < System.Math.Abs(diffX2))
            {
                minX = diffX1 - 1;
                sideX = eCollisionSide.eRight;
            }
            else
            {
                minX = diffX2 + 1;
                sideX = eCollisionSide.eLeft;
            }

            //float minY = (float)System.Math.Abs(diffY1) < (float)System.Math.Abs(diffY2) ? diffY1 : diffY2;
            float minY = 0;
            eCollisionSide sideY = eCollisionSide.eNone;
            if (System.Math.Abs(diffY1) < System.Math.Abs(diffY2))
            {
                minY = diffY1 + 1;
                sideY = eCollisionSide.eTop;
            }
            else
            {
                minY = diffY2 - 1;
                sideY = eCollisionSide.eBottom;
            }

            if (System.Math.Abs(minX) < System.Math.Abs(minY))
            {
                overlap = Vector2.UnitX * minX;
                side = sideX;
            }
            else
            {
                overlap = Vector2.UnitY * minY;
                side = sideY;
            }
            
        }


        #region Collision Tools

        /// <summary>
        /// Check collision between a registered shape and all the others registered shapes. 
        /// </summary>
        /// <param name="s">The registered shape to test</param>
        /// <param name="group">The group to test</param>
        /// <returns>null if no collision or the ref to the collided shape</returns>
        private Shape checkCollisionWithRegisteredShape(Shape s, int group)
        {
            //for every entity
            foreach (Shape iteratorShape in m_listOfShape)
            {
                //if entity and iterator are the same or collision disable or not in the group
                if (s.Id == iteratorShape.Id || !iteratorShape._bCollisionEnable || (iteratorShape._iGroup & group) == 0)
                    continue;

                //result of the collision check
                bool res = false;

                if (s._typeOfShape == eTypeShape.eRectangleShape)
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//rectangle/rectangle
                        res = checkCollisionBetweenRectangle((ShapeRectangle)s, (ShapeRectangle)iteratorShape);
                    else//rectangle/circle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)s, (ShapeCircle)iteratorShape);

                }
                else // circle
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//circle rectangle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)iteratorShape, (ShapeCircle)s);
                    else //circle circle
                        res = checkCollisionBetweenCircles((ShapeCircle)iteratorShape, (ShapeCircle)s);
                }

                //if there is a collision
                if (res)
                {
                    return iteratorShape;
                }
            }
            return null;
        }

        /// <summary>
        /// Check collision between a registered shape and all the others registered shapes. 
        /// </summary>
        /// <param name="s">The registered shape to test</param>
        /// <returns>null if no collision or the ref to the collided shape</returns>
	    private Shape checkCollisionWithRegisteredShape(Shape s)
        {
            //for every entity
	        foreach(Shape iteratorShape in m_listOfShape)
            {
                //if entity and iterator are the same
		        if(s.Id == iteratorShape.Id || !iteratorShape._bCollisionEnable)
			        continue;

                //result of the collision check
		        bool res = false;

                if (s._typeOfShape == eTypeShape.eRectangleShape)
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//rectangle/rectangle
                        res = checkCollisionBetweenRectangle((ShapeRectangle)s, (ShapeRectangle)iteratorShape);
                    else//rectangle/circle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)s, (ShapeCircle)iteratorShape);

                }
                else // circle
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//circle rectangle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)iteratorShape, (ShapeCircle)s);
                    else //circle circle
                        res = checkCollisionBetweenCircles((ShapeCircle)iteratorShape, (ShapeCircle)s);
                }

                //if there is a collision
                if (res)
                    return iteratorShape;
            }
            return null;
        }

        /// <summary>
        /// Check collision between an unregistered shape and all the others registered shapes. 
        /// </summary>
        /// <param name="s">The unregistered shape to test</param>
        /// <returns>null if no collision or the ref to the collided shape</returns>
        private Shape checkCollisionWithUnregisteredShape(Shape s)
        {
            //for every entity
            foreach (Shape iteratorShape in m_listOfShape)
            {
                //if entity and iterator are the same
                if (!iteratorShape._bCollisionEnable)
                    continue;

                //result of the collision check
                bool res = false;

                if (s._typeOfShape == eTypeShape.eRectangleShape)
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//rectangle/rectangle
                        res = checkCollisionBetweenRectangle((ShapeRectangle)s, (ShapeRectangle)iteratorShape);
                    else//rectangle/circle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)s, (ShapeCircle)iteratorShape);

                }
                else // circle
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//circle rectangle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)iteratorShape, (ShapeCircle)s);
                    else //circle circle
                        res = checkCollisionBetweenCircles((ShapeCircle)iteratorShape, (ShapeCircle)s);
                }

                //if there is a collision
                if (res)
                    return iteratorShape;
            }
            return null;
        }

        /// <summary>
        /// Check collision between an unregistered shape and all the others registered shapes from a specific group.
        /// </summary>
        /// <param name="s">The unregistered shape to test</param>
        /// <param name="group">The group used to test. It will testo only with shapes from this group.</param>
        /// <returns>null if no collision or the ref to the collided shape</returns>
        private Shape checkCollisionWithUnregisteredShape(Shape s, int group)
        {
            //for every entity
            foreach (Shape iteratorShape in m_listOfShape)
            {
                //if entity and iterator are the same
                if (!iteratorShape._bCollisionEnable || (iteratorShape._iGroup & group) == 0)
                    continue;

                //result of the collision check
                bool res = false;

                if (s._typeOfShape == eTypeShape.eRectangleShape)
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//rectangle/rectangle
                        res = checkCollisionBetweenRectangle((ShapeRectangle)s, (ShapeRectangle)iteratorShape);
                    else//rectangle/circle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)s, (ShapeCircle)iteratorShape);

                }
                else // circle
                {
                    if (iteratorShape._typeOfShape == eTypeShape.eRectangleShape)//circle rectangle
                        res = checkCollisionBetweenRectangleAndCircle((ShapeRectangle)iteratorShape, (ShapeCircle)s);
                    else //circle circle
                        res = checkCollisionBetweenCircles((ShapeCircle)iteratorShape, (ShapeCircle)s);
                }

                //if there is a collision
                if (res)
                    return iteratorShape;
            }
            return null;
        }

        /// <summary>
        /// Check collision between two rectangle shape
        /// </summary>
        /// <param name="entity1">rectangle shape 1</param>
        /// <param name="entity2">rectangle shape 2</param>
        /// <returns>true if collision or else false</returns>
	    private bool checkCollisionBetweenRectangle(ShapeRectangle entity1, ShapeRectangle entity2)
        {
            //get the oriented bounding box for the two entities
	        Vector2[] boundingBox1;
	        Vector2[] boundingBox2;

	        boundingBox1 = entity1.getOrientedBoundingBox();
	        boundingBox2 = entity2.getOrientedBoundingBox();

	        //create an array containing only the edges that we will have to test (as the shapes are rectangles, 
            //we need to test 2 edges per shapes so 4 edges).
	        Vector2[] vectorOfEdgeToTest = new Vector2[6];
	        vectorOfEdgeToTest[0] = boundingBox1[0];
	        vectorOfEdgeToTest[1] = boundingBox1[1];
	        vectorOfEdgeToTest[2] = boundingBox1[2];
	        vectorOfEdgeToTest[3] = boundingBox2[0];
	        vectorOfEdgeToTest[4] = boundingBox2[1];
	        vectorOfEdgeToTest[5] = boundingBox2[2];

	        //for every edge of the rectangle 1 (so BB1)
	        //We do it for 2 edges because the two others are parallel to the two firsts.
	        for(int i=0; i<5; i++)
	        {
		        //get the vector of the edge
		        if(i == 2)
			        i++;
		        int id1 = i;
		        int id2 = i+1;

		        Vector2 edge = vectorOfEdgeToTest[id1] - vectorOfEdgeToTest[id2];

		        //get the perpendicular vector
		        Vector2 orthogonalLine = new Vector2(-edge.Y, edge.X);
		        orthogonalLine.Normalize();

		        //get the min and max for the bounding box 1;
		        float maxBB1 = 0;
		        float minBB1 = 0;
		        polygonProjection(orthogonalLine, boundingBox1, ref minBB1, ref maxBB1);
        		
		        //get the min and max for bounding box 2
		        float maxBB2 = 0;
		        float minBB2 = 0;
		        polygonProjection(orthogonalLine, boundingBox2, ref minBB2, ref maxBB2);
        		
		        //check if overlap
		        if(!checkOverlap(minBB1, maxBB1, minBB2, maxBB2))
			        //if it doesn't overlap, a separate axis exists so no collision
			        return false;	
	        } 

	        //no separate axis found so collision
            return true;

        }

        /// <summary>
        /// Check collision betzeen a rectangle and a circle
        /// </summary>
        /// <param name="rectangle">rectangle shape</param>
        /// <param name="circle">circle shape</param>
        /// <returns>true if collision or else false</returns>
	    private bool checkCollisionBetweenRectangleAndCircle(ShapeRectangle rectangle, ShapeCircle circle)
        {
            //get the orientied bounding box of the rectangle
	        Vector2[] boundingBox = rectangle.getOrientedBoundingBox();

	        //get a vector between the two centers
	        Vector2 vectorBetweenCenter = rectangle._v2position - circle._v2position;
	        vectorBetweenCenter.Normalize();
        	
	        //get the min and max for the bounding box;
	        float maxBB1 = 0;
	        float minBB1 = 0;
	        polygonProjection(vectorBetweenCenter, boundingBox, ref minBB1, ref maxBB1);

	        //get min an dmax for the circle
	        float maxC = 0;
	        float minC = 0;
	        circleProjection(vectorBetweenCenter, circle._v2position, (float)circle.m_radius, ref minC, ref maxC);

	        //check if overlap
	        if(!checkOverlap(minBB1, maxBB1, minC, maxC))
		        //if it doesn't overlap, a separate axis exists so no collision
		        return false;	

	        //re check with the side of the bounding box
	        for(int i=0; i<3; i++)
	        {
		        int id1 = i;
		        int id2 = i+1;

		        Vector2 edge = boundingBox[id2] - boundingBox[id1];
		        Vector2 orthogonal = new Vector2( -edge.Y, edge.X);
		        orthogonal.Normalize();

		        //get the min and max for the bounding box;
		        polygonProjection(orthogonal, boundingBox, ref minBB1, ref maxBB1);

		        //get min an dmax for the circle
		        circleProjection(orthogonal, circle._v2position, (float)circle.m_radius, ref minC, ref maxC);

		        //check if overlap
		        if(!checkOverlap(minBB1, maxBB1, minC, maxC))
			        //if it doesn't overlap, a separate axis exists so no collision
			        return false;	

	        }

	        return true;
        }


        /// <summary>
        /// Check collision between two circles
        /// </summary>
        /// <param name="circle1">circle shape1</param>
        /// <param name="circle2">circle shape 2</param>
        /// <returns>true if collision or else false</returns>
        private bool checkCollisionBetweenCircles(ShapeCircle circle1, ShapeCircle circle2)
        {
            //get the distance between the centers
            float distance = (circle1._v2position - circle2._v2position).Length();

            //add the radius
            float sumOfRadius = (float)(circle1.m_radius + circle2.m_radius);

            if (distance > sumOfRadius)
                return false;
            else
                return true;
        }

        /// <summary>
        /// Do the projection of a polygon onto a line
        /// </summary>
        /// <param name="projectionLine">The line</param>
        /// <param name="boundingBox">The polygon</param>
        /// <param name="min">The min distance</param>
        /// <param name="max">The max distance</param>
	    private void polygonProjection(Vector2 projectionLine, Vector2[] boundingBox, ref float min, ref float max)
        {
            //for every point of the bounding box, calculate it's projection on the line
	        float BBPoint0 = Vector2.Dot(projectionLine, boundingBox[0]);
	        float BBPoint1 = Vector2.Dot(projectionLine, boundingBox[1]);
	        float BBPoint2 = Vector2.Dot(projectionLine, boundingBox[2]);
	        float BBPoint3 = Vector2.Dot(projectionLine, boundingBox[3]);

	        //get the maximum
            max = MathHelper.Max(BBPoint0, BBPoint1);
	        max = MathHelper.Max(max, BBPoint2);
	        max = MathHelper.Max(max, BBPoint3);

	        //get the minimum
	        min = MathHelper.Min(BBPoint0, BBPoint1);
	        min = MathHelper.Min(min, BBPoint2);
	        min = MathHelper.Min(min, BBPoint3);
        }

        /// <summary>
        /// Do the projection of a circle onto a line
        /// </summary>
        /// <param name="projectionLine">The line</param>
        /// <param name="position">The position of the center of the circle</param>
        /// <param name="radius">The circle radius</param>
        /// <param name="min">The min distance</param>
        /// <param name="max">The max distance</param>
        private void circleProjection(Vector2 projectionLine, Vector2 position, float radius, ref float min,
            ref float max)
        {
            //get the extremum point of a diameter parallel to the projection line
            Vector2 test = projectionLine * radius;
            Vector2 sideOne = position + projectionLine * radius;
            Vector2 sideTwo = position - projectionLine * radius;

            //project the point on the line
            float projectionPointOne = Vector2.Dot(projectionLine, sideOne);
            float projectionPointTwo = Vector2.Dot(projectionLine, sideTwo);

            //get the min and max
            min = MathHelper.Min(projectionPointOne, projectionPointTwo);
            max = MathHelper.Max(projectionPointOne, projectionPointTwo);
        }

        /// <summary>
        /// Check if two segments on a line are overlapping
        /// </summary>
        /// <param name="a1">segment 1 point 1</param>
        /// <param name="a2">segment 1 point 2</param>
        /// <param name="b1">segment 2 point 1</param>
        /// <param name="b2">segment 2 point 2</param>
        /// <returns></returns>
	    private bool checkOverlap(float a1, float a2, float b1, float b2)
        {
            float maxA = MathHelper.Max(a1, a2);
	        float minA = MathHelper.Min(a1, a2);

	        float maxB = MathHelper.Max(b1, b2);
	        float minB = MathHelper.Min(b1, b2);

	        if(maxA<minB || maxB< minA)
		        return false;

	        return true;
        }

        #endregion
    }
}
