#ifndef _H_AGK_PHYSICS_BODY_
#define _H_AGK_PHYSICS_BODY_

// Common includes
//#include "Box2D/Box2D.h"
//#include "Box2D/Common/b2Math.h"
#include "Common.h"

#include <vector>

struct b2Vec2;
struct b2ContactEdge;
class b2Body;
class b2Shape;
class b2Fixture;


namespace AGK
{
	struct cVertex2D;

	class cPhysicsBody
	{
	public:
		enum eBodyType {
			eStatic, eKinematic, eDynamic
		};

		enum ePhysicsShape {
			eNone, eBox, eCircle, ePolygon, eCustom
		};

		enum eBodyOrigin {
			eUnknown, eSprite, eShape
		};

	protected:
		b2Body* pPhyBody = NULL;
		b2Shape* pPhyShape = NULL;
		eBodyOrigin eOrigin = eUnknown;
		std::vector<b2Shape*> vPhyShapes;
		UINT iPhyNumShapes = 0;
		float fPhyGravityScale = 1.0f;
		bool bPhySleep = true;
		bool bPhyAwake = true;
		USHORT iPhyCategories = 0x0001;
		USHORT iPhyCategoryMask = 0xffff;
		SHORT iPhyGroup = 0;
		b2ContactEdge* pPhyContactIter = NULL;

	public:

		virtual void SetPhysicsShape(ePhysicsShape shape, int index = -1) {}
		virtual void UpdatePhysics() {}

		int GetPhysicsNumShapes() { return (int)vPhyShapes.size(); }
		int GetPhysicsShapeNumVertices(int shapeID);
		cVertex2D GetPhysicsShapeVertex(int shapeID, int vertex);
		float GetPhysicsShapeVertexX(int shapeID, int vertex);
		float GetPhysicsShapeVertexY(int shapeID, int vertex);

		void SetPhysicsShapeBox(float x1, float y1, float x2, float y2, float angle, int id = -1);
		void SetPhysicsShapeChain(UINT points, void* vertices, bool loop, int id);
		void SetPhysicsShapeChain(UINT points, UINT index, bool loop, float x, float y, int id = -1);
		void SetPhysicsShapeCircle(float x, float y, float radius, int id = -1);
		void SetPhysicsShapePolygon(UINT points, void* vertices, int id);
		void SetPhysicsShapePolygon(UINT points, UINT index, float x, float y, int id = -1);
		int AddPhysicsShapeBox(float x1, float y1, float x2, float y2, float angle);
		int AddPhysicsShapeCircle(float x, float y, float radius);
		int AddPhysicsShapePolygon(UINT points, void* vertices);
		int AddPhysicsShapePolygon(UINT points, UINT index, float x, float y);
		int AddPhysicsShapeChain(UINT points, void* vertices, bool loop);
		int AddPhysicsShapeChain(UINT points, UINT index, bool loop, float x, float y);

		void SetPhysicsCOM(float x, float y);
		void CalculatePhysicsCOM();
		cVertex2D GetPhysicsCOM();
		float GetPhysicsCOMX();
		float GetPhysicsCOMY();

		void SetCollisionGroup(int group, int shapeID = -1);
		void SetCollisionCategoryBits(UINT categories, int shapeID = -1);
		void SetCollisionCategoryBit(UINT category, int flag, int shapeID = -1);
		void SetCollisionCollideBits(UINT mask, int shapeID = -1);
		void SetCollisionCollideBit(UINT category, int flag, int shapeID = -1);

		// physics dynamics/response
		void SetPhysicsOn(eBodyType type, float posx, float posy, float angle);
		void SetPhysicsOff();
		void SetPhysicsDelete();
		void SetPhysicsFriction(float friction, int shapeID = -1);
		void SetPhysicsRestitution(float restitution, int shapeID = -1);
		void SetPhysicsDensity(float density, int shapeID = -1);
		void SetPhysicsCanRotate(bool rotate);
		void SetPhysicsVelocity(float vx, float vy);
		void SetPhysicsAngularVelocity(float va);
		void SetPhysicsDamping(float damp);
		void SetPhysicsAngularDamping(float damp);
		void SetPhysicsIsBullet(bool bullet);
		void SetPhysicsMass(float mass);
		void SetPhysicsIsSensor(bool sensor, int shapeID = -1);

		void SetPhysicsGravityScale(float scale);
		float GetPhysicsGravityScale(void);
		void SetPhysicsInitiallyAwake(bool awake) { bPhyAwake = awake; }
		void SetPhysicsAllowSleep(bool sleep);
		float GetInertia(void);
		bool GetIsBullet(void);
		bool GetIsAwake(void);

		float GetPhysicsVelocityX();
		float GetPhysicsVelocityY();
		float GetPhysicsAngularVelocity();

		void SetPhysicsForce(float x, float y, float vx, float vy);
		void SetPhysicsTorque(float a);
		void SetPhysicsLinearImpulse(float x, float y, float vx, float vy);
		void SetPhysicsAngularImpulse(float a);

		bool GetFirstContact();
		bool GetNextContact();
		float GetContactWorldX();
		float GetContactWorldY();
		//cSprite* GetContactSprite2();

	protected:
		cPhysicsBody(eBodyOrigin origin) : eOrigin(origin) {}
		~cPhysicsBody();

		virtual void phy_calc_collision_radius() {};

		void phy_release_shapes();
		void phy_delete_shape(int index);
		void phy_replace_shape(b2Shape* oldShape, b2Shape* newShape);
		b2Fixture* phy_get_fixture_of_shape(b2Body* body, b2Shape* shape);
		float phy_get_collision_radius();
		void phy_add_shape(b2Shape* shape);
		b2Vec2* phy_convert_vertices(b2Vec2* vertices, UINT numVertices);
		void phy_set_filter(b2Shape* shape, SHORT group, USHORT category, USHORT mask, USHORT flags);
		void phy_clear_contacts();
	};
}


#endif	//	_H_AGK_PHYSICS_BODY_
