#ifndef PRIMITIVEFACTORY_H
#define PRIMITIVEFACTORY_H

#include <OgreNewt.h>
#include <Ogre.h>

#include <map>

class PrimitiveFactory : public Ogre::Singleton<PrimitiveFactory>
{
public:
	PrimitiveFactory(OgreNewt::World* world, Ogre::SceneManager* sceneManager, Ogre::String defaultMaterialName = "Debug/Blue");
	~PrimitiveFactory();

	typedef std::map<Ogre::String, OgreNewt::Body*> BodyMap;

	OgreNewt::Body* createBox(Ogre::String name = "", Ogre::String material = "", Ogre::Real mass = 1.0f, Ogre::Vector3 position = Ogre::Vector3::ZERO, Ogre::Vector3 scale = Ogre::Vector3::UNIT_SCALE, Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY, OgreNewt::MaterialID* materialId = NULL, int objectId = 0, Ogre::String mesh = "box.mesh");
	OgreNewt::Body* createBox(Ogre::SceneNode* sourceNode, float mass = 1.0f, OgreNewt::MaterialID* materialId = NULL, int objectId = 0);
	OgreNewt::Body* getBox(Ogre::String name);

	OgreNewt::Body* createEllipsoid(Ogre::String name = "", Ogre::String material = "", Ogre::Real mass = 1.0f, Ogre::Vector3 position = Ogre::Vector3::ZERO, Ogre::Vector3 scale = Ogre::Vector3::UNIT_SCALE, Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY, OgreNewt::MaterialID* materialId = NULL, int objectId = 0, Ogre::String mesh = "ellipsoid.mesh");
	OgreNewt::Body* createEllipsoid(Ogre::SceneNode* sourceNode, float mass = 1.0f, OgreNewt::MaterialID* materialId = NULL, int objectId = 0);
	OgreNewt::Body* getEllipsoid(Ogre::String name);

	OgreNewt::Body* createCylinder(Ogre::String name = "", Ogre::String material = "", Ogre::Real mass = 1.0f, Ogre::Vector3 position = Ogre::Vector3::ZERO, float radius = 0.5f, float height = 1.0f, Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY, OgreNewt::MaterialID* materialId = NULL, int objectId = 0, Ogre::String mesh = "cylinder.mesh");
	OgreNewt::Body* createCylinder(Ogre::SceneNode* sourceNode, float mass = 1.0f, OgreNewt::MaterialID* materialId = NULL, int objectId = 0);
	OgreNewt::Body* getCylinder(Ogre::String name);

	OgreNewt::Body* createChamferCylinder(Ogre::String name = "", Ogre::String material = "", Ogre::Real mass = 1.0f, Ogre::Vector3 position = Ogre::Vector3::ZERO, float radius = 0.5f, float height = 1.0f, Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY, OgreNewt::MaterialID* materialId = NULL, int objectId = 0, Ogre::String mesh = "chamfercylinder.mesh");
	OgreNewt::Body* createChamferCylinder(Ogre::SceneNode* sourceNode, float mass = 1.0f, OgreNewt::MaterialID* materialId = NULL, int objectId = 0);
	OgreNewt::Body* getChamferCylinder(Ogre::String name);

	OgreNewt::Body* createCone(Ogre::String name = "", Ogre::String material = "", Ogre::Real mass = 1.0f, Ogre::Vector3 position = Ogre::Vector3::ZERO, float radius = 0.5f, float height = 1.0f, Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY, OgreNewt::MaterialID* materialId = NULL, int objectId = 0, Ogre::String mesh = "cone.mesh");
	OgreNewt::Body* createCone(Ogre::SceneNode* sourceNode, float mass = 1.0f, OgreNewt::MaterialID* materialId = NULL, int objectId = 0);
	OgreNewt::Body* getCone(Ogre::String name);

	OgreNewt::Body* createConvexHull(Ogre::String mesh, Ogre::String name = "", Ogre::String material = "", Ogre::Real mass = 1.0f, Ogre::Vector3 position = Ogre::Vector3::ZERO, Ogre::Vector3 scale = Ogre::Vector3::UNIT_SCALE, Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY, OgreNewt::MaterialID* materialId = NULL, int objectId = 0);
	OgreNewt::Body* createConvexHull(Ogre::SceneNode* sourceNode, float mass = 1.0f, OgreNewt::MaterialID* materialId = NULL, int objectId = 0);
	OgreNewt::Body* getConvexHull(Ogre::String name);

	OgreNewt::Body* createTreeCollision(Ogre::String mesh, Ogre::String name = "", Ogre::String material = "", Ogre::Vector3 position = Ogre::Vector3::ZERO, Ogre::Vector3 scale = Ogre::Vector3::UNIT_SCALE, Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY, OgreNewt::MaterialID* materialId = NULL, int objectId = 0, bool optimize = true);
	OgreNewt::Body* createTreeCollision(Ogre::SceneNode* sourceNode, OgreNewt::MaterialID* materialId = NULL, int objectId = 0, bool optimize = true);
	OgreNewt::Body* getTreeCollision(Ogre::String name);
	
	BodyMap getBoxes() { return boxes; };
	BodyMap getEllipsoids() { return ellipsoids; };
	BodyMap getCylinders() { return cylinders; };
	BodyMap getChamferCylinders() { return chamferCylinders; };
	BodyMap getCones() { return chamferCylinders; };
	BodyMap getConvexHulls() { return convexHulls; };
	BodyMap getTreeCollisions() { return treeCollisions; };

	OgreNewt::Body* getBody(Ogre::String name);

	static PrimitiveFactory& getSingleton(void);
	static PrimitiveFactory* getSingletonPtr(void);

private:
	Ogre::SceneNode* createNode(Ogre::String mesh, Ogre::String name, Ogre::String material, Ogre::Vector3 position, Ogre::Vector3 scale, Ogre::Quaternion orientation);

	OgreNewt::World* world;
	Ogre::SceneManager* sceneManager;
	Ogre::String defaultMaterialName;

	int generatedObjectCount;
	
	BodyMap boxes;
	BodyMap ellipsoids;
	BodyMap cylinders;
	BodyMap chamferCylinders;
	BodyMap cones;
	BodyMap convexHulls;
	BodyMap treeCollisions;
};

#endif