#pragma once
#include <gl/glew.h>
#include <gl/glfw3.h>
#include <glm\glm.hpp>
#include <glm\gtc\matrix_transform.hpp>
#include <Windows.h>
#include <vector>
#include "shader.h"
#include "import.h"
#include "texture.h"

#define OGL_MAJOR_VERSION 4
#define OGL_MINOR_VERSION 5
#define AA_VALUE 4
#define MAINWINDOW_NAME "MeshViewer 2.0 pre-alpha"
#define VERTEX_SHADER "Shader/VertexTextureShader.mv2shdr"
#define FRAGMENT_SHADER "Shader/FragmentTextureShader.mv2shdr"
#define TEXTURE_NAME "Textures/dice.tga"


struct oglVariables {
	GLFWwindow* window;				// window
	GLuint vertexArrayID;			// vertex array
	GLuint vertexBufferID;			// vertex buffer
	GLuint colorBufferID;			// color buffer
	GLuint samplerID;				// sampler handler
	GLuint uvBufferID;				// uv buffer
	GLuint shaderPrgmID;			// shader
	struct {
		GLuint id;					// matrix ID
		glm::mat4 projection;		// projection
		glm::mat4 view;				// view
		glm::mat4 model;			// model
		glm::mat4 mvp;				// mvp
	} matrix;
	struct {
		std::vector<GLfloat> data;	// obj data
		std::vector<GLfloat> color;	// obj color
		std::vector<GLfloat> uv;	// obj uv
		GLuint textureID;				// texture data
	} object;
};

struct {
	float fov = 45.f;
	float minView = 0.1f;
	float maxView = 100.0f;
	int witdh = 640;
	int heigh = 480;
	float rotX = 0;
	float rotY = 0;
	float rotZ = 0;
	double transX = 0.0;
	double transY = 0.0;
	double transZ = 5.0;
} monitor;

void setupGLFW()
{
	if (!glfwInit())
	{
		MessageBox(NULL, "Failed to initialize GLFW", "MeshViewer 2.0 Error", MB_OK | MB_ICONERROR);
		exit(0);
	}

	glfwWindowHint(GLFW_SAMPLES, AA_VALUE);							// antialiasing level
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OGL_MAJOR_VERSION);	// OpenGL major version number
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OGL_MINOR_VERSION);	// OpenGL minor verison number
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);	// something we need for new OGL
}

GLFWwindow* createWindow()
{
	GLFWwindow* window = glfwCreateWindow(monitor.witdh, monitor.heigh, MAINWINDOW_NAME, NULL, NULL);
	
	if (window == NULL)
	{
		char tempMajor[10], tempMinor[10];
		_itoa_s(OGL_MAJOR_VERSION, tempMajor, 10, 10);
		_itoa_s(OGL_MINOR_VERSION, tempMinor, 10, 10);

		MessageBox(NULL,
			(std::string("Your GPU does not support OpenGL ") += std::string(tempMajor) += std::string(".") += std::string(tempMinor)).c_str(),
			"MeshViewer 2.0 Error", MB_OK | MB_ICONERROR);

		glfwTerminate();
		exit(0);
	}

	glfwMakeContextCurrent(window);

	return window;
}

void setupGLEW()
{
	glewExperimental = true;

	if (glewInit() != GLEW_OK)
	{
		MessageBox(NULL, "Failed to initialize GLEW!", "MeshViewer 2.0 Error", MB_OK | MB_ICONERROR);
		glfwTerminate();
		exit(0);
	}
}

void calcMatrices(oglVariables &scene)
{
	scene.matrix.projection = glm::perspective(monitor.fov, float(monitor.witdh) / float(monitor.heigh), monitor.minView, monitor.maxView);
	scene.matrix.view = glm::lookAt(
		glm::vec3(monitor.transX, monitor.transY, monitor.transZ),
		glm::vec3(monitor.transX, monitor.transY, monitor.transZ - 1),
		glm::vec3(0, 1, 0)
	);
	scene.matrix.model = glm::mat4(1.0f);
	scene.matrix.model = glm::rotate(scene.matrix.model, monitor.rotX, glm::vec3(1, 0, 0));
	scene.matrix.model = glm::rotate(scene.matrix.model, monitor.rotY, glm::vec3(0, 1, 0));
	scene.matrix.model = glm::rotate(scene.matrix.model, monitor.rotZ, glm::vec3(0, 0, 1));

	scene.matrix.mvp = scene.matrix.projection * scene.matrix.view * scene.matrix.model;
}

void initVariables(oglVariables &temp)
{
	glGenVertexArrays(1, &(temp.vertexArrayID));
	glGenBuffers(1, &temp.vertexBufferID);
	glGenBuffers(1, &temp.colorBufferID);
	glGenBuffers(1, &temp.uvBufferID);
	temp.shaderPrgmID = LoadShaders(VERTEX_SHADER, FRAGMENT_SHADER);

	temp.matrix.id = glGetUniformLocation(temp.shaderPrgmID, "MVP");
	calcMatrices(temp);
	
	temp.samplerID = glGetUniformLocation(temp.shaderPrgmID, "textureSampler");

	temp.object.data = loadData();
	temp.object.color = loadColor();
	temp.object.uv = loadUV();

	glGenTextures(1, &temp.object.textureID);
	glBindTexture(GL_TEXTURE_2D, temp.object.textureID);
	TextureTGA tempTex(TEXTURE_NAME);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tempTex.getWidth(), tempTex.getHeight(), 0, GL_BGR, GL_UNSIGNED_BYTE, tempTex.getData().data());
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glGenerateMipmap(GL_TEXTURE_2D);

}

void cleanUp(oglVariables &scene)
{
	glDeleteBuffers(1, &scene.uvBufferID);
	glDeleteBuffers(1, &scene.colorBufferID);
	glDeleteBuffers(1, &scene.vertexBufferID);
	glDeleteVertexArrays(1, &scene.vertexArrayID);
	glDeleteProgram(scene.shaderPrgmID);
	glDeleteTextures(1, &scene.samplerID);
	glfwTerminate();
}
