#include "somarray.h"

somArray_s* ReadSomArrayChunk( char* fname, dbl_chunk_header_s* pChunkHeader,
							   System::Windows::Forms::RichTextBox^ logbox, INT iAdditionalOffset ) {
	FILE* pChunk;
	INT iByte, iHeaderSize, iNumMeshes, iLastPos;
	char szMessage[128];
	somArray_s* pSomArray;
	INT iMeshHeaderOffset;
	float vertex;

	pChunk = fopen( fname, "rb" );
	iByte = 0;
	iNumMeshes = 0;

	switch( pChunkHeader->iFlag ) {
		case 0x0E:
			iHeaderSize = FLAG_0E;
		break;
		case 0x06:
			iHeaderSize = FLAG_06;
		break;
		case 0x00:
			iHeaderSize = FLAG_00;
		break;
		default:
			sprintf( szMessage, "Unknown chunk-header flag 0x%02x!", pChunkHeader->iFlag );
			MessageBoxA( NULL, szMessage, "ERROR", MB_ICONERROR );
			return FALSE;
		break;
	}

	iMeshHeaderOffset = iLastPos = 0;
	pSomArray = (somArray_s*)malloc( sizeof(somArray_s) );
	fseek( pChunk, iHeaderSize, 0 );
	fread( &iNumMeshes, 2, 1, pChunk );
	fseek( pChunk, 2, SEEK_CUR );
	pSomArray->somOffsets = (INT*)malloc( iNumMeshes*4 );
	pSomArray->nummeshes = iNumMeshes; // < < < < < <
	pSomArray->meshes = (sSOMObj_s*)malloc( pSomArray->nummeshes*sizeof(sSOMObj_s) );

	for( INT i = 0; i < iNumMeshes; i++ ) {
		fread( &pSomArray->somOffsets[i], 4, 1, pChunk );
	}
	fread( &pSomArray->iSize, 4, 1, pChunk ); fseek( pChunk, 2, SEEK_CUR ); // Skip 2 bytes of nothing
	fseek( pChunk, 36, SEEK_CUR ); // Is this always static?

	for( INT i = 0; i < iNumMeshes; i++ ) {
		fseek( pChunk, pSomArray->somOffsets[i]+iHeaderSize+120, 0 ); // iHeaderSize+DBL Header size??

		fread( &iMeshHeaderOffset, 4, 1, pChunk );
		iMeshHeaderOffset += pSomArray->somOffsets[i]+iHeaderSize;
		fseek( pChunk, iMeshHeaderOffset, 0 );

		// Usually this should point us RIGHT to the som header,if it's not the case keep looking for it
		while( iByte != SOM_HEADER ) fread( &iByte, 4, 1, pChunk );
		iMeshHeaderOffset = ftell( pChunk )-4; // Shift back 4 bytes cuz we've read 4 bytes
		if( i ) { fseek( pChunk, 4, SEEK_CUR ); iMeshHeaderOffset += 4; }
		// ^ If it's not the first mesh we have to add 4 for some reason

		// Som Header data is 19 elements each full 32-bit INT (4 bytes)
		fread( pSomArray->meshes[i].somHeader, 19, 4, pChunk );

		iLastPos = ftell( pChunk )+( pSomArray->meshes[i].somHeader[SOM_NUMINDICES]*2 );
		if( iAdditionalOffset ) pSomArray->meshes[i].somHeader[15] -= iAdditionalOffset;

		// 15 mesh data?
		fseek( pChunk, iMeshHeaderOffset+(pSomArray->meshes[i].somHeader[15]), 0 );

		pSomArray->meshes[i].submeshes = (sMesh_s*)malloc( pSomArray->meshes[i].somHeader[SOM_NUMSUBMESHES]*sizeof(sMesh_s) );
		for( INT m = 0; m < pSomArray->meshes[i].somHeader[SOM_NUMSUBMESHES]; m++ ) {
			pSomArray->meshes[i].submeshes[m].meshData = (INT*)malloc( 40 );
			fread( pSomArray->meshes[i].submeshes[m].meshData, 4, 10, pChunk );
			//if( pSomArray->meshes[i].somHeader[SOM_NUMSUBMESHES] == 1 )
				pSomArray->meshes[i].submeshes[m].meshData[MESH_NUMINDICES] = pSomArray->meshes[i].somHeader[SOM_NUMINDICES];
		}

		for( INT m = 0; m < pSomArray->meshes[i].somHeader[SOM_NUMSUBMESHES]; m++ ) {
			fseek( pChunk, pSomArray->meshes[i].somHeader[SOM_OFFSINDICES]+iMeshHeaderOffset, 0 );
			pSomArray->meshes[i].submeshes[m].indices = (UINT16*)malloc( pSomArray->meshes[i].submeshes[m].meshData[MESH_NUMINDICES]*2 );

			// Assuming all indices are 2bytes long, although it might be a problem if the model is huge
			fseek( pChunk, pSomArray->meshes[i].submeshes[m].meshData[MESH_STRTINDICE]*2, SEEK_CUR );

			for( INT ind = 0; ind < pSomArray->meshes[i].submeshes[m].meshData[MESH_NUMINDICES]; ind++ ) {
				fread( &pSomArray->meshes[i].submeshes[m].indices[ind], 2, 1, pChunk );
			}

			fseek( pChunk, iLastPos, 0 );

			pSomArray->meshes[i].submeshes[m].vertData = (INT*)malloc( 16 );
			fread( pSomArray->meshes[i].submeshes[m].vertData, 4, 4, pChunk );

			fseek( pChunk, pSomArray->meshes[i].submeshes[m].vertData[VERT_OFFSET]+iMeshHeaderOffset, 0 );
			pSomArray->meshes[i].submeshes[m].vertexes = (sVertex_s*)malloc( (pSomArray->meshes[i].submeshes[m].vertData[VERT_NUMVERTS])*sizeof(sVertex_s) );
			//pSomArray->meshes[i].submeshes[m].normals = (sVertex_s*)malloc( (pSomArray->meshes[i].submeshes[m].vertData[VERT_NUMVERTS])*sizeof(sVertex_s) );

			for( INT vert = 0; vert < pSomArray->meshes[i].submeshes[m].vertData[VERT_NUMVERTS]; vert++ ) {
				fread( &pSomArray->meshes[i].submeshes[m].vertexes[vert].x, 4, 1, pChunk );
				fread( &pSomArray->meshes[i].submeshes[m].vertexes[vert].y, 4, 1, pChunk );
				fread( &pSomArray->meshes[i].submeshes[m].vertexes[vert].z, 4, 1, pChunk );

				//fseek( pChunk, 12, SEEK_CUR );
				fseek( pChunk, pSomArray->meshes[i].submeshes[m].vertData[VERT_STRIDE]-12, SEEK_CUR );
			}
			iLastPos += 16; // For reading meshdata
		}
	}

	return pSomArray;
}

BOOL ConstructOBJ( char* obj, somArray_s* pSomArray, char** fnames, INT iMesh ) {
	FILE* pOBJFile;
	char pLine[256];
	INT iAssignedVertexes, ind;

	pOBJFile = fopen( obj, "w" );

	if( !pOBJFile ) {
		MessageBoxA( NULL, "Couldn't create/open the OBJ file for writing", "ERROR", MB_ICONERROR );
		return FALSE;
	}

	iAssignedVertexes = 1;

	fputs( "# OBJ File Created By DBLFucker\n\n", pOBJFile );

	for( INT i = (iMesh > -1 ? iMesh : 0); i < (iMesh > -1 ? iMesh+1 : pSomArray->nummeshes); i++ ) {
		for( INT m = 0; m < pSomArray->meshes[i].somHeader[SOM_NUMSUBMESHES]; m++ ) {
			for( INT vert = 0; vert < pSomArray->meshes[i].submeshes[m].vertData[VERT_NUMVERTS]; vert++ ) {
				sprintf( pLine, "v %f %f %f\n", pSomArray->meshes[i].submeshes[m].vertexes[vert].x,
					pSomArray->meshes[i].submeshes[m].vertexes[vert].y,
					pSomArray->meshes[i].submeshes[m].vertexes[vert].z );
				fputs( pLine, pOBJFile );
			}
			strcpy( pLine, "\n\n" );
			fputs( pLine, pOBJFile );
		}
		strcpy( pLine, "\n\n\n\n" );
		fputs( pLine, pOBJFile );
	}

	for( INT i = (iMesh > -1 ? iMesh : 0); i < (iMesh > -1 ? iMesh+1 : pSomArray->nummeshes); i++ ) {
		sprintf( pLine, "g %s\n", fnames[i] );
		fputs( pLine, pOBJFile );

		for( INT m = 0; m < pSomArray->meshes[i].somHeader[SOM_NUMSUBMESHES]; m++ ) {
			//for( ind = pSomArray->meshes[i].submeshes[m].meshData[MESH_NUMINDICES]-3; ind > 0; ind-- ) {
			for( ind = 0; ind < pSomArray->meshes[i].submeshes[m].meshData[MESH_NUMINDICES]-2; ind++ ) {
				if(
					(pSomArray->meshes[i].submeshes[m].indices[ind] == pSomArray->meshes[i].submeshes[m].indices[ind+1])
					|| (pSomArray->meshes[i].submeshes[m].indices[ind] == pSomArray->meshes[i].submeshes[m].indices[ind+2])
					|| (pSomArray->meshes[i].submeshes[m].indices[ind+1] == pSomArray->meshes[i].submeshes[m].indices[ind+2]) )
						continue;

				fprintf( pOBJFile, "f %i %i %i\n",
					iAssignedVertexes+pSomArray->meshes[i].submeshes[m].indices[ind],
					iAssignedVertexes+pSomArray->meshes[i].submeshes[m].indices[ind+1],
					iAssignedVertexes+pSomArray->meshes[i].submeshes[m].indices[ind+2] );
			}
			iAssignedVertexes = pSomArray->meshes[i].submeshes[m].indices[ind+1];
			//iAssignedVertexes += ind;
		}
	}

	fclose( pOBJFile );

	return TRUE;
}