/*
   IDBSP.C
   (c) 1994 Ron Rossbach (ej070@cleveland.freenet.edu)

   This program is a mostly direct port of id's BSP compiler to MS-DOS.  In the
   words of John Carmack - "This code was written and evolved ... so it's
   probably not the cleanest thing in the world."

   Inquiries, comments, etc. are always welcome at the above address.

   Use and distribution of this code permitted according to the terms of the
   GNU General Public License.  Please give credit where credit is due (namely
   to id for releasing the code in the first place!)

   Please do not use this code to develop modified levels for the shareware
   version of DOOM.

   version 1.0.1 by Antony Suter <antony@werple.apana.org.au>
      these fixes and modifications (c) 1994 by Antony Suter.
 */

#include "idbsp.h"

WADFILE             wad_i;

void                BSPMain(FILE * pDWD, boolean overwrite);

int                 main(int argc, char **argv)
{
	char                szDWDName[81],
	                    szWADName[81];
	FILE               *pDWD;
	boolean             overwrite;

	printf("** IDBSP - iD's node builder for DOOM, version 1.0.1 **"
		"\nDOS port by Ron Rossbach (ej070@cleveland.freenet.edu)"
		"\nThis compilation by Antony Suter <antony@werple.apana.org.au>"
		"\n\nDOOM is a registered trademark of id Software, Inc."
		"\n\niD will not provide technical support for this program."
		"\n\nSee the accompanying README for terms of use, distribution, etc.");

	if (argc < 2 || argc > 3)
		{
		printf("\n\nUsage: \"idbsp dwdfile [wadfile]\""
			"\nDefault is TMP.WAD if wadfile not specified");
		Error("\nExiting....");
		}

	strcpy(szDWDName, argv[1]);

	if (argc == 3)
		strcpy(szWADName, argv[2]);
	else
		strcpy(szWADName, "tmp.wad");

	printf("\nDWD File: %s\nWAD File: %s\n", szDWDName, szWADName);

	if ((pDWD = fopen(szDWDName, "r")) == NULL)
		{
		printf("\nCannot open DWD file");
		return 0;
		}

	if ((wad_i.handle = fopen(szWADName, "rb+")) == NULL)
		{
		wad_i.handle = fopen(szWADName, "wb");
		if (wad_i.handle == NULL)
			Error("\nCannot open WAD file %s", szWADName);
		overwrite = true;
		}
	else
		{
		printf("\n\nWAD file %s already exists.  Overwrite? (y/n): ", szWADName);
		if (toupper(getchar()) == 'Y')
			{
			overwrite = true;
			fclose(wad_i.handle);
			wad_i.handle = fopen(szWADName, "wb");
			}
		else
			overwrite = false;
		}

	wad_i.pathname = (char *)SafeMalloc(strlen(szWADName) + 1);

	if (wad_i.pathname == NULL)
		{
		printf("\nERROR: wad_i.pathname: malloc");
		fclose(pDWD);
		fclose(wad_i.handle);
		return 0;
		}

	strcpy(wad_i.pathname, szWADName);

	BSPMain(pDWD, overwrite);

	fclose(pDWD);
	fclose(wad_i.handle);

	printf("\n");

	return 0;
}


void                BSPMain(FILE * pDWD, boolean overwrite)
{
	int                 version,
	                    episode,
	                    level;
	long                size;
	char                tmp[81],
	                    tmpname[81],
	                    dirname[9];

	printf("\noverwrite = %d\n", overwrite);
	if (overwrite)
		initNew();
	else
		initFromFile();

	if (!fscanf(pDWD, "WorldServer version %d\n", &version) || version != 4)
		Error("LoadDoomMap: not a version 4 doom map");

	printf("Loading version 4 doom map\n");

	while (fgets(tmp, 81, pDWD) != NULL)
		{
		if (sscanf(tmp, "level:E%dM%d", &episode, &level) == 2)
			{
			/* Handle Map Level */
			sprintf(tmp, "E%dM%d", episode, level);
			printf("\nBuilding Map Level %s", tmp);
			addName(tmp, 0, 0);
			printf("\nLoading DWD file.....");
			LoadDoomMap(pDWD);
			printf("\nBuilding BSP....");
			DrawMap();
			BuildBSP();
			printf("\nSaving WAD file.....");
			SaveDoomMap();
			SaveBlocks();
			/* Free storage */
			FreeGlobalStorage();
			}
		/* Handle other resources */
		if (sscanf(tmp, "%s :%d", dirname, &size) == 2)
			{
			strcpy(tmp, dirname);
			strcpy(tmpname, tmp);
			strcat(tmpname, ".lmp");
			printf("\nAdding resource %s", tmpname);
			AddFromFile(tmp, size, tmpname);
			}
		}

	printf("\nWriting directory.....");
	writeDirectory();

	return;
}

void                AddFromFile(char *resname, int size, char *fname)
{
	void               *p;
	FILE               *f;

	p = (void *)SafeMalloc(size);
	if ((f = fopen(fname, "rb")) == NULL)
		Error("\nAddFromFile: could not open file %s\n", fname);

	fread(p, size, 1, f);
	addName(resname, p, size);
	fclose(f);
	free(p);
}

void                FreeGlobalStorage(void)
{
	/* free(segstore_i->data); */
	free(linestore_i -> data);
	free(thingstore_i -> data);
	free(secstore_i -> data);
	free(mapvertexstore_i -> data);
	free(subsecstore_i -> data);
	free(maplinestore_i -> data);
	free(nodestore_i -> data);
	free(mapthingstore_i -> data);
	free(ldefstore_i -> data);
	free(sdefstore_i -> data);
/*  free(secdefstore_i->data); */
/*  free(bchains); */
/*  free(blines); */
/*  free(segstore_i); */
	free(linestore_i);
	free(thingstore_i);
	free(secstore_i);
	free(mapvertexstore_i);
	free(subsecstore_i);
	free(maplinestore_i);
	free(nodestore_i);
	free(mapthingstore_i);
	free(ldefstore_i);
	free(sdefstore_i);
/*  free(secdefstore_i); */
}

void                progress(void)
{
	char               *s = "/-\\|/-\\|";
	static unsigned char pcnt = 0;

	if ((pcnt & 15) == 0)
		{
		printf("%c\b", s[((pcnt) / 16) & 7]);
		fflush(stdout);
		}
	pcnt++;
}

void                Error(char *error,...)
{
	va_list             argptr;

	va_start(argptr, error);
	vprintf(error, argptr);
	va_end(argptr);
	printf("\n");
	exit(1);
}

void               *SafeMalloc(unsigned size)
{
	void               *ret = (void *)malloc(size);

	if (!ret)
		Error("\nSafeMalloc: Failed to allocate %u bytes", size);

	return ret;
}

void               *SafeCalloc(unsigned num, unsigned size)
{
	void               *ret = (void *)calloc(num, size);

	if (!ret)
		Error("\nSafeCalloc: Failed to allocate %u of %u bytes", num, size);

	return ret;
}

#ifdef __BIG_ENDIAN__
short               LittleShort(short l)
{
	byte                b1,
	                    b2;

	b1 = l & 255;
	b2 = (l >> 8) & 255;
	return (b1 << 8) + b2;
}

short               BigShort(short l)
{
	return l;
}

long                LittleLong(long l)
{
	byte                b1,
	                    b2,
	                    b3,
	                    b4;

	b1 = l & 255;
	b2 = (l >> 8) & 255;
	b3 = (l >> 16) & 255;
	b4 = (l >> 24) & 255;
	return ((long)b1 << 24) + ((long)b2 << 16) + ((long)b3 << 8) + b4;
}

long                BigLong(long l)
{
	return l;
}

#else

short               BigShort(short l)
{
	byte                b1,
	                    b2;

	b1 = l & 255;
	b2 = (l >> 8) & 255;
	return (b1 << 8) + b2;
}

short               LittleShort(short l)
{
	return l;
}

long                BigLong(long l)
{
	byte                b1,
	                    b2,
	                    b3,
	                    b4;

	b1 = l & 255;
	b2 = (l >> 8) & 255;
	b3 = (l >> 16) & 255;
	b4 = (l >> 24) & 255;
	return ((long)b1 << 24) + ((long)b2 << 16) + ((long)b3 << 8) + b4;
}

long                LittleLong(long l)
{
	return l;
}
#endif
