#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct attrib
{
	size_t cap;
	size_t num;
	float* dat;
};

struct vertex
{
	float xyz[3];
	float nxyz[3];
	float uv[2];
};

struct ivert
{
	struct vertex v;
	unsigned long iv;
	unsigned long it;
	unsigned long in;
};

unsigned short getvertex(char** in, unsigned short* vcount, unsigned short* vcap, struct ivert** vdata)
{
	if(*vcount == *vcap) {
		*vcap += *vcap >> 1;
		*vdata = realloc(*vdata, *vcap * sizeof(struct ivert));
	}
	unsigned long v = strtoul(*in, in, 10) - 1;
	*in += 1;
	unsigned long t = strtoul(*in, in, 10) - 1;
	*in += 1;
	unsigned long n = strtoul(*in, in, 10) - 1;
	unsigned short idx = 0;
	for(; idx < *vcount; ++idx) {
		if((*vdata)[idx].iv == v &&
		   (*vdata)[idx].it == t &&
		   (*vdata)[idx].in == n)
		{
			return idx;
		}
	}
	(*vdata)[idx].iv = v;
	(*vdata)[idx].it = t;
	(*vdata)[idx].in = n;
	*vcount += 1;
	return idx;
}

int main(int argc, char** argv)
{
	FILE* fin = fopen(argv[1], "r");
	fseek(fin, 0, SEEK_END);
	long size = ftell(fin);
	char* geh = malloc(size + 1);
	char* in = geh;
	in[size] = 0;
	fseek(fin, 0, SEEK_SET);
	fread(in, size, 1, fin);
	fclose(fin);

	struct attrib vertex = {0};
	struct attrib normal = {0};
	struct attrib tcoord = {0};
	vertex.cap = 1024;
	vertex.dat = malloc(1024 * 3 * sizeof(float));
	normal.cap = 1024;
	normal.dat = malloc(1024 * 3 * sizeof(float));
	tcoord.cap = 1024;
	tcoord.dat = malloc(1024 * 3 * sizeof(float));

	//skip comments and go to first vertex
	while(in[0] == '#') in = strchr(in, '\n');
	in = strchr(in, 'v') - 1;

	while(in[2] != 't')
	{
		in += 2;
		if(vertex.num == vertex.cap) {
			vertex.cap += vertex.cap >> 1;
			vertex.dat = realloc(vertex.dat, vertex.cap * 3 * sizeof(float));
		}
		vertex.dat[vertex.num * 3 + 0] = strtof(in, &in);
		vertex.dat[vertex.num * 3 + 1] = strtof(in, &in);
		vertex.dat[vertex.num * 3 + 2] = strtof(in, &in);
		vertex.num += 1;
	}
	while(in[2] != 'n')
	{
		in += 3;
		if(tcoord.num == tcoord.cap) {
			tcoord.cap += tcoord.cap >> 1;
			tcoord.dat = realloc(tcoord.dat, tcoord.cap * 3 * sizeof(float));
		}
		tcoord.dat[tcoord.num * 3 + 0] = strtof(in, &in);
		tcoord.dat[tcoord.num * 3 + 1] = strtof(in, &in);
		tcoord.num += 1;
	}
	while(in[1] != 'f')
	{
		in += 3;
		if(normal.num == normal.cap) {
			normal.cap += normal.cap >> 1;
			normal.dat = realloc(normal.dat, normal.cap * 3 * sizeof(float));
		}
		normal.dat[normal.num * 3 + 0] = strtof(in, &in);
		normal.dat[normal.num * 3 + 1] = strtof(in, &in);
		normal.dat[normal.num * 3 + 2] = strtof(in, &in);
		normal.num += 1;
	}
	//create faces (fan when more than 3 vtx)
	unsigned short vcount = 0;
	unsigned short vcap = 1024;
	struct ivert* vdata = malloc(vcap * sizeof(struct ivert));
	unsigned short icount = 0;
	unsigned short icap = 1024;
	unsigned short* idata = malloc(icap * 3 * sizeof(unsigned short));
	while(in[1] != 0) {
		in += 3;
		if(icount == icap) {
			icap += icap >> 1;
			idata = realloc(idata, icap * 3 * sizeof(unsigned short));
		}
		idata[icount * 3 + 0] = getvertex(&in, &vcount, &vcap, &vdata);
		idata[icount * 3 + 1] = getvertex(&in, &vcount, &vcap, &vdata);
		idata[icount * 3 + 2] = getvertex(&in, &vcount, &vcap, &vdata);
		icount += 1;
		while(in[0] == ' ') {
			if(icount == icap) {
				icap += icap >> 1;
				idata = realloc(idata, icap * 3 * sizeof(unsigned short));
			}
			idata[icount * 3 + 0] = idata[icount * 3 - 3];
			idata[icount * 3 + 1] = idata[icount * 3 - 1];
			idata[icount * 3 + 2] = getvertex(&in, &vcount, &vcap, &vdata);
			icount += 1;
		}
	}
	free(geh);

	//fill vertex data
	for(size_t i = 0; i < vcount; ++i)
	{
		vdata[i].v.xyz[0] = vertex.dat[vdata[i].iv * 3 + 0];
		vdata[i].v.xyz[1] = vertex.dat[vdata[i].iv * 3 + 1];
		vdata[i].v.xyz[2] = vertex.dat[vdata[i].iv * 3 + 2];
		vdata[i].v.nxyz[0] = normal.dat[vdata[i].in * 3 + 0];
		vdata[i].v.nxyz[1] = normal.dat[vdata[i].in * 3 + 1];
		vdata[i].v.nxyz[2] = normal.dat[vdata[i].in * 3 + 2];
		vdata[i].v.uv[0] = tcoord.dat[vdata[i].it * 3 + 0];
		vdata[i].v.uv[1] = tcoord.dat[vdata[i].it * 3 + 1];
	}

	//open out file
	FILE* out = fopen("model.ymd","wb");
	//write header
	unsigned ver = 0;
	icount *= 3;
	fwrite(&ver, 4, 1, out);
	fwrite(&vcount, 2, 1, out);
	fwrite(&icount, 2, 1, out);
	//write vertices
	for(unsigned short i = 0; i < vcount; ++i)
		fwrite(&vdata[i], sizeof(struct vertex), 1, out);
	//write indices
	for(unsigned short i = 0; i < icount; ++i)
		fwrite(&idata[i], sizeof(unsigned short), 1, out);
	//close outfile
	fclose(out);
	return 0;
}