#include <Irrlicht.h>
#include <IPhysics.h>

#pragma comment(lib, "Irrlicht.lib")
#pragma comment(lib, "IPhysics.lib")

CPhysics physics;
IVideoDriver* driver;
ISceneManager* smgr;
ICameraSceneNode* cam;

ITexture* cubeTexture;
ITexture* sphereTexture;

class EventReceiver : public IEventReceiver
{
public:
	bool OnEvent(SEvent event)
	{
		if(event.EventType == EET_MOUSE_INPUT_EVENT)
		{
			if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
			{
				//Throw test cube from camera's position
				f32 size,mass,velocity;
				size = 20;
				mass = 40;
				velocity = 40;
						
				SPhysicsPrimitive cube;

				cube.primitiveType = EPT_CUBE;
				cube.bodyType = EBT_DYNAMIC;
				cube.mass = mass;
				cube.node = smgr->addCubeSceneNode(size);
				cube.node->setMaterialFlag(EMF_LIGHTING, false);
				cube.node->setMaterialTexture(0, cubeTexture);
				cube.size = vector3df(size, size, size);

				IPhysicsEntity* entity = physics.addEntity(&cube);

				entity->setPosition(cam->getPosition());

				vector3df vel = (cam->getTarget() - cam->getPosition()).normalize() * velocity;
				entity->setVelocity(vel);

			}
			else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
			{
				//Throw test sphere from camera's position
				f32 size,mass,velocity;
				size = 20;
				mass = 20;
				velocity = 40;

				SPhysicsPrimitive sphere;

				sphere.primitiveType = EPT_SPHERE;
				sphere.bodyType = EBT_DYNAMIC;
				sphere.mass = mass;
				sphere.node = smgr->addSphereSceneNode(size);
				sphere.node->setMaterialFlag(EMF_LIGHTING, false);
				sphere.size = vector3df(size,size,size);

				IPhysicsEntity* entity = physics.addEntity(&sphere);

				entity->setPosition(cam->getPosition());

				vector3df vel = (cam->getTarget() - cam->getPosition()).normalize() * velocity;
				entity->setVelocity(vel);
			}
		} 

		return false;
	}
};

int main()
{
	IrrlichtDevice* device = createDevice(EDT_DIRECT3D9);

	driver = device->getVideoDriver();
	smgr = device->getSceneManager();

	cubeTexture = driver->getTexture("../../Media/Crate.jpg");

	cam = smgr->addCameraSceneNodeFPS();

	EventReceiver reciever;
	device->setEventReceiver(&reciever);

	physics.init(device);
	
	device->getFileSystem()->addZipFileArchive("../../Media/map-20kdm2.pk3");

	IAnimatedMesh* levelmesh = smgr->getMesh("20kdm2.bsp");
	IAnimatedMeshSceneNode* levelnode = smgr->addAnimatedMeshSceneNode(levelmesh);

	//To load a static mesh like a level we will use the static mesh struct
	SPhysicsStaticMesh staticMesh;
	staticMesh.mesh = levelmesh;
	staticMesh.node = levelnode;
	staticMesh.scale = vector3df(1, 1, 1);

	IPhysicsEntity* levelEntity = physics.addEntity(&staticMesh);
	levelEntity->setPosition(vector3df(-1300,-144,-1249));	

	//////////////Make a hinge joint///////////////////////////////
	///Make one side of the hinge
	ISceneNode* hinge1Node = smgr->addCubeSceneNode();
	hinge1Node->setMaterialFlag(EMF_LIGHTING, false);
	hinge1Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive hinge1;
	hinge1.size = hinge1Node->getTransformedBoundingBox().getExtent();
	hinge1.scale = vector3df(6, 10, 1);
	hinge1.mass = 10;
	hinge1.node = hinge1Node;
	hinge1.primitiveType = EPT_CUBE;

	IPhysicsEntity* hinge1Entity = physics.addEntity(&hinge1);
	hinge1Entity->setPosition(vector3df(90,-10,150));

	///Make second side of the hinge
	ISceneNode* hinge2Node = smgr->addCubeSceneNode();
	hinge2Node->setMaterialFlag(EMF_LIGHTING, false);
	hinge2Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive hinge2;
	hinge2.size = hinge2Node->getTransformedBoundingBox().getExtent();
	hinge2.scale = vector3df(6, 10, 1);
	hinge2.node = hinge2Node;
	hinge2.primitiveType = EPT_CUBE;
	hinge2.bodyType = EBT_STATIC;

	IPhysicsEntity* hinge2Entity = physics.addEntity(&hinge2);
	hinge2Entity->setPosition(vector3df(150,-10,150));

	///Make the connecting hinge joint
	SPhysicsHingeJoint hinge;
	hinge.parent = hinge2Entity;
	hinge.child = hinge1Entity;
	hinge.pivot = hinge1Entity->getPosition() + vector3df(30,0,0);
	hinge.pin = vector3df(0,1,0);
	hinge.breakForce = vector3df(2000,2000,2000);
	
	CPhysicsHinge* hingeJoint = physics.addHingeJoint(&hinge);
	//////////////End of hinge joint///////////////////////////////
	

	/////////////Make ball socket joint////////////////////////////
	///Make the ball scene node
	ISceneNode* ballNode = smgr->addSphereSceneNode();
	ballNode->setMaterialFlag(EMF_LIGHTING, false);
	ballNode->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	///Make the ball entity
	SPhysicsPrimitive ball;
	ball.size = ballNode->getTransformedBoundingBox().getExtent();
	ball.scale = vector3df(4, 4, 4);
	ball.node = ballNode;
	ball.mass = 10.0f;
	ball.primitiveType = EPT_CUBE;
	ball.bodyType = EBT_STATIC;

	IPhysicsEntity* ballEntity = physics.addEntity(&ball);
	ballEntity->setPosition(vector3df(-50,20,150));

	///Make the socket scene node
	ISceneNode* socketNode = smgr->addCubeSceneNode();
	socketNode->setMaterialFlag(EMF_LIGHTING, false);
	socketNode->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	///Make the socket entity
	SPhysicsPrimitive socket;
	socket.size = socketNode->getTransformedBoundingBox().getExtent();
	socket.scale = vector3df(6, 6, 1);
	socket.node = socketNode;
	socket.mass = 10.0f;
	socket.primitiveType = EPT_CUBE;

	IPhysicsEntity* socketEntity = physics.addEntity(&socket);
	socketEntity->setPosition(vector3df(-50,-30,150));

	///Make the connecting ball socket joint
	SPhysicsBallSocketJoint ballSocket;
	ballSocket.parent = socketEntity;
	ballSocket.child = ballEntity;
	ballSocket.pivot = ballEntity->getPosition() + vector3df(0,-20,0);
	ballSocket.pin = vector3df(0,1,0);
	ballSocket.breakForce = vector3df(50,50,50);

	CPhysicsBallSocket* ballSocketJoint = physics.addBallSocketJoint(&ballSocket);
	////////////////////End of ball socket joint///////////////////



	////////////////////Make a corkscrew joint/////////////////////
	///Make the entity on which the cork will screw and slide
	ISceneNode* cork1Node = smgr->addCubeSceneNode();
	cork1Node->setMaterialFlag(EMF_LIGHTING, false);
	cork1Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive cork1;
	cork1.size = cork1Node->getTransformedBoundingBox().getExtent();
	cork1.scale = vector3df(20, 2, 1);
	cork1.node = cork1Node;
	cork1.mass = 10.0f;
	cork1.primitiveType = EPT_CUBE;
	cork1.bodyType = EBT_STATIC;

	IPhysicsEntity* cork1Entity = physics.addEntity(&cork1);
	cork1Entity->setPosition(vector3df(400, 20, 90));

	///Make the corkscrew itself
	ISceneNode* cork2Node = smgr->addCubeSceneNode();
	cork2Node->setMaterialFlag(EMF_LIGHTING, false);
	cork2Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive cork2;
	cork2.size = cork2Node->getTransformedBoundingBox().getExtent();
	cork2.scale = vector3df(6, 8, 2);
	cork2.node = cork2Node;
	cork2.mass = 10.0f;
	cork2.primitiveType = EPT_CUBE;

	IPhysicsEntity* cork2Entity = physics.addEntity(&cork2);
	cork2Entity->setPosition(vector3df(400, 20, 90));

	///Make the connecting corkscrew joint
	SPhysicsCorkscrewJoint corkScrew;
	corkScrew.parent = cork2Entity;
	corkScrew.child = cork1Entity;
	corkScrew.pivot = cork1Node->getPosition();
	corkScrew.pin = vector3df(1,0,0);
	corkScrew.breakForce = vector3df(50,50,50);

	CPhysicsCorkscrew* corkScrewJoint = physics.addCorkscrewJoint(&corkScrew);
	////////////////////End of corkscrew joint///////////////////
	


	////////////////////Make a slider joint/////////////////////
	///Make the slider on which the beat will slide
	ISceneNode* slider1Node = smgr->addCubeSceneNode();
	slider1Node->setMaterialFlag(EMF_LIGHTING, false);
	slider1Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive slider1;
	slider1.size = slider1Node->getTransformedBoundingBox().getExtent();
	slider1.scale = vector3df(20, 2, 1);
	slider1.node = slider1Node;
	slider1.mass = 10.0f;
	slider1.primitiveType = EPT_CUBE;
	slider1.bodyType = EBT_STATIC;

	IPhysicsEntity* slider1Entity = physics.addEntity(&slider1);
	slider1Entity->setPosition(vector3df(-200, 20, 90));

	///Make the beat
	ISceneNode* slider2Node = smgr->addCubeSceneNode();
	slider2Node->setMaterialFlag(EMF_LIGHTING, false);
	slider2Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive slider2;
	slider2.size = slider2Node->getTransformedBoundingBox().getExtent();
	slider2.scale = vector3df(6, 8, 2);
	slider2.node = slider2Node;
	slider2.mass = 10.0f;
	slider2.primitiveType = EPT_CUBE;

	IPhysicsEntity* slider2Entity = physics.addEntity(&slider2);
	slider2Entity->setPosition(vector3df(-200, 20, 90));

	///Make the connecting slider joint
	SPhysicsSliderJoint slider;
	slider.parent = slider2Entity;
	slider.child = slider1Entity;
	slider.pivot = slider1Node->getPosition();
	slider.pin = vector3df(1,0,0);
	slider.breakForce = vector3df(50,50,50);

	CPhysicsSlider* sliderJoint = physics.addSliderJoint(&slider);
	////////////////////End of slider joint///////////////////



	////////////////////Make a universal joint/////////////////////
	///Make one side of the universal joint
	ISceneNode* universal1Node = smgr->addCubeSceneNode();
	universal1Node->setMaterialFlag(EMF_LIGHTING, false);
	universal1Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive universal1;
	universal1.size = universal1Node->getTransformedBoundingBox().getExtent();
	universal1.scale = vector3df(6, 8, 2);
	universal1.node = universal1Node;
	universal1.mass = 10.0f;
	universal1.primitiveType = EPT_CUBE;
	universal1.bodyType = EBT_STATIC;

	IPhysicsEntity* universal1Entity = physics.addEntity(&universal1);
	universal1Entity->setPosition(vector3df(100, 200, 100));

	///Make the second side of the universal joint
	ISceneNode* universal2Node = smgr->addCubeSceneNode();
	universal2Node->setMaterialFlag(EMF_LIGHTING, false);
	universal2Node->setMaterialTexture(0, driver->getTexture("../../Media/crate.jpg"));

	SPhysicsPrimitive universal2;
	universal2.size = universal2Node->getTransformedBoundingBox().getExtent();
	universal2.scale = vector3df(6, 8, 2);
	universal2.node = universal2Node;
	universal2.mass = 10.0f;
	universal2.primitiveType = EPT_CUBE;

	IPhysicsEntity* universal2Entity = physics.addEntity(&universal2);
	universal2Entity->setPosition(vector3df(100, 200, 100));

	///Make the connecting universal joint
	SPhysicsUniversalJoint universal;
	universal.parent = universal2Entity;
	universal.child = universal1Entity;
	universal.pivot = universal1Node->getPosition();
	universal.pin = vector3df(1,0,0);
	universal.pin2 = vector3df(0,0,1);
	universal.breakForce = vector3df(3000,3000,3000);

	CPhysicsUniversal* universalJoint = physics.addUniversalJoint(&universal);
	////////////////////End of universal joint///////////////////
 
	while (device->run())
	{
		if (device->isWindowActive())
		{
			driver->beginScene(true, true, SColor(255,0,0,0));

			smgr->drawAll();

			physics.update();

			driver->endScene();
		}
	}

	physics.close();

	return 0;
}