/*****************************************************************************
   Major portions of this software are copyrighted by the Medical College
   of Wisconsin, 1994-2000, and are released under the Gnu General Public
   License, Version 2.  See the file README.Copyright for details.
******************************************************************************/
   
#include "thd_compress.h"
#include "Amalloc.h"

/*** check if the file exists on disk
     -- returns 1 if it does, 0 if it does not ***/

int COMPRESS_is_file( char * pathname )
{
   static struct stat buf ;
   int ii ;

   if( pathname == NULL ) return 0 ;
   ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ;
   ii = (buf.st_mode & S_IFREG) != 0 ; return ii ;
}

/*--------------------------------------------------------------*/

/*** check if the filename has the apposite
     suffix for the compression mode given  ***/

int COMPRESS_has_suffix( char * fname , int mode )
{
   int ll ;

   if( mode < 0                 ) return 1 ;
   if( mode > COMPRESS_LASTCODE ) return 0 ;

   ll = strlen(fname) ;
   return ( ll > COMPRESS_suffix_len[mode] &&
            strcmp(COMPRESS_suffix[mode] ,
                   fname+(ll-COMPRESS_suffix_len[mode])) == 0 ) ;
}

/*--------------------------------------------------------------*/

/*** return the compression code for the given filename;
     if the file doesn't exist, will return COMPRESS_NOFILE ***/

int COMPRESS_filecode( char * fname )
{
   int ii ;
   char * buf ;

   if( fname == NULL || fname[0] == '\0' ) return COMPRESS_NOFILE ;

   /** check the filename suffix **/

   for( ii=0 ; ii <= COMPRESS_LASTCODE ; ii++ ){
      if( COMPRESS_has_suffix(fname,ii) ){
         if( COMPRESS_is_file(fname) ) return ii ;
         else                          return COMPRESS_NOFILE ;
      }
   }
   if( COMPRESS_is_file(fname) ) return COMPRESS_NONE ;

   /** add the suffixes to the name, and check again **/

   buf = AFMALL(char, sizeof(char) * (strlen(fname)+16) ) ;
   for( ii=0 ; ii <= COMPRESS_LASTCODE ; ii++ ){
      strcpy(buf,fname) ; strcat(buf,COMPRESS_suffix[ii]) ;
      if( COMPRESS_is_file(buf) ){ free(buf) ; return ii ; }
   }
   free(buf) ; return COMPRESS_NOFILE ;
}

/*--------------------------------------------------------------*/

/*** keep a table of which open files used fopen and which
     used popen -- because they must be closed differently ***/

#define NFOPMAX 16
static int fop_init = 0 ;
static int fop_fileno[NFOPMAX] ;
static int fop_popend[NFOPMAX] ;

static void putin_fop_table( FILE * fp , int ppp )
{
   int ii ;

   if( fp == NULL ) return ;  /* can't do much with nothing */

   if( ! fop_init ){                       /* initialize the table */
      for( ii=0 ; ii < NFOPMAX ; ii++ ){
         fop_fileno[ii] = -1 ;
         fop_popend[ii] =  0 ;
      }
      fop_init = 1 ;
   }

   for( ii=0 ; ii < NFOPMAX ; ii++ )       /* find an unused entry */
      if( fop_fileno[ii] < 0 ) break ;

   if( ii == NFOPMAX ){
      fprintf(stderr,"\n*** AFNI compressor table overflow!\n") ;
      return ;
   }

   fop_fileno[ii] = fileno(fp) ;   /* save the file number */
   fop_popend[ii] = ppp ;          /* save the popen code */
   return ;
}

/*** Use this to close a file,
     so that pclose or fclose can be called correctly ***/

int COMPRESS_fclose( FILE * fp )
{
   int fn , ii ;

   if( fp == NULL || ! fop_init ) return fclose(fp) ;

   fn = fileno(fp) ;
   for( ii=0 ; ii < NFOPMAX ; ii++ ){   /* find the file number */
      if( fop_fileno[ii] == fn ){       /* found it! */
         fop_fileno[ii] = -1 ;          /* empty this table entry */
         if( fop_popend[ii] ) return pclose(fp) ;
         else                 return fclose(fp) ;
      }
   }

   return fclose(fp) ;  /* couldn't find it, so use fclose */
}

/*--------------------------------------------------------------*/

/*** return a malloc-ed filename string that has the
     correct compression suffix attached.
     If NULL is returned, the file doesn't exist.
     The return string should be free()-ed after it is used. ***/

char * COMPRESS_filename( char * fname )
{
   char * buf ;
   int ll , mm ;

   if( fname == NULL || fname[0] == '\0' ) return NULL ;

   mm  = COMPRESS_filecode( fname ) ;  /* find compression mode */
   if( mm == COMPRESS_NOFILE ) return NULL ;

   ll  = strlen(fname) ;
   buf = AFMALL(char, sizeof(char) * (ll+16) ) ;  /* worst case */

   if( mm == COMPRESS_NONE ){
      strcpy(buf,fname) ;
   } else {
      if( ! COMPRESS_has_suffix(fname,mm) ){
         strcpy(buf,fname) ; strcat(buf,COMPRESS_suffix[mm]) ;
      } else {
         strcpy(buf,fname) ;
      }
   }
   return buf ;
}

/*--- May 1998: a simple routine ---*/

char * COMPRESS_add_suffix( char * fname , int mm )
{
   char * buf ;
   int ll ;

   if( fname == NULL || fname[0] == '\0' ) return NULL ;

   ll  = strlen(fname) ;
   buf = AFMALL(char, sizeof(char) * (ll+16) ) ;

   strcpy(buf,fname) ;
   if( mm >= 0 && mm <= COMPRESS_LASTCODE &&
       ! COMPRESS_has_suffix(fname,mm)      ){

      strcat(buf,COMPRESS_suffix[mm]) ;
   }

   return buf ;
}

/*--------------------------------------------------------------*/

/*** open a file for readin, possibly using compresson ***/

FILE * COMPRESS_fopen_read( char * fname )
{
   FILE * fp ;
   int mm ;
   char * buf , * cmd ;

   if( fname == NULL || fname[0] == '\0' ) return NULL ;

   mm = COMPRESS_filecode( fname ) ;  /* find compression mode */

   if( mm == COMPRESS_NOFILE ) return NULL ;  /* can't do nothin */

   if( mm == COMPRESS_NONE ){
      fp = fopen(fname,"r") ;   /* open it normally */
      putin_fop_table(fp,0) ;   /* save its open method */
      return fp ;
   }

#if 1
   if( ! COMPRESS_has_suffix(fname,mm) ){
      buf = AFMALL(char, sizeof(char) * (strlen(fname)+16) ) ;
      strcpy(buf,fname) ; strcat(buf,COMPRESS_suffix[mm]) ;
   } else {
      buf = fname ;
   }
#else
   buf = fname ;
#endif

   cmd = AFMALL(char, sizeof(char) * (strlen(buf)+32) ) ;
   sprintf(cmd,COMPRESS_unprogram[mm],buf) ;

   fp = popen(cmd,"r") ;    /* open a pipe to read the file */
   putin_fop_table(fp,1) ;  /* save its open method */

   free(cmd) ; if( buf != fname ) free(buf) ;
   return fp ;
}

/*-------------------------------------------------------------
    open a file for writing, possibly using compresson;
     mm should be one of the COMPRESS_ codes at the top
     of file thd_compress.h
---------------------------------------------------------------*/

FILE * COMPRESS_fopen_write( char * fname , int mm )
{
   FILE * fp ;
   char * buf , * cmd ;

   if( fname == NULL || fname[0] == '\0' ) return NULL ;

   /* Don't compress if the compression program isn't marked as OK   */
   /* [For modes that can only be compressed offline, like BRIKCOMP] */

   if( mm < 0 || ! COMPRESS_program_ok[mm] ){
      fp = fopen(fname,"w") ;   /* open it normally */
      putin_fop_table(fp,0) ;   /* save its open method */
      return fp ;
   }

#if 1
   if( ! COMPRESS_has_suffix(fname,mm) ){
      buf = AFMALL(char, sizeof(char) * (strlen(fname)+16) ) ;
      strcpy(buf,fname) ; strcat(buf,COMPRESS_suffix[mm]) ;
   } else {
      buf = fname ;
   }
#else
   buf = fname ;
#endif

   cmd = AFMALL(char,  sizeof(char) * (strlen(buf)+32) ) ;
   sprintf(cmd,COMPRESS_program[mm],buf) ;

   fp = popen(cmd,"w") ;    /* open a pipe to write the file */
   putin_fop_table(fp,1) ;  /* save its open method */

   free(cmd) ; if( buf != fname ) free(buf) ;
   return fp ;
}

/*----------------------------------------------------------*/

int COMPRESS_unlink( char * fname )
{
   char * fff = COMPRESS_filename(fname) ;
   int     ii = -1 ;
   if( fff != NULL ){ ii=unlink(fff); free(fff); }
   return ii ;
}


syntax highlighted by Code2HTML, v. 0.9.1