//---------------------------------------------------------------------------
// A kind of file system module, for the PSX-CD
// June 7th 1996, Geoffroy Audy
//---------------------------------------------------------------------------

#include <sys\types.h>
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
#include <rand.h>
#include <libcd.h>
#include <memory.h>
#include "..\include\compile.h"
#include "..\include\db.h"
void SetDumpMessage (DoubleBuffer *db);
void DumpMessage (char *message);

#define TARGETPC

#include <libsn.h>

//-------------------------------------
// Data for the file management
//-------------------------------------
#define READ_BUF_SIZE  20 * 2048        //
#define CD_SECTOR_SIZE 2048             //
int     NbrBytes;                       // Number of bytes read in the buffer
int     BufPtr;                         // Where we are in the buffer
int     FilePtr;                        // Where we are in the file
int     FileHandle;                     // File handle for PC read
CdlFILE File_loc;                       // CD file structure
CdlFILE Dummy_loc;                      //
char    *FName = NULL;                  //
u_char  *DataBuffer;                    // The buffer itself

//-------------------------------------
// Initialize some shit for the file
// system
//-------------------------------------
void InitFileSystem (u_long *memptr)
{
   #ifdef TARGETCD
      if (*memptr & 3)
         *memptr = (*memptr + 4) & 0xFFFFFFFC;

      DataBuffer = (u_char *)*memptr;
      *memptr = *memptr + READ_BUF_SIZE;
   #endif
}

//-------------------------------------
// Open a file
//-------------------------------------
int OpenFile (char filename[])
{
   int timeout;
   int retry;
   u_char  param[4], result[16];
   CdlFILE *ret;

   DumpMessage (filename);

   //----------------------------------
   #ifdef TARGETPC
      FName = filename;
      if ((FileHandle = PCopen (filename, 0, 0)) == -1)
         return (-1);

      return (0);
   #endif

   //----------------------------------
   #ifdef TARGETCD
      char    cdfilename[80];
      int k;
      for (k = 0; filename[k] != 0; k++)
         cdfilename[k] = filename[k];
      cdfilename[k] = ';';
      cdfilename[k + 1] = '1';
      cdfilename[k + 2] = 0;

      File_loc.size = 0;

      FName = filename;

      retry = 20;                       // Try to find the file on the CD...
      do
      {
         ret = CdSearchFile (&File_loc, cdfilename);
      } while ((ret == NULL) && (--retry != 0));

      memcpy ((char *)&Dummy_loc, (char *)&File_loc, sizeof (CdlFILE));

      BufPtr = 0;
      NbrBytes = 0;
      FilePtr = 0;

      return (0);
   #endif

   return (-1);
}

//-------------------------------------
// Close a file
//-------------------------------------
int CloseFile (void)
{
   u_char  param[4], result[16];
   int timeout;

   #ifdef TARGETPC
      if (PCclose (FileHandle) == -1)
         return (-1);

      return (0);
   #endif

   #ifdef TARGETCD
      BufPtr = 0;
      NbrBytes = 0;
      FilePtr = 0;

      return (0);
   #endif

   return (-1);
}

//-------------------------------------
// Print some informations about the
// file system
//-------------------------------------
void FileSysDumpData (void)
{
   FntPrint ("Last opened file: ");
   if (FName == NULL)
      FntPrint ("None.\n");
   else
      FntPrint ("%s\n", FName);
   FntPrint ("NbrBytes: %d\n", NbrBytes);
   FntPrint ("BufPtr: %d\n", BufPtr);
   FntPrint ("FilePtr: %d\n", FilePtr);
   FntPrint ("FileSize: %d\n", File_loc.size);
}

//-------------------------------------
// Returns the file size
// Return 0 if no file
//-------------------------------------
int FileSize ()
{
   #ifdef TARGETPC
      int marde, retour;

      marde = PClseek (FileHandle, 0, 1);   // Keep the actual offset

      retour = PClseek (FileHandle, 0, 2);  // Check the file size
      PClseek (FileHandle, marde, 0);       // Go back to where it was

      return (retour);
   #endif

   #ifdef TARGETCD
      return (File_loc.size);
   #endif

   return (0);
}

//-------------------------------------
// Read data from a file to a buffer
// in memory
//-------------------------------------
int ReadFile (char *memptr, u_int readbyte)
{
   u_char  param[4], result[16];
   int ix;
   int nbrbyteread;                     // How many bytes has been read

   //----------------------------------
   #ifdef TARGETPC
      return (PCread (FileHandle, (char *)memptr, readbyte));
   #endif

   //----------------------------------
   #ifdef TARGETCD
      // Don't read more data than there is in the file...
      if (readbyte <= 0)
         return (0);
      if ((readbyte - (NbrBytes - BufPtr) + FilePtr) >= File_loc.size)
         readbyte = (File_loc.size - FilePtr) + (NbrBytes - BufPtr);

      nbrbyteread = readbyte;

      while (readbyte)                   // Read as much data as we need
      {
         // Do we need to read from the CD ?
         if ((NbrBytes - BufPtr) <= 0)
         {
            // What about reading directly to the destination buffer ?
            // By the way, to do that memptr needs to be at a 4-byte boundary
            if ((readbyte >= CD_SECTOR_SIZE) && (!((u_long)memptr & 3)))
            {                           
               param[0] = CdlModeRept | CdlModeSpeed;
               CdControlB (CdlSetmode, param, 0);

               // Seek the CD to a good place in the file
               CdIntToPos (CdPosToInt (&File_loc.pos) +
                           (FilePtr / CD_SECTOR_SIZE), &Dummy_loc.pos);
               CdControlB (CdlSetloc, (u_char *)&Dummy_loc, 0);

               CdRead (readbyte / CD_SECTOR_SIZE, (u_long *)memptr, 0);
               if (CdReadSync (0, result) != 0)
                  return (-1);

               int mardeux = readbyte & ~(CD_SECTOR_SIZE - 1);
               FilePtr += mardeux;
               memptr += mardeux;
               readbyte -= mardeux;
            }

            // Fill the buffer, if we need to
            if (readbyte > 0)
            {
               param[0] = CdlModeRept | CdlModeSpeed;
               CdControlB (CdlSetmode, param, 0);

               // Seek the CD to a good place in the file
               CdIntToPos (CdPosToInt (&File_loc.pos) +
                           (FilePtr / CD_SECTOR_SIZE), &Dummy_loc.pos);
               CdControlB (CdlSetloc, (u_char *)&Dummy_loc, 0);

               // Don't read more into the buffer than there is in the file...
               if ((FilePtr + READ_BUF_SIZE) >= File_loc.size)
                  ix = ((File_loc.size - FilePtr) + (CD_SECTOR_SIZE - 1)) &
                       ~(CD_SECTOR_SIZE - 1);
               else
                  ix = READ_BUF_SIZE;

               CdRead (ix / CD_SECTOR_SIZE, (u_long *)DataBuffer, 0);
               if (CdReadSync (0, result) != 0)
                  return (-1);

               BufPtr = 0;
               NbrBytes = ix;
               FilePtr += ix;
            }
         }

         // Transfer data from the buffer to the destination in RAM
         if (readbyte < (NbrBytes - BufPtr))
            ix = readbyte;
         else
            ix = NbrBytes - BufPtr;
         memcpy ((u_char *)memptr, &(DataBuffer[BufPtr]), ix);

         memptr += ix;
         BufPtr += ix;
         readbyte -= ix;
      }

      return (nbrbyteread);
   #endif

   return (-1);
}
