#ifndef __SPhysicsStructs_h
#define __SPhysicsStructs_h

#include "PhysicsGlobal.h"
#include "EPhysicsEnums.h"
#include "IPhysicsEntity.h"

/// Attributes struct.
//! These attributes are shared by all the primitive shapes. This struct just contains common data - the shape classes derive
//! from this and extend it; you can't create a physics entity from this alone.
struct SPhysicsAttributes
{
	/// Constructor for setting default values.
	SPhysicsAttributes() : mass(10.0f), node(NULL), scale(vector3df(1,1,1)), bodyType(EBT_DYNAMIC) {};
	/// Mesh scale. See notes for ::SPhysicsTerrain.
	vector3df scale;
	/// Mass of the body.
	f32 mass;
	/// The type of body - either EBT_DYNAMIC (affected by collisions and gravity) or EBT_STATIC (solid but unaffected by collisions or gravity).
	ENUMERATED_BODY_TYPE bodyType;
	/// A pointer to the Irrlicht scene node. If there are several then this should be the root node, and the others added to it as child nodes.
	ISceneNode* node;
};

/// Primitive struct.
//! Use this for creating newton primitives.
struct SPhysicsPrimitive : SPhysicsAttributes
{
	/// Default constructor.
	SPhysicsPrimitive() {};
	/// Constructor to create this struct without declaring it
	SPhysicsPrimitive(ISceneNode* node, ENUMERATED_PRIMITIVE_TYPE primitiveType, vector3df meshScale, vector3df size, f32 height, f32 mass)
	{
		this->node = node;
		this->primitiveType = primitiveType;
		this->scale = scale;
		this->size = size;
		this->height = height;
		this->mass = mass;
	}
	/// Enum to store type of the primitive.
	ENUMERATED_PRIMITIVE_TYPE primitiveType;
	/// Offset matrix to the primitive.
	matrix4 offset;
	/// Size of the primitive (for box, sphere).
	vector3df size;
	/// Radius of the primitive (for cone, capsule, cylinder, chamfer cylinder).
	f32 radius;
	/// Set height of the primitive (for cone, capsule, cylinder, chamfer cylinder).
	f32 height;
};

/// Mesh struct.
//! Use this for creating dynamic meshes.
struct SPhysicsMesh : SPhysicsAttributes
{
	/// Default constructor for setting default values.
	SPhysicsMesh() : mesh(NULL), frame(0) {};
	/// Pointer to the Irrlicht IAnimatedMesh that the scene node was created from.
	IAnimatedMesh* mesh;
	/// The number of the frame to create the physics body from.
	int frame;
};

/// Terrain struct.
//! Use this for creating terrain.
struct SPhysicsTerrain
{
	/// Pointer to Irrlicht ITerrainSceneNode.
	ITerrainSceneNode* node;
	/// Terrain scale. When IPhysics creates the terrain, it will apply this scale to the Irrlicht node as well as the Newton mesh, so you don't have to worry about that.
	/// However, you do need to ensure that the terrain scale is set to something, otherwise your terrain will be created with a scale of (0,0,0) and so will be invisible.
	/// If you want it to be the actual size of the mesh, set it to (1, 1, 1).
	vector3df scale;
};

/// Static Mesh struct.
//! Use this for creating static meshes, for example rooms and levels.
struct SPhysicsStaticMesh
{
	SPhysicsStaticMesh() : scale(vector3df(1,1,1)) {};
	/// Pointer to the Irrlicht IAnimatedMesh that the scene node was created from.
	IAnimatedMesh* mesh;
	/// Mesh scale. See notes for ::SPhysicsTerrain.
	vector3df scale;
	/// Pointer to the scene node.
	ISceneNode* node;
};

/// Static Mesh struct.
//! Use this for loading serialized meshes
struct SPhysicsSerializedEntity : SPhysicsAttributes
{
	///Path of the serialized mesh.
	stringc path;
};

/// Car struct.
//! Use this for creating a car. It is important to remember that cars in IPhysics <B>must</B> be constructed with the positive y-axis as up, and the vehicle pointing in the <B>negative</B> x-axis.
//! The reason for this is that otherwise a positive torque makes the car go backwards, which is far more confusing and messy than just having to construct the car this way.
//! It is also assumed that you are building the car around the origin.
//! This means you'll probably need to orient your car and wheel meshes in your modelling program to meet this criteria, although rest assured this system will become more flexible in future versions.
struct SPhysicsCar
{
	/// The car body's offset from the origin. For example, if you want the car body to be 5 units above the ground, this should be (0, 5.0f, 0).
	vector3df carBodyOffset;
	/// The car body is currently modelled as a box, with these dimensions. This will be changed soon!
	vector3df carBodySize;
	/// The car's mass. Note that this is the mass of the car body, not the tires.
	f32 carMass;

	/// The front axle's offset from the origin. This will determine how far forwards the front wheels are.
	f32 frontAxleOffset;
	/// The rear axle's offset from the origin. This should be a positive number. This will determine how far back the rear wheels are.
	f32 rearAxleOffset;

	/// The axle width. The same value will be used for both front and back axles. This will determine how far apart the left and right wheels are.
	f32 axleWidth;

	/// The mass of a tire.
	f32 tireMass;

	/// The width of a tire.
	f32 tireWidth;
	/// The radius of a tire.
	f32 tireRadius;

	/// The scene node for the car body.
	ISceneNode* carBodyNode;
	/// The scene node for the <B>front left</B> tire.
	ISceneNode* tireNode_FL;
	/// The scene node for the <B>front right</B> tire.
	ISceneNode* tireNode_FR;
	/// The scene node for the <B>rear left</B> tire.
	ISceneNode* tireNode_RL;
	/// The scene node for the <B>rear right</B> tire.
	ISceneNode* tireNode_RR;

	/// The tire suspension shock - this is passed straight to Newton. From the Newton docs: "parametrized damping constant for a spring, mass, damper system. A value of one corresponds to a critically damped system."
	f32 tireSuspensionShock;
	/// The tire suspension spring - this is passed straight to Newton. From the Newton docs: "parametrized spring constant for a spring, mass, damper system. A value of one corresponds to a critically damped system."
	f32 tireSuspensionSpring; 
	/// The tire suspension length - this is passed straight to Newton. From the Newton docs: "distance from the tire set position to the upper stop on the vehicle body frame. The total suspension length is twice that."
	f32 tireSuspensionLength;

	/// The max steering angle the car is able to make. A higher number means the car will be able to make tighter turns.
	f32 maxSteerAngle;
	/// The max torque that the car can produce. A higher number means that the car gan go faster, but too high and it will start to skid and lose control.
	f32 maxTorque;
	/// The max brakes that the car has. A higher number means stronger brakes.
	f32 maxBrakes;
};


/// Camera struct.
//! Use this for applying physics on camera. This is used for player
//! collision in games.
struct SPhysicsCamera
{
	/// Default constructor for setting some default values.
	SPhysicsCamera() : node(NULL), bodySize(vector3df(1,1,1)), mass(10.0f), sensitivity(3.0f), moveSpeed(100.0f) {};
	/// Camera Scene Node.
	ICameraSceneNode* node;
	/// Camera collsion body size.
	vector3df bodySize;
	/// Mass of the camera.
	f32 mass;
	/// Sensitivity of mouse (How fast the player rotates).
	f32 sensitivity;
	/// Camera's moving speed.
	f32 moveSpeed;
};

/// Camera Keymap struct.
//! Use this struct to assign a keymap for camera movement.
struct SCameraKeyMap
{
	/// The default constructor.
	SCameraKeyMap() {};
	/// A constructor used to avoid declaring this structure.
	SCameraKeyMap(ENUMERATED_ACTION a, EKEY_CODE k) : action(a), key(k) {};
	/// Enum to store the action that will be done by the current key.
	ENUMERATED_ACTION action;
	/// The key to be checked for press.
	EKEY_CODE key;
};


struct SPhysicsUniversalJoint
{
	/// Default constructor to set some default values.
	SPhysicsUniversalJoint() : parent(NULL), child(NULL), breakForce(vector3df(0,0,0)) {};
	/// Pointer to the parent entity.
	IPhysicsBaseEntity* parent;
	/// Pointer to the child entity.
	IPhysicsBaseEntity* child;
	/// Position of the pivot of the joint.
	vector3df pivot;
	/// Position of the pin of the joint.
	vector3df pin;
	/// Position of the second pin of the joint (Universal joint).
	vector3df pin2;
	/// Amount of force required to break the joint.
	vector3df breakForce;
};

struct SPhysicsHingeJoint
{
	/// Default constructor to set some default values.
	SPhysicsHingeJoint() : parent(NULL), child(NULL), breakForce(vector3df(0,0,0)), maxAngle(0.0f), minAngle(-90.0f){};
	/// Pointer to the parent entity.
	IPhysicsBaseEntity* parent;
	/// Pointer to the child entity.
	IPhysicsBaseEntity* child;
	/// Position of the pivot of the joint.
	vector3df pivot;
	/// Position of the pin of the joint.
	vector3df pin;
	/// Amount of force required to break the joint.
	vector3df breakForce;
	/// Minimum angle movement allowed of the joint.
	f32 minAngle;
	/// Maximum angle movement allowed of the joint.
	f32 maxAngle;
};

/// Joint struct
//! Use this struct for creating all newton built-in joints
//! except upVector joint.
struct SPhysicsCorkscrewJoint
{
	/// Default constructor to set some default values.
	SPhysicsCorkscrewJoint() : parent(NULL), child(NULL), breakForce(vector3df(0,0,0)) {};
	/// Pointer to the parent entity.
	IPhysicsBaseEntity* parent;
	/// Pointer to the child entity.
	IPhysicsBaseEntity* child;
	/// Position of the pivot of the joint.
	vector3df pivot;
	/// Position of the pin of the joint.
	vector3df pin;
	/// Amount of force required to break the joint.
	vector3df breakForce;
};

/// Joint struct
//! Use this struct for creating all newton built-in joints
//! except upVector joint.
struct SPhysicsSliderJoint
{
	/// Default constructor to set some default values.
	SPhysicsSliderJoint() : parent(NULL), child(NULL), breakForce(vector3df(0,0,0)) {};
	/// Pointer to the parent entity.
	IPhysicsBaseEntity* parent;
	/// Pointer to the child entity.
	IPhysicsBaseEntity* child;
	/// Position of the pivot of the joint.
	vector3df pivot;
	/// Position of the pin of the joint.
	vector3df pin;
	/// Amount of force required to break the joint.
	vector3df breakForce;
};

/// Base Joint struct
//! Use this struct for creating all newton built-in joints
//! except upVector joint.
struct SPhysicsBallSocketJoint
{
	/// Default constructor to set some default values.
	SPhysicsBallSocketJoint() : parent(NULL), child(NULL), breakForce(vector3df(0,0,0)), maxAngle(0.0f), minAngle(-90.0f), maxTwistAngle(90.0f) {};
	/// Pointer to the parent entity.
	IPhysicsBaseEntity* parent;
	/// Pointer to the child entity.
	IPhysicsBaseEntity* child;
	/// Position of the pivot of the joint.
	vector3df pivot;
	/// Position of the pin of the joint.
	vector3df pin;
	/// Minimum angle movement allowed of the joint.
	f32 minAngle;
	/// Maximum angle movement allowed of the joint.
	f32 maxAngle;
	/// Maximum twist angle of the joint.
	f32 maxTwistAngle;
	/// Amount of force required to break the joint.
	vector3df breakForce;
};

/// UpVector struct.
//! Use this to create an upVector joint on a body.
struct SPhysicsUpVector
{
	/// Entitiy on which the upVector joint will be applied.
	IPhysicsBaseEntity* body;
	/// Pin of the upVector joint.
	vector3df pin;
};

/// CustomJoint struct.
//! Use this struct to create a customJoint.
struct SPhysicsCustomJoint
{ 
	/// Max angle of freedom allowed
	int maxDOF;
	/// Child of the joint.
	IPhysicsBaseEntity* child;
	/// Parent of the joint.
	IPhysicsBaseEntity* parent;
};

/// Pulley struct.
//! Use this struct to create a pulley.
struct SPhysicsPulley
{
	/// The gearing ration of the pulley.
	f32 gearRatio;
	/// The child of the pulley.
	IPhysicsBaseEntity* child;
	/// The parent of the pulley.
	IPhysicsBaseEntity* parent;
	/// Movement pin of the parent
	vector3df parentPin;
	/// Movement pin of the child.
	vector3df childPin;
};

/// RagDollParts struct
//! This struct is used to create the visual elements of the ragdoll.
struct SDollParts
{
	ISceneNode* head;
	ISceneNode* upperChest;
	ISceneNode* lowerChest;
	ISceneNode* rUpperArm;
	ISceneNode* rLowerArm;
	ISceneNode* rHand;
	ISceneNode* lUpperArm;
	ISceneNode* lLowerArm;
	ISceneNode* lHand;
	ISceneNode* rUpperLeg;
	ISceneNode* rLowerLeg;
	ISceneNode* rFoot;
	ISceneNode* lUpperLeg;
	ISceneNode* lLowerLeg;
	IPhysicsBaseEntity* lFoot;
};

/// Ragdoll struct.
//! Use this struct to create a ragdoll.
struct SPhysicsRagdoll
{
	/// Position of the ragdoll.
	vector3df position;
	/// Scale of the ragdoll.
	vector3df scale;
	/// Type of the ragdoll.
	ENUMERATED_RAGDOLL_TYPE type;
	/// A struct holding the visual elements of the ragdoll.
	SDollParts body;
};

#endif