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


