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

typedef unsigned char byte;
typedef char sprName[8];
#define FBIN	O_RDONLY | O_BINARY

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;

typedef struct
{
	bool		rotate;		/* if false use 0 for any position */
	int			lump[8];	/* lump to use for view angles 0-7 */
	byte		flip[8];	/* flip (1 = flip) to use for view angles 0-7 */
} spriteframe_t;

spriteframe_t sprDef;

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

sprTable_t sprTab;

lumpinfo_t* lump;

typedef struct
{
	short x;
	short y;
	short ox;
	short oy;
	short *ptr;
}	spriteInfo_t;

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;
}

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

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

void ExtractFileBase (char *path, char *dest)
{
	char	*src;
	int		length;

	src = path + strlen(path) - 1;
	while (src != path && *(src-1) != '\\' && *(src-1) != '/')
		src--;

	memset (dest,0,8);
	length = 0;
	while (*src && *src != '.')
	{
		*dest++ = toupper((int)*src++);
	}
}

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

#define	BIGSHORT(x) ShortSwap(x)

union
{
	unsigned short bleh;
	byte swapper[2];
} hack_u;

//types of input: iwad or sprite image(wip)
int main(int argc, char**argv)
{

	if(!argv[1])
		return 0;

	if(!argv[2])
	{
		printf("Please Specify an option\n-s: Generates SPRITES data lump\n-i: Creates a sprite lump out of image file (argument 3)\n");
		exit(1);
	}

	if(!strcmp(argv[2], "-s"))
	{
		int handle;
		sprName* spr;
		char path[256];
		int handle2;
		int size, i, j;
		byte chr = 0;
		int start = '0';
		char* base = argv[0];
		char name[9];
		FILE* fp;
		FILE* dat;

		KillFileName(base);

		sprintf(path, "%s/SPRLIST.lmp", base);

		if(!argv[3])
		{
			printf("Error: %s not found\n", path);
			exit(1);
		}

		//read wad
		handle = open(argv[1], FBIN);
		lseek(handle, 0, SEEK_SET);
		read(handle, &wad, sizeof(wadinfo_t));
		if(strncmp(wad.identification, "IWAD", 4)
			&& strncmp(wad.identification, "PWAD", 4))
		{
			printf("Error: Not a wad file\n");
			exit(1);
		}

		sprintf(path, "%s/SPRDEF.lmp", base);
		fp = fopen(path, "wb");
		sprintf(path, "%s/SPRTABLE.dat", base);
		dat = fopen(path, "wb");

		lseek(handle, wad.infotableofs, SEEK_SET);
		lump = (lumpinfo_t*)malloc(sizeof(lumpinfo_t)*wad.numlumps);

		read(handle, lump, sizeof(lumpinfo_t)*wad.numlumps);

		//read sprite list
		handle2 = open(argv[3], FBIN);
		lseek(handle2, 0, SEEK_END);

		size = tell(handle2);
		lseek(handle2, 0, SEEK_SET);

		spr = (sprName*)malloc(sizeof(sprName) * (size / sizeof(sprName)));

		read(handle2, spr, sizeof(sprName) * (size / sizeof(sprName)));
		close(handle2);

		for(i = size / sizeof(sprName) - 1; i >= 0; i--)
		{
			memset(&sprDef.lump, 0, sizeof(sprDef.lump));
			memset(&sprDef.flip, 0, sizeof(sprDef.flip));
			sprDef.rotate = false;

			for(j = 0; j < wad.numlumps; j++)
			{
				if(lump[j].name[0] == spr[i][0]
					&& lump[j].name[1] == spr[i][1]
					&& lump[j].name[2] == spr[i][2]
					&& lump[j].name[3] == spr[i][3])
				{
					if(lump[j].name[4])
					{
						if(!lump[j].name[5])
						{
							continue;
						}

						if((lump[j].name[5] < 48 || lump[j].name[5] > 56))
						{
							continue;
						}
						sprTab.num++;

						if(lump[j].name[5] == '0')
						{
							strncpy(name, lump[j].name, 8);
							name[8] = '\0';
							printf("Inspecting: %s\n", name);

							sprDef.lump[0] =
							sprDef.lump[1] =
							sprDef.lump[2] =
							sprDef.lump[3] = 
							sprDef.lump[4] =
							sprDef.lump[5] = 
							sprDef.lump[6] = 
							sprDef.lump[7] = W_GetNumForName(lump[j].name);
							sprDef.rotate = false;
							sprDef.flip[0] =
							sprDef.flip[1] =
							sprDef.flip[2] =
							sprDef.flip[3] =
							sprDef.flip[4] =
							sprDef.flip[5] =
							sprDef.flip[6] =
							sprDef.flip[7] = 0;
						}
						else
						{
							chr = lump[j].name[4];
							sprDef.rotate = true;
							do
							{
								strncpy(name, lump[j].name, 8);
								name[8] = '\0';
								printf("Inspecting: %s\n", name);
								sprDef.lump[lump[j].name[5] - start - 1] = 
									W_GetNumForName(lump[j].name);
								sprDef.flip[lump[j].name[5] - start - 1] =
									0;
								if(lump[j].name[6])
								{
									if(lump[j].name[6] != chr)
									{
										printf("Error: Invalid sprite %s found\n", name);
										exit(1);
									}
									if(!lump[j].name[7])
									{
										printf("Error: Invalid sprite %s found\n", name);
										exit(1);
									}
									sprDef.lump[lump[j].name[7] - start - 1] = 
										W_GetNumForName(lump[j].name);
									sprDef.flip[lump[j].name[7] - start - 1] =
										1;

								}
							} while(lump[j+=2].name[4] == chr);
							j-=2;
						}
						fwrite(&sprDef, sizeof(spriteframe_t), 1, fp);
					}
				}
			}
			fwrite(&sprTab, sizeof(sprTable_t), 1, dat);
			sprTab.pos += sprTab.num * sizeof(spriteframe_t);
			sprTab.num = 0;
		}

		free(spr);
		fclose(fp);
		fclose(dat);
		printf("Written files to %s\n", base);
		close(handle);
	}

	else if(!strcmp(argv[2], "-i"))
	{
		spriteInfo_t sprInfo;
		char* base = argv[0];
		int handle = open(argv[1], FBIN);
		int i, j, extra = 0;
		char path[256];
		char name[8];
		short pixelOf = 0;
		FILE* fp;
		FILE* fData;
		byte* buffer;
		KillFileName(base);
		ExtractFileBase(argv[1], name);

		sprintf(path, "%s/%s.lmp", base, name);

		fp = fopen(path, "wb");

		sprintf(path, "%s/%s_data.lmp", base, name);

		fData = fopen(path, "wb");

		if(!argv[3])
		{
			printf("Specify Width!\n");
			exit(1);
		}
		if(!argv[4])
		{
			printf("Specify Height!\n");
			exit(1);
		}
		if(!argv[5])
		{
			printf("Specify X Offset!\n");
			exit(1);
		}
		if(!argv[6])
		{
			printf("Specify Y Offset!\n");
			exit(1);
		}

		sprInfo.x = BIGSHORT(atoi(argv[3]));
		sprInfo.y = BIGSHORT(atoi(argv[4]));
		sprInfo.ox = BIGSHORT(atoi(argv[5]));
		sprInfo.oy = BIGSHORT(atoi(argv[6]));

		extra = BIGSHORT(sprInfo.x);

		if(extra % 2 != 0)
		{
			while(extra % 2 != 0)
				extra++;
		}

		lseek(handle, 0, SEEK_END);
		int size = tell(handle);
		lseek(handle, 0, SEEK_SET);
		buffer = (byte*)malloc(sizeof(byte)*size);
		read(handle, buffer, size);
		sprInfo.ptr = (short*)malloc(sizeof(short)*extra);
		memset(sprInfo.ptr, 0xCD, sizeof(short)*extra);

		close(handle);

		byte mask = 0, pixels = 0;
		short offset = 0;
		unsigned int null = 0xFFFFFFFF;
		bool foundPixel = false;
		for(i = 0; i < BIGSHORT(sprInfo.x); i++)
		{
			for(j = BIGSHORT(sprInfo.y) * i; j < BIGSHORT(sprInfo.y) * (i+1); j++)
			{
				if(buffer[j] != 0xFB)
				{
					if(foundPixel == false)
						fwrite(&mask, sizeof(byte), 1, fp);
					foundPixel = true;
					fwrite(&buffer[j], sizeof(byte), 1, fData);
					pixels++;
					offset++;
				}
				else if((buffer[j] == 0xFB && foundPixel == true)
					|| j == BIGSHORT(sprInfo.y) * (i+1))
				{
					fwrite(&pixels, sizeof(byte), 1, fp);
					foundPixel = false;
					fwrite(&hack_u.swapper[1], sizeof(byte), 1, fp);
					fwrite(&hack_u.swapper[0], sizeof(byte), 1, fp);
					hack_u.bleh = offset;
					pixels = 0;
				}
				mask++;
			}
			if(foundPixel == true)
			{
				fwrite(&pixels, sizeof(byte), 1, fp);
				foundPixel = false;
				fwrite(&hack_u.swapper[1], sizeof(byte), 1, fp);
				fwrite(&hack_u.swapper[0], sizeof(byte), 1, fp);
				pixels = 0;
			}
			mask = 0;
			fwrite(&null, sizeof(unsigned int), 1, fp);
		}

		fclose(fp);
		fclose(fData);
		free(buffer);

		unsigned int *iBuf;

		sprintf(path, "%s/%s.lmp", base, name);

		handle = open(path, FBIN);
		lseek(handle, 0, SEEK_END);
		size = tell(handle);
		lseek(handle, 0, SEEK_SET);

		iBuf = (unsigned int*)malloc(sizeof(unsigned int)*size / sizeof(unsigned int));

		read(handle, iBuf, sizeof(unsigned int)*size / sizeof(unsigned int));

		size = size / sizeof(unsigned int);
		j = 1;
		int k = 0;
		sprInfo.ptr[0] = BIGSHORT((8 + sizeof(short)*extra));
		for(i = 0; i < size; i++)
		{
			k+=4;
			if((iBuf[i]) == 0xFFFFFFFF)
			{
				sprInfo.ptr[j++] = BIGSHORT(((8 + sizeof(short)*extra) + k));
			}
		}

		close(handle);
		fp = fopen(path, "wb");
		fwrite(&sprInfo.x, sizeof(short), 1, fp);
		fwrite(&sprInfo.y, sizeof(short), 1, fp);
		fwrite(&sprInfo.ox, sizeof(short), 1, fp);
		fwrite(&sprInfo.oy, sizeof(short), 1, fp);
		fwrite(sprInfo.ptr, sizeof(short)*extra, 1, fp);
		fwrite(iBuf, sizeof(unsigned int)*size, 1, fp);
		free(sprInfo.ptr);
		free(iBuf);
		fclose(fp);
		printf("Written Sprite files to %s\n", argv[0]);
	}

	else
	{
		printf("Error: Invalid Option %s\n", argv[2]);
		exit(1);
	}

	return 1;
}