#pragma once
#include "../../stdafx.h"
#include "glLibObject.h"

namespace glLib { namespace Object {

class rectangular_solid : public object {
	public:
	public:
		template <typename T> rectangular_solid(T* const size,                            bool texturing=false, const glLibFlagLighting normals=GLLIB_FACE_NORMALS) {
			glLibInternal_make(size[0],size[1],size[2],texturing,NULL,normals);
		}
		template <typename T> rectangular_solid(T        size,                            bool texturing=false, const glLibFlagLighting normals=GLLIB_FACE_NORMALS) {
			glLibInternal_make(size,size,size,texturing,NULL,normals);
		}

		template <typename T> rectangular_solid(T* const size, const Texture::texture_2D*const texture,         const glLibFlagLighting normals=GLLIB_FACE_NORMALS) {
			Texture::texture_2D* textures[] = {texture,texture,texture,texture,texture,texture};
			glLibInternal_make(size[0],size[1],size[2],true,textures,normals);
		}
		template <typename T> rectangular_solid(T        size, const Texture::texture_2D*const texture,         const glLibFlagLighting normals=GLLIB_FACE_NORMALS) {
			Texture::texture_2D* textures[] = {texture,texture,texture,texture,texture,texture};
			glLibInternal_make(size,size,size,true,textures,normals);
		}

		template <typename T> rectangular_solid(T* const size, const Texture::texture_2D*const textures[],      const glLibFlagLighting normals=GLLIB_FACE_NORMALS) {
			glLibInternal_make(size[0],size[1],size[2],true,textures,normals);
		}
		template <typename T> rectangular_solid(T        size, const Texture::texture_2D*const textures[],      const glLibFlagLighting normals=GLLIB_FACE_NORMALS) {
			glLibInternal_make(size,size,size,true,textures,normals);
		}

		//TODO: Add constructors for glLibTexture3D and glLibTextureCube
		//TODO: Add tangent data
		//TODO: Check face winding consistency
	private:
		//TODO: const on textures?
		void glLibInternal_make(float x,float y,float z, bool texturing, const Texture::texture_2D*const textures[], const glLibFlagLighting normal_flag) {
			glLibInternal_init_start();

			numof_faces = 6;
			numof_meshes = 6;

			//We need this many, because each face might potentially have a different texture
			meshes = new glLibInternal_mesh*[numof_meshes];
			for (char i=0;i<6;++i) {
				glLibInternal_mesh* mesh = new glLibInternal_mesh();
				mesh->verts_per_face = 4;
				meshes[i] = mesh;
			}

			numof_vertices = 8;
			array_vertices = new GLfloat[8*3];
			x /= 2.0f;
			y /= 2.0f;
			z /= 2.0f;
			array_vertices[ 0] = -x; array_vertices[ 1] = -y; array_vertices[ 2] = -z; //0
			array_vertices[ 3] = -x; array_vertices[ 4] = -y; array_vertices[ 5] =  z; //1
			array_vertices[ 6] = -x; array_vertices[ 7] =  y; array_vertices[ 8] = -z; //2
			array_vertices[ 9] = -x; array_vertices[10] =  y; array_vertices[11] =  z; //3
			array_vertices[12] =  x; array_vertices[13] = -y; array_vertices[14] = -z; //4
			array_vertices[15] =  x; array_vertices[16] = -y; array_vertices[17] =  z; //5
			array_vertices[18] =  x; array_vertices[19] =  y; array_vertices[20] = -z; //6
			array_vertices[21] =  x; array_vertices[22] =  y; array_vertices[23] =  z; //7
			for (char i=0;i<6;++i) {
				meshes[i]->numof_indices = 4;
			}

			//TODO
			/*if (normal_flag&GLLIB_NONE) {
				numof_normals = 0;
				for (char i=0;i<6;++i) {
					meshes[i]->has_normals = false;
				}
			}*/
			if (normal_flag&GLLIB_FACE_NORMALS) {
				numof_normals = 6;
				array_normals = new GLfloat[6*3];
				array_normals[ 0] = -1.0f; array_normals[ 1] =  0.0f; array_normals[ 2] =  0.0f; //0
				array_normals[ 3] =  1.0f; array_normals[ 4] =  0.0f; array_normals[ 5] =  0.0f; //1
				array_normals[ 6] =  0.0f; array_normals[ 7] = -1.0f; array_normals[ 8] =  0.0f; //2
				array_normals[ 9] =  0.0f; array_normals[10] =  1.0f; array_normals[11] =  0.0f; //3
				array_normals[12] =  0.0f; array_normals[13] =  0.0f; array_normals[14] =  1.0f; //4
				array_normals[15] =  0.0f; array_normals[16] =  0.0f; array_normals[17] = -1.0f; //5
				for (char i=0;i<6;++i) {
					meshes[i]->has_normals = true;
				}
			}
			#ifdef GLLIB_ERROR_MODE_REPORT_ERRORS
			else {
				throw GLLIB_ERROR_TYPE_ERROR("Invalid normal specifier!");
			}
			#endif

			if (texturing) {
				numof_texcoords = 4;
				array_texcoords = new GLfloat[4*2];
				array_texcoords[0] = 0.0f; array_texcoords[1] = 0.0f; //0
				array_texcoords[2] = 0.0f; array_texcoords[3] = 1.0f; //1
				array_texcoords[4] = 1.0f; array_texcoords[5] = 0.0f; //2
				array_texcoords[6] = 1.0f; array_texcoords[7] = 1.0f; //3
				for (char i=0;i<6;++i) {
					meshes[i]->has_texcoords = true;
				}
			}
			else {
				numof_texcoords = 0;
				for (char i=0;i<6;++i) {
					meshes[i]->has_texcoords = false;
				}
			}

			for (char i=0;i<6;++i) {
				meshes[i]->init();
			}

			//Left
			meshes[0]->vindices[0] = 3;
			meshes[0]->vindices[1] = 2;
			meshes[0]->vindices[2] = 0;
			meshes[0]->vindices[3] = 1;
			if (numof_normals==6) {
				meshes[0]->nindices[0] = 0;
				meshes[0]->nindices[1] = 0;
				meshes[0]->nindices[2] = 0;
				meshes[0]->nindices[3] = 0;
			}
			if (numof_texcoords==4) {
				meshes[0]->tindices[0] = 0;
				meshes[0]->tindices[1] = 2;
				meshes[0]->tindices[2] = 3;
				meshes[0]->tindices[3] = 1;
			}
			//Right
			meshes[1]->vindices[0] = 6;
			meshes[1]->vindices[1] = 7;
			meshes[1]->vindices[2] = 5;
			meshes[1]->vindices[3] = 4;
			if (numof_normals==6) {
				meshes[1]->nindices[0] = 1;
				meshes[1]->nindices[1] = 1;
				meshes[1]->nindices[2] = 1;
				meshes[1]->nindices[3] = 1;
			}
			if (numof_texcoords==4) {
				meshes[1]->tindices[0] = 0;
				meshes[1]->tindices[1] = 2;
				meshes[1]->tindices[2] = 3;
				meshes[1]->tindices[3] = 1;
			}
			//Bottom
			meshes[2]->vindices[0] = 0;
			meshes[2]->vindices[1] = 4;
			meshes[2]->vindices[2] = 5;
			meshes[2]->vindices[3] = 1;
			if (numof_normals==6) {
				meshes[2]->nindices[0] = 2;
				meshes[2]->nindices[1] = 2;
				meshes[2]->nindices[2] = 2;
				meshes[2]->nindices[3] = 2;
			}
			if (numof_texcoords==4) {
				meshes[2]->tindices[0] = 0;
				meshes[2]->tindices[1] = 2;
				meshes[2]->tindices[2] = 3;
				meshes[2]->tindices[3] = 1;
			}
			//Top
			meshes[3]->vindices[0] = 3;
			meshes[3]->vindices[1] = 7;
			meshes[3]->vindices[2] = 6;
			meshes[3]->vindices[3] = 2;
			if (numof_normals==6) {
				meshes[3]->nindices[0] = 3;
				meshes[3]->nindices[1] = 3;
				meshes[3]->nindices[2] = 3;
				meshes[3]->nindices[3] = 3;
			}
			if (numof_texcoords==4) {
				meshes[3]->tindices[0] = 0;
				meshes[3]->tindices[1] = 2;
				meshes[3]->tindices[2] = 3;
				meshes[3]->tindices[3] = 1;
			}
			//Back
			meshes[4]->vindices[0] = 7;
			meshes[4]->vindices[1] = 3;
			meshes[4]->vindices[2] = 1;
			meshes[4]->vindices[3] = 5;
			if (numof_normals==6) {
				meshes[4]->nindices[0] = 4;
				meshes[4]->nindices[1] = 4;
				meshes[4]->nindices[2] = 4;
				meshes[4]->nindices[3] = 4;
			}
			if (numof_texcoords==4) {
				meshes[4]->tindices[0] = 0;
				meshes[4]->tindices[1] = 2;
				meshes[4]->tindices[2] = 3;
				meshes[4]->tindices[3] = 1;
			}
			//Front
			meshes[5]->vindices[0] = 2;
			meshes[5]->vindices[1] = 6;
			meshes[5]->vindices[2] = 4;
			meshes[5]->vindices[3] = 0;
			if (numof_normals==6) {
				meshes[5]->nindices[0] = 5;
				meshes[5]->nindices[1] = 5;
				meshes[5]->nindices[2] = 5;
				meshes[5]->nindices[3] = 5;
			}
			if (numof_texcoords==4) {
				meshes[5]->tindices[0] = 0;
				meshes[5]->tindices[1] = 2;
				meshes[5]->tindices[2] = 3;
				meshes[5]->tindices[3] = 1;
			}

			numof_materials = 6;
			for (char i=0;i<6;++i) {
				string key = "RectangularSolidMaterial" + to_string(i);
				mtllib[key] = new material();
				if (texturing) {
					if (textures==NULL) {
						mtllib[key]->force_texture = true;
					}
					else {
						mtllib[key]->texture->reference(textures[i]);
					}
				}
				meshes[i]->requested_material_name = key;
			}

			glLibInternal_init_end();
		}
};

};};