#ifndef __CPhysics_h
#define __CPhysics_h

#include "CMaterialManager.h"
#include "PhysicsGlobal.h"
#include "SPhysicsStructs.h"
#include "CPhysicsEntity.h"
#include "MPhysicsCallbacks.h"
#include "IPhysicsEntity.h"
#include "EPhysicsEnums.h"

//#include "CPhysicsJoint.h"

#include "CPhysicsCar.h"
#include "CPhysicsCamera.h"
#include "CPhysicsHinge.h"
#include "CPhysicsBallSocket.h"
#include "CPhysicsSlider.h"
#include "CPhysicsCorkscrew.h"
#include "CPhysicsUniversal.h"
#include "CPhysicsUpVector.h"
#include "CPhysicsCustom.h"
#include "CPhysicsPulley.h"
#include "CPhysicsRagdoll.h"
#include "CLog.h"

#include "IPhysicsWorld.h"

/// Root class.
/// All functionality for IPhysics is accessed through this class.
class CPhysics : public IPhysicsWorld
{
public:
	CPhysics(); 
	~CPhysics();
	void init(IrrlichtDevice* dev);
	void doLog(bool doLog, bool doEcho, bool path);
	void update();
	void update(f32 timestep_ms);
	CMaterialManager* getMaterialManager();
	void debug(bool enable);
	void close();
	
	IPhysicsEntity* addEntity(SPhysicsPrimitive* primitive);
	IPhysicsEntity* addEntity(IPhysicsBaseEntity* first,  ...);
	IPhysicsEntity* addEntity(SPhysicsTerrain* terrain);
	IPhysicsEntity* addEntity(SPhysicsStaticMesh* staticMesh);
	IPhysicsEntity* addEntity(SPhysicsMesh* mesh);
	IPhysicsEntity* addEntity(SPhysicsSerializedEntity* mesh);

	CPhysicsCamera* addCamera(SPhysicsCamera* camera);

	CPhysicsHinge* addHingeJoint(SPhysicsHingeJoint* joint);
	CPhysicsBallSocket* addBallSocketJoint(SPhysicsBallSocketJoint* joint);
	CPhysicsSlider* addSliderJoint(SPhysicsSliderJoint* joint);
	CPhysicsCorkscrew* addCorkscrewJoint(SPhysicsCorkscrewJoint* joint);
	CPhysicsUniversal* addUniversalJoint(SPhysicsUniversalJoint* joint);
	CPhysicsUpVector* addUpVectorJoint(SPhysicsUpVector* upVector);

	CPhysicsPulley* addPulley(SPhysicsPulley* pulley);

	IPhysicsCar* addCar(SPhysicsCar *car);

	IPhysicsEntity* throwTestCube(ICameraSceneNode* cam, f32 size, f32 mass, f32 velocity);
	IPhysicsEntity* throwTestCube(CPhysicsCamera* camEntity, f32 size, f32 mass, f32 velocity);
	IPhysicsEntity* throwTestCube(CPhysicsCamera* camEntity);
	
	IPhysicsEntity* throwTestSphere(ICameraSceneNode* cam, f32 size, f32 mass, f32 velocity);
	IPhysicsEntity* throwTestSphere(CPhysicsCamera* camEntity, f32 size, f32 mass, f32 velocity);
	IPhysicsEntity* throwTestSphere(CPhysicsCamera* camEntity);

	void setUpdateMode(PHYSICS_UPDATE_MODE updateMode);
	void setUpdatesPerSecond(s32 updatesPerSecond);

private:

	IPhysicsEntity* setUpRigidBody(NewtonBody *body, NewtonCollision* collision, SPhysicsAttributes* attributes);

	list<IPhysicsBaseEntity*> m_entityList;
	// timestep stuff
	f32 m_timestepAccumulator;
	ITimer* m_timer;
	f32 m_oldTime;
	PHYSICS_UPDATE_MODE m_updateMode;
	s32 m_updatesPerSecond;

	CLog* m_log;
	CMaterialManager* m_materialManager;
	CPhysicsCamera* m_camEntity;

	bool m_isCam;
	bool m_showDebug;

	static IrrlichtDevice* m_device;

	/*
	void addMeshToTreeCollisionStandard(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df meshScale);
	void addMeshToTreeCollision2TCoords(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df meshScale);
	void addMeshToTreeCollisionTangents(IMeshBuffer* meshBuffer, NewtonCollision* treeCollision, vector3df meshScale);

	void addCollisionStandardToMesh(IMeshBuffer* meshBuffer, vector3df meshScale);
	void addCollision2TCoordsToMesh(IMeshBuffer* meshBuffer, vector3df meshScale);
	void addCollisionTangentsToMesh(IMeshBuffer* meshBuffer, vector3df meshScale);
*/

	static void _cdecl NewtonDebugBody (const NewtonBody* body);
	static void _cdecl NewtonDebugCollision (const NewtonBody* body, int vertexCount, const float* FaceArray, int id);
	
	static void _cdecl getFromFile(void* serializeHandle, void* buffer, size_t size);

};


#endif