#pragma once
#ifndef FIREWORKS_H
#define FIREWORKS_H

//////////////
// Includes //
//////////////
// C++ general includes
#include <string>
#include <iostream>
#include <vector>

// OpenGL Includes
#include <glad/glad.h>
#include <GLFW/glfw3.h> // GLFW must be included after GLAD!

#include "stb_image.h"
#include "rtrSetupGLFWandGLAD.h" //rtrGLFWGLAD::
#include "rtrShader.h" //rtrShader::
#include "rtrVAO.h"
#include "rtrCamera.h"
#include "rtrModelLoading.h"
#include "rtrMaterialsAndLighting.h"
#include "rtrCubeMap.h"
#include "ParticleEmitter.h"
#include "DrawableObject.h"
#include "include/rtrTextRendering.h"

#define TTL 5.0f

enum RocketStatus 
{
	WAITING, USINGLIGHTER, BURNING, FLYING, EXPLODING
};

namespace fireworks
{
	class Rocket : public DrawableObject
	{

	private:
		float ttl_timer = TTL;
		glm::vec3 DimensionsSpark = glm::vec3(0.03, 0.03, 0.03);
		glm::vec3 DimensionsFlame = glm::vec3(0.05, 0.3, 0.05);
		glm::vec3 PositionSparkRelativeToBody = glm::vec3(0, -0.3, 0);
		glm::vec3 PositionFlameRelativeToBody = glm::vec3(0, -0.2, 0);

	public:
		unsigned int VAO_Body = 0;
		unsigned int VAO_Stick = 0;
		unsigned int VAO_Fire = 0;
		rtrShader::Shader ShaderBody;
		rtrShader::Shader ShaderStick;
		rtrShader::Shader ShaderFire;
		float Speed = 16;
		float MaxHeight = 25;
		glm::vec3 InitialPosition = glm::vec3(0, 1.75, -18);
		glm::vec3 Position;
		glm::vec3 PositionStickRelativeToBody = glm::vec3(-0.02, -0.6, 0);
		glm::vec3 PositionFireRelativeToBody = glm::vec3(0, -0.3, 0);
		glm::vec3 DimensionsBody = glm::vec3(0.1, 0.4, 0.1);
		glm::vec3 DimensionsStick = glm::vec3(0.02, 1.5, 0.02);
		glm::vec3 DimensionsFire = glm::vec3(0.03, 0.03, 0.03);
		glm::mat4 ModelMatrixBody;
		glm::mat4 ModelMatrixStick;
		glm::mat4 ModelMatrixFire;
		glm::vec3 ColorBody = glm::vec3(0.14, 0, 0); //Red
		glm::vec3 ColorStick = glm::vec3(0.15, 0.075, 0.0); //Brown
		glm::vec3 LightColor = glm::vec3(0.9882, 0.9333, 0.6549);
		glm::vec3 LightColorAtFlight = glm::vec3(0.9882, 0.9333, 0.6549); // warm white
		float LightStrength = 0.0; // intensity of color should be in [0,1]
		float LightStrenghtAtExplosion = 20;
		float LightStrenghtAtFlight = 0.8;
		RocketStatus Status = WAITING;
		ParticleEmitter Emitter;
		float timeOfIgnition = 0;
		float timeOfExplosion = 0;
		float StartOfUsingLighter = 0;
		float StartOfBurning = 0;


		Rocket():
			ShaderBody(rtrShader::Shader("shaders\\rocket.vert", "shaders\\rocket.frag")),
			ShaderStick(rtrShader::Shader("shaders\\rocket.vert", "shaders\\rocket.frag")),
			ShaderFire(rtrShader::Shader("shaders\\rocket.vert", "shaders\\rocket.frag")),
			ModelMatrixBody(glm::translate(glm::scale(glm::mat4(1), DimensionsBody), InitialPosition)),
			ModelMatrixStick(glm::translate(glm::scale(glm::mat4(1), DimensionsStick), InitialPosition + PositionStickRelativeToBody)),
			ModelMatrixFire(glm::translate(glm::scale(glm::mat4(1), DimensionsFire), InitialPosition + PositionFireRelativeToBody)),
			Emitter(glm::vec3(InitialPosition.x, MaxHeight, InitialPosition.z)),
			Position(InitialPosition)
		{
			// Define Vertices for a cube
			float verticesCube[] = {
				// positions          // normals           // texture coords
				-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
				 0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
				 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
				 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
				-0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
				-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

				-0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
				 0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 0.0f,
				 0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
				 0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
				-0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 1.0f,
				-0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,

				-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
				-0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
				-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
				-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
				-0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
				-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

				 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
				 0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
				 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
				 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
				 0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
				 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

				-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
				 0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 1.0f,
				 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
				 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
				-0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f,
				-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,

				-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
				 0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
				 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
				 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
				-0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
				-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f
			};

			// Define VAOs
			unsigned int dimensionOfAttributes[] = { 3,3,2 };
			unsigned int VBO_Body;
			rtrVAO::createVAOwithoutEBO(VAO_Body, VBO_Body, verticesCube, 36, 3, dimensionOfAttributes);
			unsigned int VBO_Stick;
			rtrVAO::createVAOwithoutEBO(VAO_Stick, VBO_Stick, verticesCube, 36, 3, dimensionOfAttributes);
			unsigned int VBO_Fire;
			rtrVAO::createVAOwithoutEBO(VAO_Fire, VBO_Fire, verticesCube, 36, 3, dimensionOfAttributes);
		}

		void UpdateParameters(float passedTimeSinceLastFrame)
		{
			if (Position.y >= MaxHeight) // If rocket is at explosion height
			{
				if (ttl_timer > 0) // If explosion is still going on
				{
					// If this is first frame of explosion
					if (Status != EXPLODING) timeOfExplosion = (float)glfwGetTime();
					
					// Calculate fading  light
					float timeSinceExplosion = (float)glfwGetTime() - timeOfExplosion;
					LightStrength = LightStrenghtAtExplosion * glm::cos(0.5*3.1415 * timeSinceExplosion / TTL);
					LightColor = Emitter.current_color;
					// Calculate Particles
					Emitter.simulate(passedTimeSinceLastFrame);
					ttl_timer -= passedTimeSinceLastFrame;
					
					// Update Status of rocket
					Status = EXPLODING;
				}
				else // Explosion has just finished
				{
					//reset explosion parameters
					Emitter.reset(true);

					// Reset Position of rocket to starting position on ground and its light color
					LightColor = LightColorAtFlight;
					Position.y = InitialPosition.y;
					ttl_timer = TTL;
					Status = USINGLIGHTER;
				}
				
			}
			else if(Status == FLYING) // rocket is not exploded yet
			{
				LightStrength = LightStrenghtAtFlight; // Make fire more bright
				DimensionsFire = DimensionsFlame; // Make fire big
				PositionFireRelativeToBody = PositionFlameRelativeToBody;
				Position.y += (passedTimeSinceLastFrame * Speed);
			}
			else if (Status == BURNING)
			{
				LightStrength = 0.25 * LightStrenghtAtFlight; // Make fire less bright
				DimensionsFire = DimensionsSpark; // Make fire small
				PositionFireRelativeToBody = PositionSparkRelativeToBody;
				if ((float)glfwGetTime() - timeOfIgnition > 4)
				{
					//If rocket burned for 5 seconds, start it
					Status = FLYING;
				}

			}
			else if (Status == USINGLIGHTER)
			{
				LightStrength = 0.0;
				// Save current time as ignition because as soon status changes to BURNING 
				// timeOfIgnition will be the last time point before that status switch happend!
				timeOfIgnition = (float)glfwGetTime();
				float timeWaited = (float)glfwGetTime() - StartOfUsingLighter;
				if (timeWaited > 1)
				{
					StartOfBurning = (float)glfwGetTime();
					Status = BURNING; // After 1 seconds waiting ignite rocket
				}
			}
			else if (Status == WAITING)
			{
				LightStrength = 0.0;
				StartOfUsingLighter = (float)glfwGetTime();
			}

			ModelMatrixBody = glm::scale(glm::translate(glm::mat4(1.0f), Position), DimensionsBody);
			ModelMatrixStick = glm::scale(glm::translate(glm::mat4(1.0f), Position + PositionStickRelativeToBody), DimensionsStick);
			ModelMatrixFire = glm::scale(glm::translate(glm::mat4(1.0f), Position + PositionFireRelativeToBody), DimensionsFire);
		}

		void UpdateShader(glm::mat4 viewMatrix, glm::mat4 projectionMatrix)
		{
			//Body
			ShaderBody.use();
			ShaderBody.setVec3F("color", ColorBody);
			ShaderBody.setMat4F("modelMatrix", ModelMatrixBody);
			ShaderBody.setMat4F("viewMatrix", viewMatrix);
			ShaderBody.setMat4F("projectionMatrix", projectionMatrix);
			ShaderBody.setFloat("strength", 1);


			//Stick
			ShaderStick.use();
			ShaderStick.setVec3F("color", ColorStick);
			ShaderStick.setMat4F("modelMatrix", ModelMatrixStick);
			ShaderStick.setMat4F("viewMatrix", viewMatrix);
			ShaderStick.setMat4F("projectionMatrix", projectionMatrix);
			ShaderStick.setFloat("strength", 1);

			//Stick
			ShaderFire.use();
			ShaderFire.setVec3F("color", LightColor);
			ShaderFire.setMat4F("modelMatrix", ModelMatrixFire);
			ShaderFire.setMat4F("viewMatrix", viewMatrix);
			ShaderFire.setMat4F("projectionMatrix", projectionMatrix);
			ShaderFire.setFloat("strength", LightStrength * 4);

			//Particles
			Emitter.update_shader(viewMatrix, projectionMatrix);
		}

		void Draw()
		{
			if (Status != EXPLODING)
			{
				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
				ShaderBody.use();
				glBindVertexArray(VAO_Body);
				glDrawArrays(GL_TRIANGLES, 0, 36);
				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
				ShaderStick.use();
				glBindVertexArray(VAO_Stick);
				glDrawArrays(GL_TRIANGLES, 0, 36);
				if (Status == BURNING || Status == FLYING)
				{
					ShaderFire.use();
					glBindVertexArray(VAO_Fire);
					glDrawArrays(GL_TRIANGLES, 0, 36);
				}
			}
			else //if rocket is EXPLODING
			{
				if (ttl_timer > 0) Emitter.draw();
			}
		}
	};

	void configureCityModel(rtrModelLoading::PhysicalObject& cityModel)
	{
		cityModel.SetPosition(glm::vec3(0.0, -16.0, 0));
		cityModel.SetScale(glm::vec3(0.25, 0.25, 0.25));
		cityModel.Material.specularColor = glm::vec3(1.0f, 1.0f, 1.0f);
		cityModel.Material.diffuseStrength = 1.0;
		cityModel.Material.shininess = 1.0f;
		cityModel.Material.specularStrength = 0.5;
	}

	void configureLights(rtrMaterialsAndLighting::Light lightSources[], const fireworks::Rocket& rocket, rtrModelLoading::PhysicalObject& cityModel, rtrCamera::CameraForGLFW& camera)
	{
		// Ambient Light
		lightSources[0].type = 0; //0 = ambient light
		lightSources[0].activated = true;
		lightSources[0].strength = 0.08;
		lightSources[0].color = glm::vec3(0.9f, 0.9f, 1.0f);
		lightSources[0].sendDataToShader(cityModel.Shader, "lightSources[0]");

		// Point Light: Rocket
		lightSources[1].type = 1; // 1 = Point Light
		lightSources[1].activated = true;
		lightSources[1].position = rocket.Position;
		lightSources[1].color = rocket.LightColor;
		lightSources[1].strength = 1.0;
		lightSources[1].sendDataToShader(cityModel.Shader, "lightSources[1]");

		// Directional Light: MoonLight
		lightSources[2].type = 2; // 2 = directional Light
		lightSources[2].activated = true;
		lightSources[2].color = glm::vec3(1.0f, 1.0f, 1.0f);
		lightSources[2].strength = 0.09;
		lightSources[2].direction = glm::vec3(0, -1, -1);
		lightSources[2].sendDataToShader(cityModel.Shader, "lightSources[2]");

		// Spotlight: Flashlight
		lightSources[3].type = 3; // 3 = spotlight
		lightSources[3].activated = false;
		lightSources[3].strength = 1.0f;
		lightSources[3].color = glm::vec3(1.0f, 1.0f, 1.0f);
		lightSources[3].position = camera.Position;
		lightSources[3].direction = camera.GetFront();
		lightSources[3].sendDataToShader(cityModel.Shader, "lightSources[3]");
	}

	void updateLights(
		GLFWwindow* window,
		rtrCamera::CameraForGLFW& camera,
		const unsigned int& NUMBER_OF_LIGHT_SOURCES,
		rtrMaterialsAndLighting::Light lightSources[],
		rtrModelLoading::PhysicalObject& cityModel,
		const Rocket& rocket)
	{
		for (int i = 0; i < NUMBER_OF_LIGHT_SOURCES; i++)
		{
			lightSources[i].processKeyboardInput(window);

			std::string part1 = "lightSources[";
			std::string part2 = std::to_string(i);
			std::string part3 = "]";
			std::string nameOfUniform = part1 + part2 + part3;
			lightSources[i].sendActivationStatusToShader(cityModel.Shader, nameOfUniform);

			// if is point light (rocket) update position and strength
			if (lightSources[i].type == 1)
			{
				lightSources[i].position = rocket.Position;
				lightSources[i].color = rocket.LightColor;
				lightSources[1].strength = rocket.LightStrength;
				lightSources[i].sendDataToShader(cityModel.Shader, "lightSources[1]");
			}

			// if is Spotlight update pos and dir
			if (lightSources[i].type == 3)
			{
				lightSources[i].position = camera.Position;
				lightSources[i].direction = camera.GetFront();
				lightSources[i].sendPosAndDirToShader(cityModel.Shader, "lightSources[3]");
			}
		}
	}

	void renderStartScreen(GLFWwindow* window, glm::vec2 resolution)
	{
		// Show Startscreen
		rtrText::freeTypeFont fontArial("fonts\\arial.ttf", 50);
		rtrShader::Shader textShader("shaders\\text.vert", "shaders\\text.frag");
		textShader.use();
		textShader.setMat4F("projectionMatrix", glm::ortho(0.0f, resolution.x, 0.0f, resolution.y));
		textShader.setInt("textureUnitText", 0);
		textShader.setVec3F("textColor", glm::vec3(1, 1, 1));
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glm::vec2 pos(0.2 * resolution.x, 0.8 * resolution.y);
		fontArial.render(textShader, "Course Real Time Rendering at TU Wien, 2022/2023 ", pos.x, pos.y, 1, glm::vec3(1, 1, 1), resolution.x, resolution.y);
		pos = glm::vec2(0.3 * resolution.x, 0.75 * resolution.y);
		fontArial.render(textShader, "Ondrej Peterka & J. Christian Reiher ", pos.x, pos.y, 1, glm::vec3(1, 1, 1), resolution.x, resolution.y);
		pos = glm::vec2(0.13 * resolution.x, 0.6 * resolution.y);
		fontArial.render(textShader, "We wish all staff and students a happy and successful New Year!", pos.x, pos.y, 1, glm::vec3(1, 1, 1), resolution.x, resolution.y);
		pos = glm::vec2(0.16 * resolution.x, 0.4 * resolution.y);
		fontArial.render(textShader, "3D Model: \"old town model\" by Herminio Nieves (2013): https://free3d.com/3d-model/old-fashion-town-88316.html ", pos.x, pos.y, 0.5, glm::vec3(1, 1, 1), resolution.x, resolution.y);
		pos = glm::vec2(0.165 * resolution.x, 0.35 * resolution.y);
		fontArial.render(textShader, "Lighter Image by phichto: https://pngtree.com/freepng/realistic-lighter-metal-lighters-zippo-with-fire_6502575.html ", pos.x, pos.y, 0.5, glm::vec3(1, 1, 1), resolution.x, resolution.y);
		pos = glm::vec2(0.16 * resolution.x, 0.3 * resolution.y);
		fontArial.render(textShader, "Sky Box by Hipshot @ www.zfight.com : http://www.zfight.com/misc/images/textures/envmaps/grimmnight_large.jpg ", pos.x, pos.y, 0.5, glm::vec3(1, 1, 1), resolution.x, resolution.y);
		pos = glm::vec2(0.3 * resolution.x, 0.2 * resolution.y);
		fontArial.render(textShader, "Toggle Keys: (A)mbient light, (D)iffuse Light, (P)oint Light, (S)hadows, ", pos.x, pos.y, 0.5, glm::vec3(1, 1, 1), resolution.x, resolution.y);
		pos = glm::vec2(0.4 * resolution.x, 0.1 * resolution.y);
		fontArial.render(textShader, "ESC: Exit,   ENTER: Manual Camera", pos.x, pos.y, 0.5, glm::vec3(1, 1, 1), resolution.x, resolution.y);


		glfwSwapBuffers(window);
		float time = (float)glfwGetTime();
		while ((float)glfwGetTime() - time < 6) {}
	}

	class Inventory: public DrawableObject
	{
	public:
		rtrShader::Shader Shader = rtrShader::Shader("shaders\\inventory.vert", "shaders\\inventory.frag");
		unsigned int VAO = 0;
		unsigned int VBO = 0;
		unsigned int textureId = rtrTexture::loadTextureFromFile("textures\\inventory.png");
		bool allowOpening = true;
		bool isOpen = false;
		float timeOfOpening = -1;
		bool lighterSelected = false;
		float distanceFromRocketToOpenInventory =5;
		Inventory(glm::vec2 screenRes)
		{
			float dx = screenRes.x > screenRes.y ? screenRes.y / screenRes.x : 1;
			float dy = screenRes.x < screenRes.y ? screenRes.x / screenRes.y : 1;
			float vertices[] = {
				// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. NOTE that this plane is now much smaller and at the top of the screen
				// positions   // texCoords
				-0.5f*dx,   0.5f*dy,  0.0f, 1.0f, // left top
				-0.5f*dx,  -0.5f*dy,  0.0f, 0.0f, // left bottom
				 0.5f*dx,  -0.5f*dy,  1.0f, 0.0f, // right bottom 

				-0.5f*dx,  0.5f*dy,  0.0f, 1.0f, // left top again
				 0.5f*dx, -0.5f*dy,  1.0f, 0.0f, // right bottom 
				 0.5f*dx,  0.5f*dy,  1.0f, 1.0f  // right top
			};
			unsigned int dimensionOfAttributes[] = { 2,2 };
			rtrVAO::createVAOwithoutEBO(VAO, VBO, vertices, 6, 2, dimensionOfAttributes);
		}

		void update(glm::vec3 cameraPosition, glm::vec3 rocketPosition, RocketStatus rocketStatus)
		{
			float distanceToRocket = glm::length(cameraPosition - rocketPosition);
			if (rocketStatus != WAITING) // Iff rocket has been ignited don't allow opening Inventory
			{
				allowOpening = false;
				lighterSelected = false; // rocket has been ignited, unselect lighter
			}
			else //If rocket is waiting allow using inventory
			{
				allowOpening=true;
			}
			if (allowOpening && distanceToRocket <= distanceFromRocketToOpenInventory)
			{
				if (!isOpen)
				{
					// if inventory was just opened save Opening time
					isOpen = true;
					timeOfOpening = (float)glfwGetTime();
				}
				else if (isOpen && (float)glfwGetTime() - timeOfOpening > 1)
				{
					// If inventory is already open: select Lighter and close it after 2 seconds 
					isOpen = false;
					lighterSelected = true;
				}				
			}
		}

		void Draw()
		{
			if (isOpen)
			{
				glDisable(GL_DEPTH_TEST);
				Shader.use();
				glActiveTexture(GL_TEXTURE0);
				glBindTexture(GL_TEXTURE_2D, textureId);
				Shader.setInt("textureUnit", 0);
				glBindVertexArray(VAO);
				glDrawArrays(GL_TRIANGLES, 0, 6);
				glEnable(GL_DEPTH_TEST);
			}
		}
	};

	class CameraScript
	{
		public:
			Rocket* rocket;
			rtrCamera::CameraForGLFW* camera;
			GLFWwindow* window;
			Inventory* inventory;
			unsigned int currentStateId = 0;
			float endTimeOfLastState = 0;
			glm::vec3 lastLookAt = glm::vec3(0, 0, 0);
			glm::vec3 lastCameraPosition = glm::vec3(0, 0, 0);
			bool lookAtExplosionCenter = false;
			
			CameraScript(GLFWwindow* windowInput, Rocket* inputRocket, rtrCamera::CameraForGLFW* inputCamera, Inventory* inventoryInput):
				rocket(inputRocket), 
				camera(inputCamera),
				window(windowInput),
				inventory(inventoryInput)
			{
				//Nothing happening here
			}

			void Apply()
			{
				//Stage 0: Wait for 2 seconds while looking towards rocket
				if (currentStateId == 0)
				{
					camera->automaticMovementDirection = glm::vec3(rocket->Position.x - camera->Position.x, 0, rocket->Position.z - camera->Position.z);
					camera->automaticMovementSpeed = 0;
					camera->Front = glm::normalize(rocket->Position - camera->Position);
					if ((float)glfwGetTime() - endTimeOfLastState > 2)
					{
						endTimeOfLastState = (float)glfwGetTime();
						currentStateId++;
					}
				}

				// Stage 1: Move towards rocket 
				if (currentStateId == 1)
				{
					camera->Front = glm::normalize(rocket->Position - camera->Position);
					camera->automaticMovementDirection = glm::vec3(rocket->Position.x - camera->Position.x, 0, rocket->Position.z - camera->Position.z);
					camera->automaticMovementSpeed = 5;
					if (glm::length(camera->Position - rocket->Position) < inventory->distanceFromRocketToOpenInventory + 0.1)
					{
						endTimeOfLastState = (float)glfwGetTime();
						currentStateId++;
					}
				}
				
				// Stage 2: When close to rocket move very slow until inventory opens
				if (currentStateId == 2)
				{
					camera->Front = glm::normalize(rocket->Position - camera->Position);
					camera->automaticMovementDirection = glm::vec3(rocket->Position.x - camera->Position.x, 0, rocket->Position.z - camera->Position.z);
					camera->automaticMovementSpeed = 0.5;
					if (inventory->isOpen)
					{
						endTimeOfLastState = (float)glfwGetTime();
						currentStateId++;
					}
				}

				// Stage 3: Wait until rocket is burning for 1 sec or so
				if (currentStateId == 3)
				{
					camera->automaticMovementSpeed = 0;
					camera->Front = glm::normalize(rocket->Position - camera->Position);
					if ((float)glfwGetTime() - endTimeOfLastState > 3)
					{
						endTimeOfLastState = (float)glfwGetTime();
						currentStateId++;
					}
				}

				// Stage 4: Move away from rocket until 20m away while looking at rocket up to certain hight
				if (currentStateId == 4)
				{
					camera->automaticMovementDirection = -glm::vec3(rocket->Position.x - camera->Position.x, 0, rocket->Position.z - camera->Position.z);
					camera->automaticMovementSpeed = 10;
					camera->Front = glm::normalize(rocket->Position - camera->Position);
					if (rtrCamera::pitch < 10.0) camera->Front = glm::normalize(rocket->Position - camera->Position);
					if (glm::length(rocket->Position - camera->Position) > 40)
					{
						endTimeOfLastState = (float)glfwGetTime();
						currentStateId++;
					}
					lastLookAt = camera->Position + (30.0f * camera->Front);
					lastCameraPosition = camera->Position;
				}

				// Stage 5: Wait and Look at explosion
				if (currentStateId == 5)
				{
					camera->automaticMovementSpeed = 0;
					camera->FarPlane = 500;
					if ((float)glfwGetTime() - endTimeOfLastState > 6.5)
					{
						currentStateId = 6;
						endTimeOfLastState = glfwGetTime();
					}					
				}

				// Stage 6: Slowly look down at rocket starting position
				if (currentStateId == 6)
				{
					float currentTime = (float)glfwGetTime();
					glm::vec3 target = glm::normalize(rocket->InitialPosition - camera->Position);
					if (glm::length(target - glm::normalize(camera->Front)) > 0.01)
					{
						camera->Front -= (currentTime - endTimeOfLastState) * glm::vec3(0,0.2,0);
					}
					else currentStateId = 7;
					endTimeOfLastState = currentTime;
				}
				

				// Stage 7: fly towards explosion until 45m height reached
				if (currentStateId == 7)
				{
					glm::vec3 explosionPosition = rocket->InitialPosition + glm::vec3(0, rocket->MaxHeight, 0);
					if (camera->Position.y < 45)
					{
						if (!lookAtExplosionCenter && rocket->Status == EXPLODING) lookAtExplosionCenter = true;
						glm::vec3 delta = glm::vec3(-7, 0, 0);
						if (!lookAtExplosionCenter) camera->Front = rocket->Position - camera->Position;//lastLookAt - camera->Position;
						else camera->Front = explosionPosition - camera->Position;
						camera->automaticMovementDirection = explosionPosition + delta - lastCameraPosition;
						camera->automaticMovementSpeed = 6;
					}
					else
					{
						currentStateId = 8;
					};
				}
				
				// Stage 8: Wait in air and exit until next explosion, then deactivate rocket
				if (currentStateId == 8)
				{
					camera->automaticMovementSpeed = 0.0f;
					if (rocket->Status == USINGLIGHTER)
					{
						rocket->Status = WAITING;
						endTimeOfLastState = (float)glfwGetTime();
						currentStateId = 9;
					}

				}

				// Wait 2 seconds after rocket was deactivated and fade out
				if (currentStateId == 9)
				{
					if((float)glfwGetTime()-endTimeOfLastState > 2.0)
					glfwSetWindowShouldClose(window, true);
				}

			}
	};
}
#endif