/***************************************************************************/
/*                                                                         */
/*                                                                         */
/* Raven 3D Engine                                                         */
/* Copyright (C) 1996 by Softdisk Publishing                               */
/*                                                                         */
/* Original Design:                                                        */
/*  John Carmack of id Software                                            */
/*                                                                         */
/* Enhancements by:                                                        */
/*  Robert Morgan of Channel 7............................Main Engine Code */
/*  Todd Lewis of Softdisk Publishing......Tools,Utilities,Special Effects */
/*  John Bianca of Softdisk Publishing..............Low-level Optimization */
/*  Carlos Hasan..........................................Music/Sound Code */
/*                                                                         */
/*                                                                         */
/***************************************************************************/

#include <malloc.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "d_global.h"
#include "d_disk.h"
#include "d_misc.h"
#include "protos.h"
#include "audio.h"

//pvmk - use posixy name for this
#include <strings.h>
#define stricmp strcasecmp


/**** VARIABLES ****/

fileinfo_t  fileinfo;     // the file header
lumpinfo_t* infotable;    // pointers into the cache file
void**      lumpmain;     // pointers to the lumps in main memory
int         cachehandle;  // handle of current file

extern boolean waiting;

/**** FUNCTIONS ****/

void CA_ReadFile(char* name, void* buffer, unsigned length)
/* generic read file */
{
    int handle;

    if ((handle = open(name, O_RDONLY /*| O_BINARY*/)) == -1)
        MS_Error("CA_ReadFile: Open failed on %s!", name);
    if (!read(handle, buffer, length))
    {
        close(handle);
        MS_Error("CA_LoadFile: Read failed on %s!", name);
    }
    close(handle);
}


void* CA_LoadFile(char* name)
/* generic load file */
{
    int      handle;
    unsigned length;
    void*    buffer;

    if ((handle = open(name, O_RDONLY /*| O_BINARY*/)) == -1)
        MS_Error("CA_LoadFile: Open failed on %s!", name);
    
    
    //length = filelength(handle);
    
    //PVMK - reimplement the above 
    length = lseek(handle, 0, SEEK_END);
    lseek(handle, 0, SEEK_SET);
    if(length > 1024*1024*1024)
	    MS_Error("CA_LoadFile: Bad length for %s!", name);
    
    if (!(buffer = malloc(length)))
        MS_Error("CA_LoadFile: Malloc failed for %s!", name);
    if (!read(handle, buffer, length))
    {
        close(handle);
        MS_Error("CA_LoadFile: Read failed on %s!", name);
    }
    close(handle);
    return buffer;
}


void CA_InitFile(char* filename)
/* initialize link file */
{
    unsigned size, i;

    if (cachehandle)  // already open, must shut down
    {
        close(cachehandle);
        free(infotable);
        for (i = 0; i < (unsigned)fileinfo.numlumps; i++)  // dump the lumps
            if (lumpmain[i])
                free(lumpmain[i]);
        free(lumpmain);
    }
    // load the header
    if ((cachehandle = open(filename, O_RDONLY /*| O_BINARY*/)) == -1)
        MS_Error("CA_InitFile: Can't open %s!", filename);
    read(cachehandle, (void*) &fileinfo, sizeof(fileinfo));
    // load the info list
    size      = fileinfo.infotablesize;
    infotable = malloc(size);
    lseek(cachehandle, fileinfo.infotableofs, SEEK_SET);
    read(cachehandle, (void*) infotable, size);
    size     = fileinfo.numlumps * sizeof(lumpmain[0]); //was "sizeof(int)". AAAAAH -betopp
    lumpmain = malloc(size);
    memset(lumpmain, 0, size);
}


int CA_CheckNamedNum(char* name)
/* returns number of lump if found
   returns -1 if name not found */
{
    int i, ofs;

    for (i = 0; i < fileinfo.numlumps; i++)
    {
        ofs = infotable[i].nameofs;
        if (!ofs)
            continue;
        if (stricmp(name, ((char*) infotable) + ofs) == 0)
            return i;
    }
    return -1;
}


int CA_GetNamedNum(char* name)
/* searches for lump with name
   returns -1 if not found */
{
    int i;

    i = CA_CheckNamedNum(name);
    if (i != -1)
        return i;
    MS_Error("CA_GetNamedNum: %s not found!", name);
    return -1;
}


void* CA_CacheLump(int lump)
/* returns pointer to lump
   caches lump in memory */
{
#ifdef PARMCHECK
    if (lump >= fileinfo.numlumps)
        MS_Error("CA_LumpPointer: %i>%i max lumps!", lump, fileinfo.numlumps);
#endif
    if (!lumpmain[lump])
    {
        // load the lump off disk
        if (!(lumpmain[lump] = malloc(infotable[lump].size)))
            MS_Error("CA_LumpPointer: malloc failure of lump %d, with size %d",
                     lump,
                     infotable[lump].size);
        lseek(cachehandle, infotable[lump].filepos, SEEK_SET);
        if (waiting)
            UpdateWait();
        if (MusicPresent && MusicPlaying)
            dPoll();  // have to poll a lot!
        read(cachehandle, lumpmain[lump], infotable[lump].size);
        if (waiting)
            UpdateWait();
        if (MusicPresent && MusicPlaying)
            dPoll();  // have to poll a lot!
    }
    return lumpmain[lump];
}


void CA_ReadLump(int lump, void* dest)
/* reads a lump into a buffer */
{
#ifdef PARMCHECK
    if (lump >= fileinfo.numlumps)
        MS_Error("CA_ReadLump: %i>%i max lumps!", lump, fileinfo.numlumps);
#endif
    lseek(cachehandle, infotable[lump].filepos, SEEK_SET);
    read(cachehandle, dest, infotable[lump].size);
}


void CA_FreeLump(unsigned lump)
/* frees a cached lump */
{
#ifdef PARMCHECK
    if (lump >= fileinfo.numlumps)
        MS_Error("CA_FreeLump: %i>%i max lumps!", lump, fileinfo.numlumps);
#endif
    if (!lumpmain[lump])
        return;
    free(lumpmain[lump]);
    lumpmain[lump] = NULL;
}


void CA_WriteLump(unsigned lump)
/* writes a lump to the link file */
{
#ifdef PARMCHECK
    if (lump >= fileinfo.numlumps)
        MS_Error("CA_WriteLump: %i>%i max lumps!", lump, fileinfo.numlumps);
    if (!lumpmain[lump])
        MS_Error("CA_WriteLump: %i not cached in!", lump);
#endif
    lseek(cachehandle, infotable[lump].filepos, SEEK_SET);
    write(cachehandle, lumpmain[lump], infotable[lump].size);
}
