#include <GL/glew.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "wavefrontobj.h"

#define OBJ_LINE_BUFFER_SIZE 256

/**
 * 
 * ADJUSTMENT NEEDED FOR
 *     - Textures
 *     - Face Definitions other than vertex/texture/normal
 *     - Vertex positions including w
 *     - Any faces using vertices yet to be defined
 *       (File is read top to bottom. A face using a vertex
 *       defined underneath it in the file will not work)
 * 
 */

ParsedObjFile readObjFile(char* path) {
	ParsedObjFile parsedFile;

	FILE* fp = fopen(path, "r");

	if (fp == NULL) {
		fprintf(stderr, "File could not be opened: %s", path);
		parsedFile.faces = NULL;
		parsedFile.length = 0;
	}

	uint numVertices = 0;
	uint numVertexNormals = 0;
	uint numFaces = 0;
	uint numTextureCoords = 0;

	char buf[OBJ_LINE_BUFFER_SIZE];

	while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) {
		if (buf[0] == 'v') {
			if (buf[1] == ' ') {
				numVertices++;
			} else if (buf[1] == 't') {
				numTextureCoords++;
			} else if (buf[1] == 'n') {
				numVertexNormals++;
			}
		}
		if (buf[0] == 'f') {
			int numSpaces = 0;
			for (int i = 0; i < strlen(buf); i++) {
				if (buf[i] == ' ') {
					numSpaces++;
				}
			}
			numFaces += numSpaces - 2;
		}
	}

	// printf("Vertices: %d\nFaces: %d\nNormals:%d\nTextures:%d\n", numVertices, numFaces, numVertexNormals, numTextureCoords);

	vec3* vertices = (vec3*) malloc(sizeof(vec3) * numVertices);
	vec3* normals = (vec3*) malloc(sizeof(vec3) * numVertexNormals);

	face* faces = (face*) malloc(sizeof(face) * numFaces);

	parsedFile.faces = faces;
	parsedFile.length = numFaces;

	rewind(fp);

	uint curVertex = 0;
	uint curNormal = 0;
	uint curFace = 0;

	while (fgets(buf, OBJ_LINE_BUFFER_SIZE, fp)) {
		if (buf[0] == 'v') {
			if (buf[1] == ' ') {

				sscanf(buf,
					"v %f %f %f",
					&vertices[curVertex].x,
					&vertices[curVertex].y,
					&vertices[curVertex].z
				);
				curVertex++;

			} else if (buf[1] == 't') {
				continue;
			} else if (buf[1] == 'n') {

				sscanf(buf,
					"vn %f %f %f",
					&normals[curNormal].x,
					&normals[curNormal].y,
					&normals[curNormal].z
				);
				curNormal++;

			}
		}

		if (buf[0] == 'f') {
			int v1, v2, v3;
			int vt1, vt2, vt3;
			int vn1, vn2, vn3;

			sscanf(buf,
				"f %d/%d/%d %d/%d/%d %d/%d/%d",
				&v1, &vt1, &vn1,
				&v2, &vt2, &vn2,
				&v3, &vt3, &vn3
			);

			memcpy(&faces[curFace].v1.position, &vertices[v1 - 1], sizeof(vec3));
			memcpy(&faces[curFace].v2.position, &vertices[v2 - 1], sizeof(vec3));
			memcpy(&faces[curFace].v3.position, &vertices[v3 - 1], sizeof(vec3));

			memcpy(&faces[curFace].v1.normal, &normals[vn1 - 1], sizeof(vec3));
			memcpy(&faces[curFace].v2.normal, &normals[vn2 - 1], sizeof(vec3));
			memcpy(&faces[curFace].v3.normal, &normals[vn3 - 1], sizeof(vec3));

			curFace++;

			int numSpaces = 0;
			for (int i = 0; i < strlen(buf); i++) {
				if (buf[i] == ' ') {
					numSpaces++;
				}
			}

			if (numSpaces == 4) {
				sscanf(buf,
					"f %d/%d/%d %*d/%*d/%*d %d/%d/%d %d/%d/%d",
					&v1, &vt1, &vn1,
					&v2, &vt2, &vn2,
					&v3, &vt3, &vn3
				);

				memcpy(&faces[curFace].v1.position, &vertices[v1 - 1], sizeof(vec3));
				memcpy(&faces[curFace].v2.position, &vertices[v2 - 1], sizeof(vec3));
				memcpy(&faces[curFace].v3.position, &vertices[v3 - 1], sizeof(vec3));

				memcpy(&faces[curFace].v1.normal, &normals[vn1 - 1], sizeof(vec3));
				memcpy(&faces[curFace].v2.normal, &normals[vn2 - 1], sizeof(vec3));
				memcpy(&faces[curFace].v3.normal, &normals[vn3 - 1], sizeof(vec3));

				curFace++;
			}


			// TODO: textures
		}

	}

	free(vertices);
	free(normals);
	fclose(fp);

	return parsedFile;
}

void clearParsedFile(ParsedObjFile file) {
	free(file.faces);
}