#include "texcontext.h"

TexContextList_s* LoadTexContextChunk( const char* chunkfname ) {
	dbl_chunk_header_s* pChunkHeader;
	FILE* pChunk;
	char szMessage[128];
	TexContextList_s* pTexContextList = (TexContextList_s*)malloc( sizeof(TexContextList_s) );
	TexContext_s* pTexContextArray, * pTexContextPacked;
	INT iHeaderSize, iByte, iLastPos, iPrevPacked, iTotalPacked, t;
	INT* iOffsetsToGoTo;

	pChunk = fopen( chunkfname, "rb" );
	if( !pChunk ) {
		MessageBoxA( NULL, "Couldn't open the DB_TEXTURE_CONTEXT chunk", "ERROR", MB_ICONERROR );
		return FALSE;
	}
	pChunkHeader = ReadChunkHeader( pChunk, 0, (dbl_header_s*)DBL_CHUNK_NODBLHEADER );
	if( !pChunkHeader ) {
		MessageBoxA( NULL, "Couldn't read the chunk header", "ERROR", MB_ICONERROR );
		return FALSE;
	}

	if( pChunkHeader->iDataChunkType != DB_TEXTURE_CONTEXT &&
		pChunkHeader->iDataChunkType != DB_TEXTURE_CONTEXT2 ) {
			MessageBoxA( NULL, "The chunk header datatype mismatch\nThis is NOT a texture context chunk", "ERROR", MB_ICONERROR );
			return FALSE;
	}

	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 );
			free( pChunkHeader );
			return FALSE;
		break;
	}

	free( pChunkHeader );

	iByte = 0;
	fseek( pChunk, iHeaderSize, 0 );
	fread( &iByte, 2, 1, pChunk );
	//iByte = 35;
	pTexContextList->iEntries = iByte;
	fseek( pChunk, 2, SEEK_CUR );

	iOffsetsToGoTo = (INT*)malloc( pTexContextList->iEntries*4 );

	for( INT i = 0; i < pTexContextList->iEntries; i++ ) {
		fread( &iByte, 4, 1, pChunk );
		iOffsetsToGoTo[i] = iByte;
		iByte = 0;
	}

	pTexContextArray = (TexContext_s*)malloc( (pTexContextList->iEntries*4)*sizeof(TexContext_s) );

	// Start reading entries

	iPrevPacked = 0;
	iTotalPacked = 0;
	iLastPos = 0;
	t = -1;
	for( INT i = 0; i < pTexContextList->iEntries; i++ ) {
		t++;
		iByte = iOffsetsToGoTo[i];
		pTexContextArray[t].iOffset = iByte;
		iLastPos = ftell( pChunk );
		fseek( pChunk, iByte+iHeaderSize, 0 );
		fseek( pChunk, 4, SEEK_CUR );
		iByte = 0;
		fread( &iByte, 1, 1, pChunk );
		pTexContextArray[t].iPacked = iByte;
		iPrevPacked = iByte;
		/*if( pTexContextArray[t].iPacked == 0xEE ) {
			break;
		}*/
		if( !pTexContextArray[t].iPacked ) {
			fseek( pChunk, iLastPos, 0 );
			iByte = 0;
			continue;
		}
		for( INT p = 0; p < iPrevPacked; p++ ) {
			if( p > 0 ) fseek( pChunk, (32-strlen(pTexContextArray[t-1].associatedMesh))-1, SEEK_CUR );
			else fseek( pChunk, 3, SEEK_CUR );
			fread( &iByte, 2, 1, pChunk );
			pTexContextArray[t].iTexNum = iByte;
			fseek( pChunk, 5, SEEK_CUR );
			fread( &iByte, 4, 1, pChunk );
			fseek( pChunk, 1, SEEK_CUR );
			pTexContextArray[t].iFX = iByte;
			iByte = 1;
			pTexContextArray[t].associatedMesh = (char*)malloc( 64*4 );
			for( INT c = 0; c < 64; c++ ) {
				fread( &iByte, 1, 1, pChunk );
				pTexContextArray[t].associatedMesh[c] = iByte;
				if( iByte == 0x00 ) break;
				iByte = 0;
			}
			t++;
		}
		t--;
		fseek( pChunk, iLastPos, 0 );
		iByte = 0;
	}

	pTexContextList->iWrittenEntries = t+1;

	// Shrink the context array because there's a lot of unused mem here that's just occupied and not used

	pTexContextPacked = (TexContext_s*)malloc( pTexContextList->iWrittenEntries*sizeof(TexContext_s) );
	for( INT i = 0; i < pTexContextList->iWrittenEntries; i++ ) {
		if( !pTexContextArray[i].iPacked ) {
			pTexContextPacked[i].iPacked = pTexContextArray[i].iPacked;
			continue;
		}
		pTexContextPacked[i].associatedMesh = (char*)malloc( strlen(pTexContextArray[i].associatedMesh)*4 );
		strcpy( pTexContextPacked[i].associatedMesh, pTexContextArray[i].associatedMesh );
		free( pTexContextArray[i].associatedMesh );
		pTexContextPacked[i].iFX = pTexContextArray[i].iFX;
		pTexContextPacked[i].iOffset = pTexContextArray[i].iOffset;
		pTexContextPacked[i].iPacked = pTexContextArray[i].iPacked;
		pTexContextPacked[i].iTexNum = pTexContextArray[i].iTexNum;
	}
	free( pTexContextArray );
	free( iOffsetsToGoTo );

	fclose( pChunk );

	pTexContextList->context = pTexContextPacked;
	return pTexContextList;
}

BOOL CreateTexContextChunk( const char* chunkfname, TexContextList_s* pTexContextList, dbl_chunk_header_s* pHeader ) {
	FILE* pChunk;
	INT iHeaderSize, iByte, namelen, iLastPos, t, iPrevPacked;
	INT16* iTCOffsets;

	pChunk = fopen( chunkfname, "wb" );
	if( !pChunk ) {
		MessageBoxA( NULL, "Couldn't create the chunk data-file", "ERROR", MB_ICONERROR );
		return FALSE;
	}

	iTCOffsets = (INT16*)malloc( pTexContextList->iEntries*2 );

	iByte = 0;
	fwrite( &pHeader->iDataChunkType, 2, 1, pChunk );
	fwrite( &pHeader->iFlag, 2, 1, pChunk );
	//fwrite( &iByte, 1, 1, pChunk );
	fseek( pChunk, 4, SEEK_CUR );
	fwrite( &pHeader->iDataChunkVer, 2, 1, pChunk );
	if( pHeader->iFlag != 0x00 ) {
		fwrite( "1000", 4, 1, pChunk ); //iHeaderSize += 4; // It's 4 more bytes because of the 1000
	}

	switch( pHeader->iFlag ) {
		case 0x0E:
			iHeaderSize = FLAG_0E;
		break;
		case 0x06:
			iHeaderSize = FLAG_06;
		break;
		case 0x00:
			iHeaderSize = FLAG_00;
		break;
	}

	fseek( pChunk, iHeaderSize, 0 );
	iByte = pTexContextList->iEntries;
	fwrite( &iByte, 2, 1, pChunk );
	iByte = 1;
	fwrite( &iByte, 1, 1, pChunk );
	fseek( pChunk, 1, SEEK_CUR );

	for( INT i = 0; i < pTexContextList->iEntries; i++ ) {
		iTCOffsets[i] = ftell( pChunk );
		fseek( pChunk, 4, SEEK_CUR );
	}

	namelen = 32; // Make sure we do not move forward to god knows where on the first entry
	t = -1;
	for( INT i = 0; i < pTexContextList->iEntries; i++ ) {
		t++; // We keep track of how many actual entries we've parsed separate to the entries that
		fseek( pChunk, 32-namelen, SEEK_CUR ); // may contain other sub-entries inside (i)
		iLastPos = ftell( pChunk )-iHeaderSize; // Memorize where we're writing at
		fseek( pChunk, iTCOffsets[i], 0 ); // Go to our sweet spot to fill in the offset
		fwrite( &iLastPos, 4, 1, pChunk );
		fseek( pChunk, iLastPos+iHeaderSize, 0 ); // Go back
		iByte = 0xFF; // It doesn't have to be 0xFF, but it's a tradition
		for( INT b = 0; b < 4; b++ ) fwrite( &iByte, 1, 1, pChunk );
		iPrevPacked = pTexContextList->context[t].iPacked;
		fwrite( &pTexContextList->context[t].iPacked, 1, 1, pChunk ); // Write how many other entries this entry has packed inside of it
		if( t >= pTexContextList->iWrittenEntries ) break;
		if( !iPrevPacked ) { // If this thing doesn't have anything packed we skip the iteration, why it even exists?
			iByte = 0;
			for( INT b = 0; b < 3; b++ ) fwrite( &iByte, 1, 1, pChunk );
			continue;
		}
		namelen = strlen(pTexContextList->context[t].associatedMesh);
		for( INT p = 0; p < iPrevPacked; p++ ) {
			namelen = strlen(pTexContextList->context[t].associatedMesh);
			fseek( pChunk, 3, SEEK_CUR );
			fwrite( &pTexContextList->context[t].iTexNum, 2, 1, pChunk );
			fseek( pChunk, 1, SEEK_CUR );
			iByte = 1;
			for( INT b = 0; b < 4; b++ ) fwrite( &iByte, 1, 1, pChunk );
			fwrite( &pTexContextList->context[t].iFX, 4, 1, pChunk );
			fseek( pChunk, 1, SEEK_CUR );
			for( INT y = 0; y < namelen; y++ ) {
				fwrite( &pTexContextList->context[t].associatedMesh[y], 1, 1, pChunk );
			}
			// In some circumstances you have to subtract 3, or not.. it's a weird system I know
			fseek( pChunk, (iPrevPacked > 1 && p < iPrevPacked-1) ? (32-namelen)-3 : 32-namelen, SEEK_CUR );
			t++; // One more entry has been parsed
		}
		t--; // Remove the extra entry
		namelen = 32; // Make sure we don't go forward on our next iteration
	}

	// FINALIZE, calculate the chunk size
	iLastPos = 0;
	fseek( pChunk, 0, SEEK_END );
	iLastPos = ftell( pChunk )-iHeaderSize;
	fseek( pChunk, 4, 0 );
	fwrite( &iLastPos, 4, 1, pChunk );
	free( iTCOffsets );

	fclose( pChunk );

	return TRUE;
}

char* FindATexContextChunk( char* szChunkfilename ) {
	char path[128];
	char seekpath[128];
	char pFilename[256];
	INT iLastSlash = 0, iTotalCHFiles = 0;
	FILE* pChunkFile;
	HANDLE hFile;
	char hPrevFile[256];
	WIN32_FIND_DATAA pFileData;
	dbl_chunk_header_s* pTexContextHdr;

	for( INT i = 0; i < strlen(szChunkfilename); i++ ) if( szChunkfilename[i] == '\\' ) iLastSlash = i;
	strcpy( path, szChunkfilename );
	path[iLastSlash] = '\0';
	strcpy( pFilename, path );
	strcpy( seekpath, path );
	strcat( seekpath, "\\*.chk" );

	hFile = (HANDLE)1;
	while( hFile ) {
		if( hFile == (HANDLE)1 ) hFile = FindFirstFileA(seekpath, &pFileData);
		FindNextFileA(hFile, &pFileData);
		if( !strcmp(pFileData.cFileName, hPrevFile) ) break;
		strcpy( hPrevFile, pFileData.cFileName );

		iTotalCHFiles++;
	}

	for( INT i = 0; i < iTotalCHFiles; i++ ) {
		sprintf( hPrevFile, (i+1 < 10) ? "\\Chunk0%i.chk" : "\\Chunk%i.chk", i+1 );
		strcpy( path, pFilename );
		strcat( path, hPrevFile );
		pChunkFile = fopen( path, "rb" );
		if( !pChunkFile ) continue;

		pTexContextHdr = ReadChunkHeader( pChunkFile, 0, (dbl_header_s*)DBL_CHUNK_NODBLHEADER );
		if( pTexContextHdr->iDataChunkType == DB_TEXTURE_CONTEXT || 
			pTexContextHdr->iDataChunkType == DB_TEXTURE_CONTEXT2 ) {
			free( pTexContextHdr );
			fclose( pChunkFile );
			char* found = (char*)malloc( strlen(path)*4 ); //*4
			strcpy( found, path );
			return found;
		}

		free( pTexContextHdr );
		fclose( pChunkFile );
	}
	return FALSE;
}