#include "renderer/VertexIO.h"
#include "unittest/TestSuite.h"

static void testInit(void) {
	VertexAttributeTypeSpec attributeTypeSpec = {"position", ATTRIBUTE_TYPE_FLOAT, ATTRIBUTE_USAGE_POSITION, 2};
	VertexFormat * vertexFormat = VertexFormat_create(1, &attributeTypeSpec);
	VertexIO * vertexIO = VertexIO_create(vertexFormat, 1.0, 2.0);
	TestCase_assertPointerNonNULL(vertexIO);
	TestCase_assertPointerEqual(vertexIO->vertexFormat, vertexFormat);
	TestCase_assertPointerNULL(vertexIO->vertices);
	TestCase_assertPointerNULL(vertexIO->indexes);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 0);
	TestCase_assertUIntEqual(vertexIO->indexCount, 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[0], 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[1], 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[2], 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[3], 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[4], 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[5], 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[6], 0);
	TestCase_assertUIntEqual(vertexIO->textureBinds[7], 0);
	TestCase_assertDoubleEqual(vertexIO->referenceTime, 1.0);
	TestCase_assertDoubleEqual(vertexIO->deltaTime, 2.0);
	VertexIO_dispose(vertexIO);
	VertexFormat_dispose(vertexFormat);
}

static void testGetTextureIndex(void) {
	VertexAttributeTypeSpec attributeTypeSpec = {"position", ATTRIBUTE_TYPE_FLOAT, ATTRIBUTE_USAGE_POSITION, 2};
	VertexFormat * vertexFormat = VertexFormat_create(1, &attributeTypeSpec);
	VertexIO * vertexIO = VertexIO_create(vertexFormat, 0.0, 0.0);
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 0), 0);
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 1), 0);
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 2), 0);
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 3), 0);
	vertexIO->textureBinds[1] = 1;
	vertexIO->textureBinds[2] = 3;
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 0), 0);
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 1), 1);
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 2), 0);
	TestCase_assertUIntEqual(VertexIO_getTextureIndex(vertexIO, 3), 2);
	VertexIO_dispose(vertexIO);
	VertexFormat_dispose(vertexFormat);
}

static void testWriteVertices(void) {
	VertexAttributeTypeSpec attributeTypeSpec1 = {"position", ATTRIBUTE_TYPE_FLOAT, ATTRIBUTE_USAGE_POSITION, 2};
	VertexFormat * vertexFormat1 = VertexFormat_create(1, &attributeTypeSpec1);
	VertexIO * vertexIO = VertexIO_create(vertexFormat1, 0.0, 0.0);
	float vertices[6] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
	VertexIO_writeVertices(vertexIO, 1, vertices);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 1);
	TestCase_assertPointerNonNULL(vertexIO->vertices);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[0], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[1], 1.0f);
	VertexIO_writeVertices(vertexIO, 3, vertices);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 4);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[0], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[1], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[2], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[3], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[4], 2.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[5], 3.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[6], 4.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[7], 5.0f);
	VertexIO_dispose(vertexIO);
	VertexFormat_dispose(vertexFormat1);
	
	VertexAttributeTypeSpec attributeTypeSpec2 = {"position", ATTRIBUTE_TYPE_FLOAT, ATTRIBUTE_USAGE_POSITION, 3};
	VertexFormat * vertexFormat2 = VertexFormat_create(1, &attributeTypeSpec2);
	vertexIO = VertexIO_create(vertexFormat2, 0.0, 0.0);
	VertexIO_writeVertices(vertexIO, 2, vertices);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 2);
	TestCase_assertPointerNonNULL(vertexIO->vertices);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[0], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[1], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[2], 2.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[3], 3.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[4], 4.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[5], 5.0f);
	VertexIO_writeVertices(vertexIO, 1, vertices);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 3);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[0], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[1], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[2], 2.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[3], 3.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[4], 4.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[5], 5.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[6], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[7], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[8], 2.0f);
	VertexIO_dispose(vertexIO);
	VertexFormat_dispose(vertexFormat2);
}

static void testWriteIndexes(void) {
	VertexAttributeTypeSpec attributeTypeSpec = {"position", ATTRIBUTE_TYPE_FLOAT, ATTRIBUTE_USAGE_POSITION, 2};
	VertexFormat * vertexFormat = VertexFormat_create(1, &attributeTypeSpec);
	VertexIO * vertexIO = VertexIO_create(vertexFormat, 0.0, 0.0);
	uint32_t indexes[3] = {0, 1, 2};
	VertexIO_writeIndexes(vertexIO, 2, indexes);
	TestCase_assertUIntEqual(vertexIO->indexCount, 2);
	TestCase_assertPointerNonNULL(vertexIO->indexes);
	TestCase_assertUIntEqual(vertexIO->indexes[0], 0);
	TestCase_assertUIntEqual(vertexIO->indexes[1], 1);
	VertexIO_writeIndexes(vertexIO, 3, indexes);
	TestCase_assertUIntEqual(vertexIO->indexCount, 5);
	TestCase_assertUIntEqual(vertexIO->indexes[0], 0);
	TestCase_assertUIntEqual(vertexIO->indexes[1], 1);
	TestCase_assertUIntEqual(vertexIO->indexes[2], 0);
	TestCase_assertUIntEqual(vertexIO->indexes[3], 1);
	TestCase_assertUIntEqual(vertexIO->indexes[4], 2);
	VertexIO_dispose(vertexIO);
	VertexFormat_dispose(vertexFormat);
}

static void testWriteIndexedVertices(void) {
	VertexAttributeTypeSpec attributeTypeSpec = {"position", ATTRIBUTE_TYPE_FLOAT, ATTRIBUTE_USAGE_POSITION, 2};
	VertexFormat * vertexFormat = VertexFormat_create(1, &attributeTypeSpec);
	VertexIO * vertexIO = VertexIO_create(vertexFormat, 0.0, 0.0);
	float vertices[8] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
	uint32_t indexes[6] = {0, 1, 2, 2, 3, 0};
	VertexIO_writeIndexedVertices(vertexIO, 1, vertices, 1, indexes);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 1);
	TestCase_assertPointerNonNULL(vertexIO->vertices);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[0], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[1], 1.0f);
	TestCase_assertUIntEqual(vertexIO->indexCount, 1);
	TestCase_assertPointerNonNULL(vertexIO->indexes);
	TestCase_assertUIntEqual(vertexIO->indexes[0], 0);
	
	VertexIO_writeIndexedVertices(vertexIO, 4, vertices, 6, indexes);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 5);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[0], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[1], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[2], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[3], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[4], 2.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[5], 3.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[6], 4.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[7], 5.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[8], 6.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[9], 7.0f);
	TestCase_assertUIntEqual(vertexIO->indexCount, 7);
	TestCase_assertUIntEqual(vertexIO->indexes[0], 0);
	TestCase_assertUIntEqual(vertexIO->indexes[1], 1);
	TestCase_assertUIntEqual(vertexIO->indexes[2], 2);
	TestCase_assertUIntEqual(vertexIO->indexes[3], 3);
	TestCase_assertUIntEqual(vertexIO->indexes[4], 3);
	TestCase_assertUIntEqual(vertexIO->indexes[5], 4);
	TestCase_assertUIntEqual(vertexIO->indexes[6], 1);
	
	VertexIO_writeIndexedVertices(vertexIO, 1, vertices, 1, indexes);
	TestCase_assertUIntEqual(vertexIO->vertexCount, 6);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[0], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[1], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[2], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[3], 1.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[4], 2.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[5], 3.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[6], 4.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[7], 5.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[8], 6.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[9], 7.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[10], 0.0f);
	TestCase_assertFloatEqual(((float *) vertexIO->vertices)[11], 1.0f);
	TestCase_assertUIntEqual(vertexIO->indexCount, 8);
	TestCase_assertUIntEqual(vertexIO->indexes[0], 0);
	TestCase_assertUIntEqual(vertexIO->indexes[1], 1);
	TestCase_assertUIntEqual(vertexIO->indexes[2], 2);
	TestCase_assertUIntEqual(vertexIO->indexes[3], 3);
	TestCase_assertUIntEqual(vertexIO->indexes[4], 3);
	TestCase_assertUIntEqual(vertexIO->indexes[5], 4);
	TestCase_assertUIntEqual(vertexIO->indexes[6], 1);
	TestCase_assertUIntEqual(vertexIO->indexes[7], 5);
	VertexIO_dispose(vertexIO);
	VertexFormat_dispose(vertexFormat);
}

TEST_SUITE(VertexIOTest,
           testInit,
           testGetTextureIndex,
           testWriteVertices,
           testWriteIndexes,
           testWriteIndexedVertices)
