
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
#include <string>

//---------------------------------------------------------------------

#include <GlobalDevice.h>
#include <GameObject.h>
#include <Player.h>

const char* APPLICATION_TITLE = "This is obviously simple - A Volatile Dove game - v1.1";

//---------------------------------------------------------------------

int main(int argc, char* argv[])
{
	bool isWindowed = false;
	irr::video::E_DRIVER_TYPE driverType = 
#ifdef WIN32
          video::EDT_DIRECT3D9;
#else
          video::EDT_OPENGL;
#endif
	for (int i = 1; i < argc; ++i)
	{
		std::string strargv = std::string(argv[i]);
		if (strargv == std::string("--windowed"))
			isWindowed = true;
		else if (strargv == std::string("--opengl"))
			driverType = video::EDT_OPENGL;
		else if (strargv == std::string("--direct3d8"))
			driverType = video::EDT_DIRECT3D8;
		else if (strargv == std::string("--direct3d9"))
			driverType = video::EDT_DIRECT3D9;
		else if (strargv == std::string("--software"))
			driverType = video::EDT_SOFTWARE;
		else if (strargv == std::string("--burningsvideo"))
			driverType = video::EDT_BURNINGSVIDEO;
	}
	dimension2d<s32> windowSize(640, 480);
	if (!isWindowed)
	{
		windowSize = GlobalDevice::getDesktopResolution();
	}
	GlobalDevice globalDevice(windowSize, !isWindowed, driverType);

	IrrlichtDevice* device = GlobalDevice::getDevice();
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	IGUIEnvironment* guienv = device->getGUIEnvironment();
	
	device->setResizeAble(true);

	bool restartGame = false;
	do
	{
		//int emergencyCallcombination = 0;
		restartGame = false;
		smgr->clear();

		ITexture* menutext = driver->getTexture("data/menutext.png");

		ITexture* wintext = driver->getTexture("data/win.png");

		ICameraSceneNode* camera = smgr->addCameraSceneNode(0, vector3df(0,50,-40), vector3df(0,20,0));
		
		ILightSceneNode* light = smgr->addLightSceneNode(0, core::vector3df(0,50,0),video::SColorf(1.0f, 1.0f, 1.0f, 1.0f), 200.f);
		light->setLightType(video::ELT_POINT);
		light->getLightData().AmbientColor = SColor(128,128,128,128);
		light->getLightData().DiffuseColor = SColor(255,255,255,255);
		light->getLightData().SpecularColor = SColor(255,127,127,127);

		IMeshSceneNode* ground = GlobalDevice::loadNodeFromMeshFile("data/ground1.3ds");
		
		Player player;

		IGUIFont* font = guienv->getFont("data/fontcourier.bmp");
		if (font) guienv->getSkin()->setFont(font);

		GameObjectVector gameObjects;
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_GIRLBODY, vector3df(0.f,0.f,40.f)));
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_BATTERY, vector3df(40.f,0.f,15.f)));
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_MEDICALROBOT, vector3df(-65.f,0.f,25.f)));
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_CHEMICALLIQUID, vector3df(70.f,0.f,30.f)));
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_CHEMICALBOTTLE, vector3df(65.f,0.f,35.f)));
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_PAPER, vector3df(99.f,20.f,-10.f)));
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_GIRLBLOOD, vector3df(30.f,0.f,40.f)));
		gameObjects.push_back(new GameObject(GameObject::GAMEOBJECT_SCREWDRIVER, vector3df(-55.f,0.f,-10.f)));
		
		u32 framesWaitForTitle = 0;
		vector2df screenShakePos(0.f, 0.f);
		
		bool foundStupidEnd[2];
		foundStupidEnd[0]=false;
		foundStupidEnd[1]=false;

		bool winTheGame = false;
		while(device->run())
		{
			camera->setAspectRatio((float)GlobalDevice::getMainWindowSize().X / (float)GlobalDevice::getMainWindowSize().Y);
			if (GlobalDevice::getFrameDuration() < 10000)
			{
				//let the computer available for other tasks
				device->sleep((u32)(10 - GlobalDevice::getFrameDuration() / 1000));
			}
	        
			//-------------------------
			// manage scene
			
			player.manage(gameObjects);
			bool needShakingScreen = false;
			GameObjectVector pendingCreatedObjects;

			for (GameObjectVector::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
			{
				GameObject* go = *it;
				if (go != NULL)
				{
					go->manage(&player, gameObjects);
					
					GameObjectVector currentObjectCreatedObjects = go->getPendingCreatedObjects();
					pendingCreatedObjects.insert(pendingCreatedObjects.begin(), currentObjectCreatedObjects.begin(), currentObjectCreatedObjects.end());
					go->clearPendingCreatedObjects();

					int stupidEndId = go->getAndClearStupidEndId();
					if (stupidEndId != -1) foundStupidEnd[stupidEndId] = true;
					
					if (go->needShakingScreen()) needShakingScreen = true;
				}
			}

			//add newly created objects
			for (GameObjectVector::iterator it = pendingCreatedObjects.begin(); it != pendingCreatedObjects.end(); it++)
				gameObjects.push_back(*it);

			//delete destroyed objects
			for (GameObjectVector::iterator it = gameObjects.begin(); it != gameObjects.end(); it++) 
			{
				if ((*it) != NULL && (*it)->isAutodestroyed()) 
				{
					delete (*it);
					(*it) = NULL;
				}
			}
			
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_X]) break;
			else if (GlobalDevice::getEventManager()->keys[KEY_KEY_R]) {restartGame = true;break;}
			/*
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_S] && emergencyCallcombination==0) {emergencyCallcombination++;}
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_I] && emergencyCallcombination==1) {emergencyCallcombination++;}
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_M] && emergencyCallcombination==2) {emergencyCallcombination++;}
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_P] && emergencyCallcombination==3) {emergencyCallcombination++;}
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_L] && emergencyCallcombination==4) {emergencyCallcombination++;}
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_E] && emergencyCallcombination==5) {emergencyCallcombination++;}
			if (emergencyCallcombination == 6)
			{
				winTheGame = true;
				emergencyCallcombination = 7;
			}
			*/
			if (GlobalDevice::getEventManager()->keys[KEY_KEY_C]) winTheGame = true;

			//-------------------------
			// draw background and ground
			
			driver->beginScene(true, true, SColor(255,100,101,140));

			if (GlobalDevice::getEventManager()->keys[KEY_SPACE] && false)
			{
				camera->setPosition(player.getPosition()+vector3df(0.f,5.f,0.f)+player.getDirectionVector()*10.f);
				camera->setTarget(player.getPosition()+vector3df(0.f,5.f,0.f)+player.getDirectionVector()*20.f);
			}
			else if (needShakingScreen)
			{
				camera->setPosition(vector3df(player.getPosition().X + screenShakePos.X, 50.f + screenShakePos.Y, -40.f));
				camera->setTarget(vector3df(player.getPosition().X + screenShakePos.X, 20.f + screenShakePos.Y, 0.f));
				screenShakePos.X = GlobalDevice::getFrameDuration() * GlobalDevice::getRandomNumber(-500.f, 500.f);
				screenShakePos.Y = GlobalDevice::getFrameDuration() * GlobalDevice::getRandomNumber(-500.f, 500.f);
			}
			else
			{
				camera->setPosition(vector3df(player.getPosition().X, 50.f, -40.f));
				camera->setTarget(vector3df(player.getPosition().X, 20.f, 0.f));
			}

			smgr->drawAll();
			
			//-------------------------
			// 2d display

			guienv->drawAll();
			if (GlobalDevice::getEventManager()->keys[KEY_ESCAPE])
			{
				driver->draw2DRectangle(SColor(128,0,0,0), GlobalDevice::getDevice()->getVideoDriver()->getViewPort());
				GlobalDevice::draw2DImageTranspChannel(menutext, position2d<s32>(0,0));
			}
			else
			{
				if (winTheGame)
				{
					driver->draw2DRectangle(SColor(128,0,0,0), rect<s32>(
						GlobalDevice::getDevice()->getVideoDriver()->getViewPort().UpperLeftCorner.X, 
						GlobalDevice::getDevice()->getVideoDriver()->getViewPort().LowerRightCorner.Y/2 - 30,
						GlobalDevice::getDevice()->getVideoDriver()->getViewPort().LowerRightCorner.X,
						GlobalDevice::getDevice()->getVideoDriver()->getViewPort().LowerRightCorner.Y/2 + 30));
					GlobalDevice::draw2DImageTranspChannel(wintext, position2d<s32>(
						GlobalDevice::getMainWindowSize().X/2-wintext->getSize().Width/2, 
						GlobalDevice::getMainWindowSize().Y/2-wintext->getSize().Height/2));
				}
			}
			
			
			driver->endScene();

			//-------------------------
			// update fps
			
			if (++framesWaitForTitle==100)
			{
					core::stringw str = core::stringw(APPLICATION_TITLE);
					str += L" - FPS: ";
					str += (s32)(1.f/globalDevice.getFrameDuration());

					device->setWindowCaption(str.c_str());
					framesWaitForTitle=0;
			}
			globalDevice.updateFrameDuration();
		}

		for (GameObjectVector::iterator it = gameObjects.begin(); it != gameObjects.end(); it++)
			if (*it != NULL)
				delete *it;
	}
	while(restartGame);

	return 0;
}

//---------------------------------------------------------------------
