#include "wavefrontobj.h"
#include <GL/glew.h>
#include <stdlib.h>

typedef struct {
    GLuint vao;
    GLuint vbo;
	ParsedObjFile object;
} ObjectData;

/**
 * Loads an object.
 * Basically generates vbo and vao for an object and saving them in the ObjectData struct.
 */
void load_object(ObjectData* objectData) {
		// write faces to buffer
	//GLuint triangleVertexBufferObject;
	glGenBuffers(1, &objectData->vbo);
	glBindBuffer(GL_ARRAY_BUFFER, objectData->vbo);
	glBufferData(GL_ARRAY_BUFFER, objectData->object.length * sizeof(face), objectData->object.faces, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);


	// create vertex array object
	glGenVertexArrays(1, &objectData->vao);
	glBindVertexArray(objectData->vao);
	glBindBuffer(GL_ARRAY_BUFFER, objectData->vao);

	// vertex positions
	glVertexAttribPointer(
		0,
		3,
		GL_FLOAT,
		GL_FALSE,
		sizeof(vertex),
		0
	);
	glEnableVertexAttribArray(0);

	// vertex normals
	glVertexAttribPointer(
		1,
		3,
		GL_FLOAT,
		GL_FALSE,
		sizeof(vertex),
		(void*) offsetof(vertex, normal)
	);
	glEnableVertexAttribArray(1);

	// vertex texture coordinates
	glVertexAttribPointer(
		2,
		2,
		GL_FLOAT,
		GL_FALSE,
		sizeof(vertex),
		(void*) offsetof(vertex, texture)
	);
	glEnableVertexAttribArray(2);

	// face tangents
	glVertexAttribPointer(
		3,
		3,
		GL_FLOAT,
		GL_FALSE,
		sizeof(vertex),
		(void*) offsetof(vertex, tangent)
	);
	glEnableVertexAttribArray(3);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);
}

/**
 * Takes a string-pointer, a number of files to read and a number to store the added objects to
 * Returns an array of objects.
*/
ObjectData* readObjFiles(char** path, int numModels, int* count) {
	ObjectData* objects = (ObjectData*) malloc(sizeof(ObjectData) * numModels);
	*count += numModels;
	if (!objects) {
        printf("ERROR in objectHandler: Failed to allocate memory for objects\n");
        return NULL;
    }

	for (int i = 0; i < numModels; ++i) {
        objects[i].object = readObjFile(path[i]);
		load_object(&objects[i]);
    }
	
	return objects;
}

/**
 * Takes a single object and reads it a certain number of times.
 * Returns an array of objects.
 */
ObjectData* readSingleObjFile(char** path, int numModels, int* count) {
	ObjectData* objects = (ObjectData*) malloc(sizeof(ObjectData) * numModels);
	*count += numModels;
	
	if (!objects) {
        printf("ERROR in objectHandler: Failed to allocate memory for objects\n");
		fflush(stdout);
        return NULL;
    }

	for (int i = 0; i < numModels; ++i) {
        objects[i].object = readObjFile(*path);
		load_object(&objects[i]);
		*count++;
    }
	
	return objects;
}

/**
 * Draw call for a single object.
 * Used to clean up the draw calls in Main().
 */
void draw_object(ObjectData* objectData) {
    glBindVertexArray(objectData->vao);
    glDrawArrays(GL_TRIANGLES, 0, objectData->object.length * 3); // Annahme: Jedes face hat 3 vertices
    glBindVertexArray(0);
}