#include "idbsp.h"
#include <ctype.h>

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

wadinfo_t;


typedef struct
	{
	int                 filepos;
	int                 size;
	char                name[8];
	}

lumpinfo_t;


/*
   =============================================================================
 */

/*
   ============
   =
   = initFromFile:
   =
   ============
 */

/* WADFILE *initFromFile(WADFILE *self,char const *path) */
void                initFromFile(void)
{
	wadinfo_t           wad;
	lumpinfo_t         *lumps;
	int                 i;

/*
   self->pathname = malloc(strlen(path)+1);
   strcpy (self->pathname, path);
   self->dirty = false;
   self->handle = open (self->pathname, O_RDWR, 0666);
   if (self->handle== -1)
   {
   /*              [self free]; */
/*    return nil; */
/*
   WadfileFree(self);
   return NULL;
   }
 */
/*
   read in the header
 */
/*              read (self->handle, &wad, sizeof(wad)); */
	fread(&wad, sizeof(wad), 1, wad_i.handle);
	if (strncmp(wad.identification, "PWAD", 4))
		{
/*
   close (self->handle);
   WadfileFree(self);
   return NULL;
 */
		Error("\ninitFromFile: specified WAD is not a PWAD");
		}
/*
   wad.numlumps = LONG (wad.numlumps);
   wad.infotableofs = LONG (wad.infotableofs);
 */
/*
   read in the lumpinfo
 */
/*              lseek (self->handle, wad.infotableofs, SEEK_SET); */
	fseek(wad_i.handle, wad.infotableofs, SEEK_SET);
/*
   info = [[Storage alloc] initCount: wad.numlumps elementSize: sizeof(lumpinfo_t) description: ""];
   lumps = [info elementAt: 0];
 */
	wad_i.info = (STORAGE *) SafeMalloc(sizeof(STORAGE));
	wad_i.info -> data = (lumpinfo_t *) SafeCalloc(wad.numlumps, sizeof(lumpinfo_t));
	wad_i.info -> count = wad.numlumps;
	wad_i.info -> size = sizeof(lumpinfo_t);
	lumps = wad_i.info -> data;

/*              read (self->handle, lumps, wad.numlumps*sizeof(lumpinfo_t)); */
	fread(lumps, sizeof(lumpinfo_t), wad.numlumps, wad_i.handle);
/*
   for (i=0 ; i<wad.numlumps ; i++, lumps++)
   {
   lumps->filepos = LONG (lumps->filepos);
   lumps->size = LONG (lumps->size);
   }
 */
	return;
}


/*
   ============
   =
   = initNew:
   =
   ============
 */

void                initNew(void)
{
	wadinfo_t           wad;

/*
   self->pathname = malloc(strlen(path)+1);
   strcpy (self->pathname, path);
 */

/*      info = [[Storage alloc] initCount: 0 elementSize: sizeof(lumpinfo_t) description: ""]; */
	wad_i.info = (STORAGE *) SafeMalloc(sizeof(STORAGE));
	wad_i.info -> data = (lumpinfo_t *) SafeMalloc(sizeof(lumpinfo_t));
	wad_i.info -> size = sizeof(lumpinfo_t);
	wad_i.info -> count = 0;

	wad_i.dirty = true;
/*
   self->handle = open (self->pathname, O_CREAT | O_TRUNC | O_RDWR, 0666);
   if (self->handle== -1)
   return NULL;
 */
/* leave space for wad header */
/*      write (self->handle, &wad, sizeof(wad)); */
	fwrite(&wad, sizeof(wad), 1, wad_i.handle);

	return;
}

/* WADFILE *WadfileClose(WADFILE *self) */
void                WadfileClose(void)
{
/* close (self->handle); */
	fclose(wad_i.handle);
	return;
}

/* void WadfileFree(WADFILE *self) */
void                WadfileFree(void)
{
/*
   close (handle);
   [info free];
   free (self->pathname);
   return [super free];
 */
	fclose(wad_i.handle);
	free(wad_i.info -> data);
	free(wad_i.info);
	free(wad_i.pathname);
}

/*
   =============================================================================
 */

/* int numLumps(WADFILE *self) */
int                 numLumps(void)
{
/*      return [info count]; */
	return wad_i.info -> count;
}

/* int lumpsize(WADFILE *self,int lump) */
int                 lumpsize(int lump)
{
	lumpinfo_t         *inf;

/*
   inf = [info elementAt: lump];
   return inf->size;
 */
	inf = wad_i.info -> data;
	inf += lump;
	return inf -> size;
}

/* int lumpstart(WADFILE *self,int lump) */
int                 lumpstart(int lump)
{
	lumpinfo_t         *inf;

/*
   inf = [info elementAt: lump];
   return inf->filepos;
 */
	inf = wad_i.info -> data;
	inf += lump;
	return inf -> filepos;
}

/* char const *lumpname(WADFILE *self,int lump) */
char const         *lumpname(int lump)
{
	lumpinfo_t         *inf;

/*
   inf = [info elementAt: lump];
   return inf->name;
 */
	inf = wad_i.info -> data;
	inf += lump;
	return inf -> name;
}

/*
   ================
   =
   = lumpNamed:
   =
   ================
 */

/*int lumpNamed(WADFILE *self,char const *name) */
int                 lumpNamed(char const *name)
{
	lumpinfo_t         *inf;
	int                 i,
	                    count;
	char                name8[9];
	int                 v1,
	                    v2;

/* make the name into two integers for easy compares */

	memset(name8, 0, 9);
	if (strlen(name) < 9)
		strncpy(name8, name, 9);
	for (i = 0; i < 9; i++)
		name8[i] = toupper(name8[i]);  /* case insensitive */

	v1 = *(int *)name8;
	v2 = *(int *)&name8[4];


/* scan backwards so patch lump files take precedence */

/*      count = [info count]; */
	count = wad_i.info -> count;
	for (i = count - 1; i >= 0; i--)
		{
/*              inf = [info elementAt: i]; */
		inf = wad_i.info -> data;
		inf += i;
		if (*(int *)inf -> name == v1 && *(int *)&inf -> name[4] == v2)
			return i;
		}
	return -1;
}

/*
   ================
   =
   = loadLump:
   =
   ================
 */

/* void *loadLump(WADFILE *self,int lump) */
void               *loadLump(int lump)
{
	lumpinfo_t         *inf;
	byte               *buf;

/*
   inf = [info elementAt: lump];
   buf = malloc (inf->size);

   lseek (handle, inf->filepos, L_SET);
   read (handle, buf, inf->size);
 */
	inf = wad_i.info -> data;
	inf += lump;
	buf = (byte *) malloc(inf -> size);
/*
   lseek(self->handle, inf->filepos, SEEK_SET);
   read(self->handle, buf, inf->size);
 */
	fseek(wad_i.handle, inf -> filepos, SEEK_SET);
	fread(buf, inf -> size, 1, wad_i.handle);

	return buf;
}

/* void *loadLumpNamed(WADFILE *self,char const *name) */
void               *loadLumpNamed(char const *name)
{
/*      return [self loadLump:[self lumpNamed: name]]; */
	return loadLump(lumpNamed(name));
}

/*
   ============================================================================
 */

/*
   ================
   =
   = addName:data:size:
   =
   ================
 */

/* WADFILE *addName(WADFILE *self,char const *name, void *data, int size) */
void                addName(char const *name, void *data, int size)
{
	int                 i;
	lumpinfo_t         *newlump;

/*
   if (wad_i.info->count > 0)
   {
   wad_i.info->count += 1;
   wad_i.info->data = (lumpinfo_t *)realloc(wad_i.info->data,
   (wad_i.info->count + 1) * sizeof(lumpinfo_t));
   }
 */

	newlump = (lumpinfo_t *) wad_i.info -> data + wad_i.info -> count;

	wad_i.dirty = true;
	memset(newlump -> name, 0, sizeof(newlump -> name));
	strncpy(newlump -> name, name, 8);
	for (i = 0; i < 8; i++)
		newlump -> name[i] = toupper(newlump -> name[i]);
/*      newlump->filepos = lseek(self->handle,0, L_XTND); */
/*      newlump->filepos = lseek(self->handle,0,SEEK_END); */
	fseek(wad_i.handle, 0, SEEK_END);
	newlump -> filepos = ftell(wad_i.handle);
	newlump -> size = size;

/*      [info addElement: &new]; */

/*      write (self->handle, data, size); */
	fwrite(data, size, 1, wad_i.handle);

	wad_i.info -> count += 1;
	wad_i.info -> data = (lumpinfo_t *) realloc(wad_i.info -> data,
		(wad_i.info -> count + 1) * sizeof(lumpinfo_t));

	return;
}


/*
   ================
   =
   = writeDirectory:
   =
   char            identification[4];              // should be IWAD
   int             numlumps;
   int             infotableofs;
   ================
 */

/* WADFILE *writeDirectory(WADFILE *self) */
void                writeDirectory(void)
{
	wadinfo_t           wad;
	int                 i,
	                    count;
	lumpinfo_t         *inf;

/*
   write the directory
 */
/*
   count = [info count];
   inf = [info elementAt:0];
 */
	count = wad_i.info -> count;
	inf = wad_i.info -> data;
/*
   for (i=0 ; i<count ; i++)
   {
   inf[i].filepos = LONG (inf[i].filepos);
   inf[i].size = LONG (inf[i].size);
   }
 */
/*      wad.infotableofs = LONG (lseek(self->handle,0, L_XTND)); */
/*      wad.infotableofs = LONG(lseek(self->handle,0,SEEK_END)); */
	fseek(wad_i.handle, 0, SEEK_END);
	wad.infotableofs = ftell(wad_i.handle);

/*      write (self->handle, inf, count*sizeof(lumpinfo_t)); */
	fwrite(inf, sizeof(lumpinfo_t), count, wad_i.handle);
/*
   for (i=0 ; i<count ; i++)
   {
   inf[i].filepos = LONG (inf[i].filepos);
   inf[i].size = LONG (inf[i].size);
   }
 */

/*
   write the header
 */
	strncpy(wad.identification, "PWAD", 4);
/*      wad.numlumps = LONG ([info count]); */
	wad.numlumps = wad_i.info -> count;
/*
   lseek (self->handle, 0, SEEK_SET);
   write (self->handle, &wad, sizeof(wad));
 */
	fseek(wad_i.handle, 0, SEEK_SET);
	fwrite(&wad, sizeof(wad), 1, wad_i.handle);

	return;
}
