#include <irrlicht.h>
#include <IPhysics.h>

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

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;

IrrlichtDevice* device;

class eventReceiver : public IEventReceiver
{
public:
	eventReceiver(CPhysics* physics, ICameraSceneNode* camera, int cubeMat)
	{
		m_physics = physics;
		m_camera = camera;

		m_cubeMat = cubeMat;
	}

	~eventReceiver()
	{
	}

	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 = 10;
				mass = 10;
				velocity = 5;
						
				SPhysicsPrimitive cube;

				cube.primitiveType = EPT_CUBE;
				cube.bodyType = EBT_DYNAMIC;
				cube.mass = mass;
				cube.node = device->getSceneManager()->addCubeSceneNode(size);
				cube.node->setMaterialFlag(EMF_LIGHTING, false);
				cube.node->setMaterialTexture(0, device->getVideoDriver()->getTexture("crate.jpg"));
				cube.size = vector3df(size, size, size);

				IPhysicsEntity* entity = m_physics->addEntity(&cube);
				entity->setMaterial(m_cubeMat);
				entity->setPosition(m_camera->getPosition());

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

			}
		} 

		//camEntity->onEvent(event);

		return false;
	}
protected:
	CPhysics* m_physics;
	ICameraSceneNode* m_camera;

	int m_cubeMat;
};

class materialC : public IMaterialCallback
{
public:
	materialC()
	{
	}

	~materialC()
	{
	}

	int beginCallback()
	{
		cout << "Oy, dont touch me" << endl;

		return 1;
	}
	
	int processCalback()
	{
		cout << "Oy, y u still touchin me" << endl;
		
		IParticleSystemSceneNode* ps = 0;
		ps = device->getSceneManager()->addParticleSystemSceneNode(false);
		
		ps->setPosition(getContactPosition());
		ps->setScale(core::vector3df(2,2,2));


		return 1;
	}

	void endCallback()
	{
		cout << "AVADAKEDAVRA...." << endl;
	}
};

int main()
{
	device = createDevice(EDT_OPENGL);
	
	ISceneManager* smgr = device->getSceneManager();
	IVideoDriver* driver = device->getVideoDriver();

	ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
	
	CPhysics physics;
	physics.init(device);

	CMaterialManager* materialManager = physics.getMaterialManager();
	int groundMat = materialManager->createMaterial();
	int cubeMat = materialManager->createMaterial();

	materialManager->setFriction(groundMat, groundMat, 1.4f, 0.8f);
	materialManager->setElasticity(groundMat, groundMat, 0.3f);
	materialManager->setSoftness(groundMat, groundMat, 0.05f);

	materialManager->setFriction(groundMat, cubeMat, 1.0f, 0.6f);
	materialManager->setElasticity(groundMat, cubeMat, 0.1f);
	materialManager->setSoftness(groundMat, cubeMat, 0.01f);
	
	materialC callBack;

	materialManager->setUserCollisionCallback(groundMat, cubeMat, &callBack);
	
	//Create Level Collision
	device->getFileSystem()->addZipFileArchive("../../Media/map-20kdm2.pk3");

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

	SPhysicsStaticMesh level;
	level.mesh = levelmesh;
	level.node = levelnode;
	level.scale = vector3df(1, 1, 1);
	level.node->setScale(level.scale);

	IPhysicsEntity* levelEntity = physics.addEntity(&level);
	levelEntity->setPosition(vector3df(-1300,-144,-1249)*level.scale);	
	levelEntity->setMaterial(groundMat);

	SPhysicsPrimitive cube2;

	cube2.primitiveType = EPT_CUBE;
	cube2.bodyType = EBT_DYNAMIC;
	cube2.mass = 0;
	cube2.node = device->getSceneManager()->addCubeSceneNode();
	cube2.node->setMaterialFlag(EMF_LIGHTING, false);
	cube2.node->setMaterialTexture(0, device->getVideoDriver()->getTexture("../../Media/crate.jpg"));
	cube2.size = vector3df(6, 10, 1);

	IPhysicsEntity* entity2 = physics.addEntity(&cube2);
	entity2->setMaterial(cubeMat);
	entity2->setPosition(camera->getPosition());

	eventReceiver receiver(&physics, camera, cubeMat);
	device->setEventReceiver(&receiver);

	while(device->run())
	{ 
		driver->beginScene(true, true, 0);

		physics.update();

		smgr->drawAll();

		driver->endScene();
	}

	physics.close();

	return 0;
}