#include "palmdep.h"
#include "endianutils.h"
#include "pnobridge.h"
#include "StarterRsc.h"

//static char chdir [ 128 ] = ""; // add to VFSPATH for path

/*int fchdir ( char *path ) {
  StrCopy ( chdir, path );
  return ( 0 );
}*/

FILE *fopen ( const char *filename, char *mode ) {
//FILE *fopen ( char *filename, char *mode ) {
  UInt32 voliter = palm_vfs_iter();
  char path [ 260 ];
  Err err;  
  FILE *myfile = (FILE *)malloc ( sizeof(FILE) );
  if (!myfile)
  {
  	DEBUGS("Out of memory fopen");
  	return NULL;
  }

#ifdef DEBUGFILE
  DEBUGS( __FUNCTION__);
#endif

  StrCopy ( myfile -> filename, filename );
  myfile -> tail = 0;
  myfile -> ref = 0;
  myfile -> size = 0;

  if ( StrChr ( mode, 'r' ) && StrChr ( mode, 'w' ) ) {
    myfile -> bufferp = 0; // no buffering on read+write files
    //DEBUGS("Internal eror: Game fopen() is confusing");
  } else if ( StrChr ( mode, 'w' ) ) {
    myfile -> bufferp = 2; // buffering single direction stream
  } else {
    myfile -> bufferp = 1; // buffering single direction stream
  }

  // looks like general purpose work, so don't screw with path
  //path [ 0 ] = '\0';
//  StrCat ( path, VFSPATH );
//  StrCat ( path, chdir );
  //StrCat ( path, filename+2 );
  StrPrintF( path, "%s", filename );
  // MYCODE EDIT why is this here: voliter=filename[0]-48;
  //StrPrintF ( path, "%s%s", VFSPATH, filename );

//  DEBUGS(path);

  if ( myfile->bufferp==2 || myfile->bufferp==0 ){
  	//write only mode, so remove existing file  	
    VFSFileDelete(voliter, path);
  }

  if( myfile->bufferp==2 || myfile->bufferp==0 )
  {
  	// Read/Write (implies EXCLUSIVE!)
  	err = VFSFileOpen ( voliter, path, vfsModeReadWrite, & (myfile->ref) );
  }
  else
  {
  	// Read only (not exclusive)
  	err = VFSFileOpen ( voliter, path, vfsModeRead, & (myfile->ref) );
  }
  
#ifdef SF_LITTLEENDIAN
//  myfile -> ref = ByteSwap32 ( myfile -> ref );
#endif

  if ( err != errNone ) {

    if ( StrChr ( mode, 'w' ) ) {
      /* couldn't open it, but try and create it.. */
      err = VFSFileCreate ( voliter, path );

      if ( err != errNone ) {
	//DEBUGS ( "create: Failed" );
	return ( NULL );
      }

      err = VFSFileOpen ( voliter, path, vfsModeReadWrite, & (myfile->ref) );

#ifdef SF_LITTLEENDIAN
//      myfile -> ref = ByteSwap32 ( myfile -> ref );
#endif

      if ( err != errNone ) {
	DEBUGS ( "open write: Failed" );
	free ( myfile );	
	return ( NULL );
      }

    } else {
//      DEBUGS ( "open: Failed" );
      free ( myfile );      
      return ( NULL );
    }

  }

  VFSFileSize ( myfile -> ref, & (myfile -> size) );
  
 
//  StrIToA ( str, (myfile -> size) );
//  DEBUGS ( str );      

#ifdef SF_LITTLEENDIAN
  //myfile -> size = ByteSwap32 ( myfile -> size );
#endif

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

//	DEBUGS ("File opened");
//	DEBUGS ("Ref :");
//	DEBUGU32 (myfile->ref);
//	DEBUGS ("Size :");
//	DEBUGU32 (myfile->size);

  return ( myfile );
}

Int8 fclose ( FILE *file ) {

#ifdef DEBUGFILE
  DEBUGS(__FUNCTION__);
#endif

  if ( file -> bufferp == 2 && file -> tail ) {
    // write buffer, so we need to empty the buffer into the stream
    UInt32 result;
    VFSFileWrite ( file -> ref, file -> tail, file -> buffer, &result );
  }

  VFSFileClose ( file -> ref );

  free ( file );

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

  return ( 0 );
}

UInt32 fwrite ( const void *_buf, UInt32 size, UInt32 num, FILE *file ) {
//UInt32 fwrite ( char *buf, UInt32 size, UInt32 num, FILE *file ) {
  char *buf = (char*) _buf;
  UInt32 result;

#ifdef DEBUGFILE
  DEBUGS(__FUNCTION__);
  DEBUGU32(size*num);
#endif

  // for fwrite, lets assume they're calling it since they want to write
  // a block of stuff, not just a single character; so first lets flush
  // any buffer so far, and then write out their buffer
  // (later could shove their buf into our file buffer..)
#if 0
  Err err;

  if ( file -> tail ) {
    VFSFileWrite ( file -> ref, file -> tail, file -> buffer, &result );
    file -> tail = 0;
  }

  if ( size*num ) {
    err = VFSFileWrite ( file -> ref, size*num, buf, &result );
  }
#else
  result = size*num;
  while ( result ) {
    fputc ( *buf++, file );
    result--;
  }
#endif

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

  //return ( result );
  return ( num );
}

int fputc ( UInt8 c, FILE *file ) {

#ifdef DEBUGFILE
  DEBUGS(__FUNCTION__);
#endif

  if ( file == stdout ) {
    //screen_push ( c );
  } else {

    //draw_progress_bar ( 100 * file -> tail / 255 );

    // buffer large enough to hold another char?
    if ( file -> tail == TAILMAX || file->bufferp==0 ) {
      UInt32 result;
      VFSFileWrite ( file -> ref, file -> tail, file -> buffer, &result );
      file -> tail = 0;
      //fwrite ( &c, 1, 1, file );
    }

    // insert into buffer
    file -> buffer [ file -> tail++ ] = c;

  }

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

  return ( c );
}

UInt8 file_exists ( const char *filename ) {
  FILE *f = fopen ( filename, "r" );

  if ( f ) {
    fclose ( f );
    return ( 1 );
  }

  return ( 0 );
}

UInt32 fread ( void *_buf, UInt32 size, UInt32 num, FILE *file ) {
//UInt32 fread ( char *buf, UInt32 size, UInt32 num, FILE *file ) {
  char *buf = (char*)_buf;
  UInt32 result;
  Err err=0;
  UInt32 ext = size * num;

#ifdef DEBUGFILE
  DEBUGS(__FUNCTION__);
  DEBUGS(file->filename);
  DEBUGU32(num*size);
#endif

  // do we have any data in the buffer already? if so, lets first use
  // that and then pick up any extra needed
  if ( ext < file -> tail ) {
    // buffer already has all the data
    //DEBUGS("less");

    // pick up buffered bytes
    MemMove ( buf, file -> buffer, ext );

    // shuffle buffer up into place
    MemMove ( file -> buffer, file -> buffer + ext, file -> tail - ext );

    // update tail to new size
    file -> tail -= ext;

  } else {
  	int res1;
    // buffer doesn't have enough data
    //DEBUGS("more");

    // move buffer into buf
    MemMove ( buf, file -> buffer, file -> tail ); // might be zero

    // go to end of buff
    buf += file -> tail;

    // num remaining
    ext -= file -> tail;

    // empty buffer
    res1=file -> tail;
    file -> tail = 0; // now empty

    // pick up remaining
    err = VFSFileRead ( file -> ref, ext, buf, &result );

	if (err) num = (result+res1) / size;
  }

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

  //return ( result );
//  if (error) return 0;
  return ( num );
}

UInt32 ftell ( FILE *file ) {
  UInt32 result;
  Err err;

#ifdef DEBUGFILE
  DEBUGS(__FUNCTION__);
#endif

  err = VFSFileTell ( file -> ref, &result );

  if ( file -> bufferp == 1 ) {
    result -= file -> tail;
  } else if ( file -> bufferp == 2 ) {
    result += file -> tail;
  }

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

  return ( result );
}

int fgetc ( FILE *file ) {
  UInt8 c;

#ifdef DEBUGFILE
  DEBUGS(__FUNCTION__);
#endif

  // buffer empty? If so, populate it..
  if ( file -> tail == 0 ) {
    //fread ( &c, 1, 1, file );
    UInt32 size = 255;

    if ( file -> size - ftell ( file ) < 255 ) {
      size = file -> size - ftell ( file );
    }
    if (!size) c=0;
    else{
	    fread ( file -> buffer, size, 1, file );
	    file -> tail += size;
	}
  }

  // already in the buffer?
  if ( file -> tail ) {

    // disrupts loading display
    //draw_progress_bar ( 100 * file -> tail / 255 );

    c = file -> buffer [ 0 ];
    MemMove ( file -> buffer, file -> buffer + 1, file -> tail - 1 );
    file -> tail -= 1;

  }

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

  return ( c ); // -1 on error?
}

char *fgets(char *buf,int size,FILE *file){
	int i;
	char c;
	if (!size) return buf;
	if (size==1) {buf[0]=0;return buf;}
	for (i=0;i<size-1;i++){
		c=fgetc(file);
		if ((!c)||(c=='\n')) break;
		buf[i]=c;
	}
	buf[i]=0;
	if (!c) return NULL;
	return buf;
}


Int8 fseek ( FILE *file, Int32 rel, UInt16 source ) {
  Err err;

#ifdef DEBUGFILE
  DEBUGS(__FUNCTION__);
#endif

  //added by YOYO
  //if fseek in write-mode (for ex snss.c for nes :-) )
  if ( file -> bufferp == 2 && file -> tail ) {
    // write buffer, so we need to empty the buffer into the stream
    UInt32 result;
    VFSFileWrite ( file -> ref, file -> tail, file -> buffer, &result );
  }

  //


  file -> tail = 0; // should only fseeking on a read stream so we can dump it
  err = VFSFileSeek ( file -> ref, source, rel );

#ifdef DEBUGFILE
  DEBUGS( "Exit");
#endif

  return ( 0 ); // success
}

Int8 remove ( const char *filename )
{
  UInt32 voliter = palm_vfs_iter();
  char path [ 256 ];
  Err err;  
  // looks like general purpose work, so don't screw with path
  path [ 0 ] = '\0';
//  StrCat ( path, VFSPATH );
//  StrCat ( path, chdir );

  StrCat ( path, filename );
  // MYCODE EDIT why is this here: voliter=filename[0]-48;
  //StrPrintF ( path, "%s%s", VFSPATH, filename );

//  DEBUGS(path);
	err = VFSFileDelete(voliter, path);
	
	return err;
}

Int8 fgetdate( const char *filename,UInt32 *date)
{
	Err err;
	FILE *f=fopen(filename,"rb");
	if (!f) return -1;
	err = VFSFileGetDate(f -> ref,vfsFileDateModified ,date);
	fclose(f);	
	return err;	
} 


UInt32 fgetsize(FILE *f){
	if (!f) return 0;
	return f->size;
}
