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

short ShortSwap (short dat)
{
	return (((unsigned short)dat<<8) + ((unsigned short)dat>>8))&0xffff;
}

#define	BIGSHORT(x) ShortSwap(x)

typedef unsigned char byte;
typedef struct
{
	char		identification[4];		/* should be IWAD */
	int			numlumps;
	int			infotableofs;
} wadinfo_t;

wadinfo_t* wad;

typedef struct
{
	int			filepos;					/* also texture_t * for comp lumps */
	int			size;
	char		name[8];
} lumpinfo_t;

lumpinfo_t* lump;

union
{
	unsigned int fileSize;
	byte fSizeChunk[4];
}	ptr_u;

union
{
	unsigned int leafs;
	byte leafChunk[4];
}	leafs_u;

long LongSwap (long dat)
{
	unsigned    a,b,c,d;
	
	a = (dat>>24)&0xff;
	b = (dat>>16)&0xff;
	c = (dat>>8)&0xff;
	d = dat&0xff;
	return (d<<24)+(c<<16)+(b<<8)+a;
}

typedef struct
{
	int num;
	int pos;
}	sprTable_t;

sprTable_t* sprTab;

#define	LITTLELONG(x) LongSwap(x)

void KillFileName(char *name)
{
	char *search;

	search = name+strlen(name)-1;
	while(search != name)
	{
		if(*search == 92 || *search == 47)
		{
			search++;
			*search = '\0';
			return;
		}
		search--;
	}
}

static int W_GetNumForName(char* name)
{
	int i = 0;
	char fillName[9];
	strncpy(fillName, name, 8);
	fillName[8] = 0;
	for(i = 0; i < wad->numlumps; i++)
	{
		if(!strncmp(fillName, lump[i].name, 8))
		{
			return i;
		}
	}
	return -1;
}

int main(int argc, char**argv)
{
	int handle = open(argv[1],O_RDONLY | O_BINARY);
	unsigned char* buffer;
	unsigned char* buffer2;
	unsigned char* data;
	int size, size2, i, size3;
	char filePath[256];
	char mapName[8];
	char* base = argv[0];
	FILE*f;
	KillFileName(base);

	if(!argv[1])
	{
		printf("GBADLINK use: <rom file> <iwad file>\n");
		printf("Error: No doom gba rom found\n");
	}
	if(!argv[2])
	{
		printf("Error: No gba doom iwad found\n");
	}

	sprintf(filePath, "%s/GBADOOM.GBA", base);
	f = fopen(filePath, "wb");

	lseek(handle, 0, SEEK_END);
	size3 = tell(handle);

	buffer = (unsigned char*)malloc(size3);

	lseek(handle, 0, SEEK_SET);
	read(handle, buffer, size3);

	close(handle);

	//set wad pointer
	ptr_u.fileSize = size3 * 17;

	buffer[0x4E38] = ptr_u.fSizeChunk[0];
	buffer[0x4E39] = ptr_u.fSizeChunk[1];
	buffer[0x4E3A] = ptr_u.fSizeChunk[2];
	buffer[0x4E3B] = ptr_u.fSizeChunk[3];

	handle = open(argv[2],O_RDONLY | O_BINARY);
	lseek(handle, 0, SEEK_END);
	size = tell(handle);

	buffer2 = (unsigned char*)malloc(size);
	lseek(handle, 0, SEEK_SET);
	read(handle, buffer2, size);

	wad = (wadinfo_t*)buffer2;
	wad->identification[0] = 'S';
	lump = (lumpinfo_t*)&buffer2[wad->infotableofs];


	for(i = 0; i < wad->numlumps; i++)
	{
		lump[i].filepos = LITTLELONG(lump[i].filepos);
		lump[i].size = LITTLELONG(lump[i].size);
	}

	lseek(handle, 12, SEEK_END);
	size = tell(handle);

	data = (unsigned char*)malloc(wad->infotableofs - sizeof(wadinfo_t));
	lseek(handle, 12, SEEK_SET);
	read(handle, data, wad->infotableofs - sizeof(wadinfo_t));

	//handle Custom Sprite Table
	if(W_GetNumForName("SPRTABLE") != -1)
	{
		if(W_GetNumForName("SPRTABLE") != 0)
		{
			printf("Warning: Lump SPRTABLE needs to be the first index in the wad\n");
		}
		sprTab = (sprTable_t*)(data + LITTLELONG(lump[W_GetNumForName("SPRTABLE")].filepos) - 12);
		for(i = 0; i < (LITTLELONG(lump[W_GetNumForName("SPRTABLE")].size) / 8); i++)
		{
			sprTab[i].pos += (ptr_u.fileSize
				+ (LITTLELONG(lump[W_GetNumForName("SPRDEF")].filepos)));
		}
		data = (unsigned char*)sprTab;
		ptr_u.fileSize = ptr_u.fileSize +
			LITTLELONG(lump[W_GetNumForName("SPRTABLE")].filepos);

		buffer[0x14658] = buffer[0x14834] =
			 buffer[0x1F30] = ptr_u.fSizeChunk[0];
		buffer[0x14659] = buffer[0x14835] =
			 buffer[0x1F31] =  ptr_u.fSizeChunk[1];
		buffer[0x1465A] = buffer[0x14836] =
			 buffer[0x1F32] =  ptr_u.fSizeChunk[2];
		buffer[0x1465B] = buffer[0x14837] =
			 buffer[0x1F33] =  ptr_u.fSizeChunk[3];
	}
	close(handle);

	//handle Custom Map 'Leafs' data
	for(i = 1; i < 25; i++)
	{
		sprintf(mapName, "MAP%02d", i);
		if(W_GetNumForName(mapName) != -1)
		{
			if(!strncmp(lump[W_GetNumForName(mapName) + 11].name, "LEAFS", 8))
			{
				leafs_u.leafs = (ptr_u.fileSize
				+ (LITTLELONG(
				lump[W_GetNumForName(lump[W_GetNumForName(mapName) + 
				11].name)].filepos)) - 12);

				buffer[0x6C76D0 + ((i-1) * 4)] = leafs_u.leafChunk[0];
				buffer[0x6C76D1 + ((i-1) * 4)] = leafs_u.leafChunk[1];
				buffer[0x6C76D2 + ((i-1) * 4)] = leafs_u.leafChunk[2];
				buffer[0x6C76D3 + ((i-1) * 4)] = leafs_u.leafChunk[3];
			}
		}
	}

	size2 = wad->numlumps;
	wad->infotableofs = LITTLELONG(wad->infotableofs);
	wad->numlumps = LITTLELONG(wad->numlumps);

	fwrite(buffer, size3, 1, f);
	fwrite(wad, sizeof(wadinfo_t), 1, f);
	fwrite(data, LITTLELONG(wad->infotableofs) - sizeof(wadinfo_t), 1, f);
	fwrite(lump, sizeof(lumpinfo_t) * size2, 1, f);

	fclose(f);
	free(buffer);
	free(buffer2);
	free(data);

	return 1;
}

