#ifndef PHYSXWRAPPER_H
#define PHYSXWRAPPER_H
#include <map>
#include <list>
#include <string>
#include <NxPhysics.h>
#include <NxCooking.h>
#include <NxStream.h>
#include "MVector3.h"
#include "GeNode.h"

#ifdef PHYSXWRAPPER_CPP
	#define EXTERN
#else
	#define EXTERN extern
#endif

/* actor groups */
#define TYPENO_CHARACTER	1
#define TYPENO_WALL			2
#define TYPENO_ITEM			3
#define TYPENO_CAMERA		4
#define TYPENO_LIGHT		5
#define TYPENO_TRIGGER		6

/* shape groups */
#define SHAPE_OTHER			0
#define SHAPE_SPHERE		1
#define SHAPE_VIEWVOL		2
#define SHAPE_DUMMY			3
#define SHAPE_LIGHT_SPHERE	4
#define SHAPE_TRIGGER		5

struct Trigger {
	NxActor* actor;
	void (*actionCallback)(NxActor*, Trigger*, NxTriggerFlag);
	std::string id;
};

EXTERN std::map<std::string, void (*)(NxActor*, Trigger*, NxTriggerFlag)> actionMap;
EXTERN std::list<Trigger*> triggerList;

class PhysXWrapper :
	public NxUserTriggerReport,
	public NxUserContactReport,
	public NxUserOutputStream {
private:
	NxCookingInterface *cooking;
	NxPhysicsSDK* physXSDK;

public:
	NxScene* scene;
	NxVec3 curGravity;

	PhysXWrapper(void);

	bool init(void);
	void release(void);
	void fetch(void);
	void advance(void);

	MVector3 quat2euler(NxQuat q);

    void onContactNotify(NxContactPair& pair, NxU32 events);
	void onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status);

	NxConvexShapeDesc* cookConvexMesh(const NxConvexMeshDesc& desc);
	NxTriangleMeshShapeDesc* cookTriangleMesh(const NxTriangleMeshDesc& desc);

	void reportError (NxErrorCode code, const char *message, const char* file, int line);
    NxAssertResponse reportAssertViolation (const char *message, const char *file,int line);
    void print (const char *message);
	
	void changeGravity(NxVec3 vec);
};

EXTERN PhysXWrapper physx;

class PhysXDebugRenderer : public GeNode {
private:
	const NxDebugRenderable* data;

public: 
    void render();
	void update();
	void setupColor(NxU32 color);
	void shadowPass(GeLight *) {};
};

EXTERN PhysXDebugRenderer gDebugRenderer;

class MemoryWriteBuffer : public NxStream
	{
	public:
								MemoryWriteBuffer();
	virtual						~MemoryWriteBuffer();
				void			clear();

	virtual		NxU8			readByte()								const	{ NX_ASSERT(0);	return 0;	}
	virtual		NxU16			readWord()								const	{ NX_ASSERT(0);	return 0;	}
	virtual		NxU32			readDword()								const	{ NX_ASSERT(0);	return 0;	}
	virtual		float			readFloat()								const	{ NX_ASSERT(0);	return 0.0f;}
	virtual		double			readDouble()							const	{ NX_ASSERT(0);	return 0.0;	}
	virtual		void			readBuffer(void* buffer, NxU32 size)	const	{ NX_ASSERT(0);				}

	virtual		NxStream&		storeByte(NxU8 b);
	virtual		NxStream&		storeWord(NxU16 w);
	virtual		NxStream&		storeDword(NxU32 d);
	virtual		NxStream&		storeFloat(NxReal f);
	virtual		NxStream&		storeDouble(NxF64 f);
	virtual		NxStream&		storeBuffer(const void* buffer, NxU32 size);

				NxU32			currentSize;
				NxU32			maxSize;
				NxU8*			data;
	};

class MemoryReadBuffer : public NxStream
	{
	public:
								MemoryReadBuffer(const NxU8* data);
	virtual						~MemoryReadBuffer();

	virtual		NxU8			readByte()								const;
	virtual		NxU16			readWord()								const;
	virtual		NxU32			readDword()								const;
	virtual		float			readFloat()								const;
	virtual		double			readDouble()							const;
	virtual		void			readBuffer(void* buffer, NxU32 size)	const;

	virtual		NxStream&		storeByte(NxU8 b)							{ NX_ASSERT(0);	return *this;	}
	virtual		NxStream&		storeWord(NxU16 w)							{ NX_ASSERT(0);	return *this;	}
	virtual		NxStream&		storeDword(NxU32 d)							{ NX_ASSERT(0);	return *this;	}
	virtual		NxStream&		storeFloat(NxReal f)						{ NX_ASSERT(0);	return *this;	}
	virtual		NxStream&		storeDouble(NxF64 f)						{ NX_ASSERT(0);	return *this;	}
	virtual		NxStream&		storeBuffer(const void* buffer, NxU32 size)	{ NX_ASSERT(0);	return *this;	}

	mutable		const NxU8*		buffer;
	};

#undef EXTERN
#endif