int main(int argc, char* argv[]){

	XMLParser* xml = new XMLParser();

	try{
		xml->loadXML(".\\settings.xml");
	} catch(std::exception& e){
		std::cout << e.what() <<std::endl;
		std::cout << "Default values will be applied" <<std::endl;
		loadDefaultValues(xml);

		xml->writeToXML(".\\settings.xml");
	}

	GLFWWindow* wnd;

	try{
		wnd = new GLFWWindow(xml->get<int>("Window", "width"),
							 xml->get<int>("Window", "height"),
							 "RayTracer",
							 xml->get<bool>("Window", "windowed"));
	} catch(std::exception& e){
		std::cout << e.what() << std::endl;
		std::cin.get();
		delete xml;
		
		return -1;
	}

	std::cout << "OpenGL Version: " << glGetString(GL_VERSION) <<std::endl;

	if(glewInit() != GLEW_OK){
		std::cout << "Could not initialize GLEW!" <<std::endl;
		std::cin.get();

		delete wnd;
		delete xml;

		return -1;
	} else {
		std::cout << "GLEW Version: " << glewGetString(GLEW_VERSION) <<std::endl;
	}


	GLFWInput* input = new GLFWInput();
	GLFWTimer* timer = new GLFWTimer();
	int maxFPS = xml->get<int>("Window", "maxFPS");
	int width = xml->get<int>("Window", "width");
	int height = xml->get<int>("Window", "height");
	boost::shared_ptr<TextureRenderer>	texRenderer;
	boost::shared_ptr<OpenGLRaytracer>	ort;
	boost::shared_ptr<Texture>			tex;
	boost::shared_ptr<Scene>			scene;
	boost::shared_ptr<SceneReader>		sceneReader;
	boost::shared_ptr<SceneLoader>		sceneLoader;
	boost::shared_ptr<InputControl>		inputControl;
	boost::shared_ptr<Camera>			camera;

	int frameCounter = 0, fps = 0;
	int reflectionDepth = xml->get<int>("Raytracing", "reflectionDepth"); 
	bool running = true;
	char i = 0;
	
	try{
		camera = boost::shared_ptr<Camera>(new Camera(xml->get<int>("Window", "width"), xml->get<int>("Window", "height"), xml->get<float>("Camera", "fovY"), 
													  glm::vec3(xml->get<float>("Camera", "posX"), xml->get<float>("Camera", "posY"),xml->get<float>("Camera", "posZ")), 
													  glm::vec3(xml->get<float>("Camera", "dirX"), xml->get<float>("Camera", "dirY"), xml->get<float>("Camera", "dirZ")),
													  glm::vec3(xml->get<float>("Camera", "upX"), xml->get<float>("Camera", "upY"), xml->get<float>("Camera", "upZ"))));

		tex = boost::shared_ptr<Texture>(new Texture(xml->get<int>("Window", "width"), xml->get<int>("Window", "height"), GL_RGBA8));
		texRenderer = boost::shared_ptr<TextureRenderer>(new TextureRenderer(xml->get<int>("Window", "width"), xml->get<int>("Window", "height"), tex));
		ort = boost::shared_ptr<OpenGLRaytracer>(new OpenGLRaytracer(tex, (*camera.get()), reflectionDepth));
		inputControl = boost::shared_ptr<InputControl>(new InputControl(xml->get<float>("Camera", "velocityRotate"), xml->get<float>("Camera", "velocityTranslate")));
		scene = boost::shared_ptr<Scene>(new Scene());
		sceneReader = boost::shared_ptr<SceneReader>(new SceneReader());
		sceneLoader = boost::shared_ptr<SceneLoader>(new SceneLoader((*ort.get())));

		for(int i = 0; i < argc; ++i){
			sceneReader->readScene((std::string(".\\")+std::string(argv[i])).c_str(), (*scene.get()));
			sceneLoader->loadScene((*scene.get()), (*ort.get()));
			scene->clear();
		}

		while(running){
			glGetError();
			if(timer->getTimeDiffWithoutActualization() > static_cast<double>(1.0)/static_cast<double>(maxFPS)){
				timer->getTimeDiff();

				inputControl->processInput((*camera.get()), reflectionDepth);
				camera->update();
			    
				ort->renderScene((*camera.get()), width, height, reflectionDepth);
				texRenderer->draw();
				wnd->swapBuffers();

				if(input->isKeyPressed(GLFW_KEY_ESC)){
					running = false;
				}

				frameCounter++;
				if(timer->getRefreshedTime() > 1.0){
					fps = frameCounter;
					frameCounter = 0;
					timer->resetTime();
				}

				wnd->setWindowTitle(boost::lexical_cast<std::string, int>(fps).c_str());
			}

			if(glGetError() != GL_NO_ERROR){
				throw std::exception("ERROR!");
			}

		}
		
	} catch(std::exception&e ){
		std::cout << e.what() <<std::endl;
		std::cin.get();
	}
	
	delete timer;
	delete input;
	delete wnd;
}
int main() {

    LPTSTR path = new TCHAR[100];
    GetModuleFileName(HINST_THISCOMPONENT,path, 100);

    std::cout << "Executing: " << path  << std::endl;

    XMLParser* xml = new XMLParser();

    try {
        xml->loadXML(".\\particles.xml");

    } catch(std::exception& e) {
        std::cout << e.what() <<std::endl;
        std::cout << "Default values will be applied!" <<std::endl;

        loadDefaultValues(xml);

        try {
            xml->writeToXML(".\\particles.xml");
        } catch(std::exception& e) {
            std::cout << e.what() <<std::endl;
        }
    }


    GLFWWindow* wnd;

    try {

        wnd = new GLFWWindow(xml->get<int>("Window", "width"),
                             xml->get<int>("Window", "height"),
                             "OpenGL_4.3_Particle_System",
                             xml->get<bool>("Window", "windowed"));

    } catch(std::exception& e) {
        std::cout << e.what() <<std::endl;
        std::cin.get();

        delete xml;

        return -1;
    }

    std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;

    if(glewInit() != GLEW_OK) {
        std::cout << "Could not initialize GLEW!" <<std::endl;
        std::cin.get();

        delete wnd;
        delete xml;

        return -1;
    } else {
        std::cout << "GLEW Version: " <<glewGetString(GLEW_VERSION) <<std::endl;
    }

    ParticleSystem* ps;

    try {
        ps = new ParticleSystem(xml->get<int>("Particles", "maxParticles"),
                                xml->get<int>("Particles", "iniRadius"),
                                xml->get<float>("Particles", "quadLength"),
                                xml->get<int>("Window", "maxFPS"),
                                xml->get<float>("Camera", "translation_velocity"),
                                xml->get<float>("Camera", "rotation_velocity"));

    } catch(std::exception& e) {
        std::cout << e.what() <<std::endl;
        std::cin.get();

        delete wnd;
        delete xml;

        return -1;
    }

    delete xml;

    try {
        ps->run(wnd);
    } catch(std::exception& e) {
        std::cout << e.what() <<std::endl;
        std::cin.get();
    }

    delete ps;
    delete wnd;

    return 0;
}