/*
 * Header for the declaration of a model
 */

#pragma once

#ifndef MODEL_H
#define MODEL_H

#include "common.hpp"

#include <sstream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <set>
#include <map>

#include "mesh.h"
#include "material.h"
#include "shader.hpp"


class Model
{

public:
	Model(); //default constructor
	~Model();	//default deconstructor

	bool loadMod(char* filepath);	//load a model definition
	
	//add a new vertex to the indices array
	void addVertex(int* pVertex, std::set<int>& vHashSet, std::map<int, int>& hashToIndexMap,
		std::vector<float*>& vertexPositions, std::vector<float*>& newVertexPositions,
		std::vector<float*>& textureCoordinates, std::vector<float*>& newTextureCoordinates,
		std::vector<float*>& normals, std::vector<float*>& newNormals,
		GLuint* indices, int& inserIndex, int& currIndex, int& storedIndex);
	void addTDir(int* pVertex, std::set<int>& vHashSet, std::map<int, int>& hashToIndexMap,
		std::vector<glm::vec3>& tan1, std::vector<glm::vec3>& tan2, glm::vec3& sdir, glm::vec3& tdir, int& index, int& storedIndex);
	void calcTangentVec(int* pVert1, int* pVert2, int* pVert3, std::vector<float*>& vertexPositions,
		std::vector<float*>& textureCoordinates, std::vector<float*>& normalPositions, std::vector<float*>& tangents);
	void calcTangent(int vertexCount, std::vector<float*>& vertexPositions, std::vector<float*>& normalPositions, 
		std::vector<float*>& textureCoordinates, int trianglesCount, std::vector<int*>& triangles, std::vector<glm::vec4>& tangents);
	int getTangHash(int _x, int _y, int _z);
	
	int getVertexHash(int* vertex);	//get a hash code out of the triangle information
	bool loadMatProp(char* filepath);	//load the material properties
	void setMaterial(Material* material);	//set a material
	void setMesh(Mesh* mesh);	//set a mesh
	Mesh* getMesh();	//get the mesh of the model
	Material* getMaterial();	//get the material information of the model
	bool buildVBOs(const Shader &shader);	//build the vbos for this model
	bool buildVBOsNorm(const Shader &shader);	//build the vbos for normal mapping for this model
	void render();	//render the model
	void getDimension(std::vector<float*>& vertexPositions, float* dimension);		//get the dimensions of the model
	GLuint getVAO(); //get the vertex array object
	GLuint getVBO_vertices() {return vbo_vertices;}
	GLuint getVBO_normals() {return vbo_normals;}
	GLuint getVBO_textures() {return vbo_texture;}
	GLuint getVBO_tangents() {return vbo_tangents;}
	GLuint getVBO_indices() {return vbo_indices;}

	//cast a string to an integer
	int StringToInt(const std::string& str_input, const int default_value);
	//cast a string to a float
	float StringToFloat(const std::string& str_input, const float default_value);
	
private:
	GLuint vao_id;
	GLuint vbo_vertices;
	GLuint vbo_normals;
	GLuint vbo_texture;
	GLuint vbo_indices;
	GLuint vbo_tangents;
	GLint loc_vertices;
	GLint loc_normals;
	GLint loc_texture;
	GLint loc_tangents;

	Mesh* mesh;	//mesh information
	Material* material;	//material information

};
#endif