/*****************************************************************************
   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 "mrilib.h"
#include "thd.h"

/*--------------------------------------------------------------
   SARR: string array routines (not easily coded as macros)

     SARR_find_string: return index of string in the array
     SARR_find_substring: return index of string that has substring in it
     ci : if 1 then search is case instensitive
   If these return value < 0, string or substring not found!
----------------------------------------------------------------*/

int SARR_find_string( THD_string_array * sar , char * str, byte ci )
{
   return SARR_lookfor_string( sar , str , 0 , ci) ;
}

int SARR_find_substring( THD_string_array * sar , char * str, byte ci )
{
   return SARR_lookfor_substring( sar , str , 0 , ci) ;
}

int SARR_lookfor_string( THD_string_array * sar , char * str ,
                         int nstart , byte ci )
{
   int ii ;

   if( sar == NULL || str == NULL ) return -1 ;

   for( ii=nstart ; ii < sar->num ; ii++ ){
      if( sar->ar[ii] != NULL &&
          ( (ci && !strcasecmp(sar->ar[ii],str)) || !strcmp(sar->ar[ii],str) ) )
         return ii ;
   }
   return -1 ;
}

int SARR_lookfor_substring( THD_string_array * sar , char * sub ,
                            int nstart , byte ci )
{
   int ii ;

   if( sar == NULL || sub == NULL ) return -1 ;

   for( ii=nstart ; ii < sar->num ; ii++ ){
      if( sar->ar[ii] != NULL &&
          ( (ci && strcasestr(sar->ar[ii],sub)) || strstr(sar->ar[ii],sub) ) )
         return ii ;
   }
   return -1 ;
}

/*--------------------------------------------------------------
   routines to return an alphabetized list of all the entries
   in a directory that don't begin with '.'

   01 Feb 1998: modified to avoid use of scandir routine.
----------------------------------------------------------------*/

#ifndef DONT_USE_SCANDIR
#  ifdef SCANDIR_WANTS_CONST
      int THD_select_dirent( const struct dirent * dp )
#  else
      int THD_select_dirent( struct dirent * dp )
#  endif
      {
         if( dp == NULL || dp->d_name[0] == '\0' || dp->d_name[0] == '.' )
            return 0 ;
         return 1 ;
      }
#endif

THD_string_array * THD_get_all_filenames( char * dirname )
{
#ifndef DONT_USE_SCANDIR
   struct dirent ** dplist=NULL ;
#endif
   int nfiles , dlen , ii , n_fname , max_fname ;
   THD_string_array * star ;
   char * total_dirname , * total_fname ;
   char ** gname=NULL ;

ENTRY("THD_get_all_filenames") ;

   if( dirname == NULL || (dlen=strlen(dirname)) == 0 ) RETURN( NULL );
   if( ! THD_is_directory(dirname) )                    RETURN( NULL );

   total_dirname = (char*)RwcMalloc( dlen+4 ) ;
   strcpy( total_dirname , dirname ) ;
   if( total_dirname[dlen-1] != '/' ){
      total_dirname[dlen]   = '/' ;     /* add a slash */
      total_dirname[++dlen] = '\0' ;
   }

#ifdef DONT_USE_SCANDIR
   total_dirname[dlen]   = '*' ;                            /* add wildcard */
   total_dirname[++dlen] = '\0' ;
   MCW_warn_expand(0) ;
if(PRINT_TRACING){
 char str[256]; sprintf(str,"MCW_file_expand(%s)",total_dirname); STATUS(str);
}
   MCW_file_expand( 1, &total_dirname, &nfiles, &gname ) ;  /* find files */
#else
   nfiles = scandir( dirname ,
                     &dplist ,
                     THD_select_dirent ,
                     alphasort ) ;
#endif

   if( nfiles < 1 ){
       myRwcFree( total_dirname ) ;
#ifdef DONT_USE_SCANDIR
       if( gname != NULL ) free(gname) ;
#else
       if( dplist != NULL ) free(dplist) ;
#endif
       RETURN( NULL );
   }

   INIT_SARR( star ) ;

#ifndef DONT_USE_SCANDIR
   max_fname   = dlen+64 ;
   total_fname = (char*)RwcMalloc( max_fname ) ;
#endif

   for( ii=0 ; ii < nfiles ; ii++ ){
#ifdef DONT_USE_SCANDIR
      ADDTO_SARR( star , gname[ii] ) ;
#else
      n_fname = dlen + strlen( dplist[ii]->d_name ) + 4 ;
      if( n_fname > max_fname ){
         total_fname = AFREALL(total_fname, char, n_fname ) ;
         max_fname   = n_fname ;
      }
      strcpy( total_fname , total_dirname ) ;
      strcat( total_fname , dplist[ii]->d_name ) ;
      ADDTO_SARR( star , total_fname ) ;
      free( dplist[ii] ) ;
#endif
   }

   myRwcFree( total_dirname ) ;
#ifdef DONT_USE_SCANDIR
   MCW_free_expand( nfiles , gname ) ;
#else
   myRwcFree( total_fname ) ;
   free( dplist ) ;
#endif
   RETURN( star );
}

/*------------------------------------------------------------------
  Returns a list of all subdirectories under the input,
  recursively to level "lev", including the input directory.
--------------------------------------------------------------------*/

THD_string_array * THD_get_all_subdirs( int lev , char * dirname )
{
   int ii , jj , dlen ;
   THD_string_array * star , * flist , * dlist ;
   char * total_dirname ;

ENTRY("THD_get_all_subdirs") ;

   if( dirname == NULL || (dlen=strlen(dirname)) == 0 ) RETURN( NULL );

   total_dirname = (char*)RwcMalloc( dlen+2 ) ;
   strcpy( total_dirname , dirname ) ;
   if( total_dirname[dlen-1] != '/' ){
      total_dirname[dlen]   = '/' ;
      total_dirname[++dlen] = '\0' ;
   }

   INIT_SARR( star ) ;
   ADDTO_SARR( star , total_dirname ) ;

   /** want only this level? **/

   if( lev <= 0 ) RETURN( star );

   /** must want deeper levels **/

   flist = THD_get_all_filenames( total_dirname ) ;
   myRwcFree(total_dirname) ;

   if( flist == NULL ) RETURN( star );
   if( flist->num == 0 ){ DESTROY_SARR(flist) ; RETURN( star ); }

   dlist = THD_extract_directories( flist ) ;
   DESTROY_SARR(flist) ;
   if( dlist == NULL ) RETURN( star );
   if( dlist->num == 0 ){ DESTROY_SARR(dlist) ; RETURN( star ); }

   for( ii=0 ; ii < dlist->num ; ii++ ){
      flist = THD_get_all_subdirs( lev-1 , dlist->ar[ii] ) ;
      if( flist == NULL ) continue ;
      for( jj=0 ; jj < flist->num ; jj++ ){
         ADDTO_SARR( star , flist->ar[jj] ) ;
      }
      DESTROY_SARR(flist) ;
   }

   DESTROY_SARR(dlist) ;
   RETURN( star );
}

/*-------------------------------------------------------
   take a list of filenames and extract a new list
   consisting only of regular files
---------------------------------------------------------*/

THD_string_array * THD_extract_regular_files( THD_string_array * star_in )
{
   THD_string_array * star_out ;
   int ii ;

ENTRY("THD_extract_regular_files") ;

   if( star_in == NULL || star_in->num <= 0 ) RETURN( NULL );

   INIT_SARR(star_out) ;

   for( ii=0 ; ii < star_in->num ; ii++ ){
      if( THD_is_file(star_in->ar[ii]) )
         ADDTO_SARR( star_out , star_in->ar[ii] ) ;
   }

   if( star_out->num == 0 ) DESTROY_SARR(star_out) ;
   RETURN( star_out );
}

/*-------------------------------------------------------
   take a list of filenames and extract a new list
   consisting only of directories
---------------------------------------------------------*/

THD_string_array * THD_extract_directories( THD_string_array * star_in )
{
   THD_string_array *star_out ; char *dname ;
   int ii ;

ENTRY("THD_extract_directories") ;

   if( star_in == NULL || star_in->num <= 0 ) RETURN( NULL );

   INIT_SARR(star_out) ;

   for( ii=0 ; ii < star_in->num ; ii++ ){
     dname = star_in->ar[ii] ;
     if( THD_forbidden_directory(dname) ) continue ;
     if( THD_is_directory(dname) )
       ADDTO_SARR( star_out , dname ) ;
   }

   if( star_out->num == 0 ) DESTROY_SARR(star_out) ;
   RETURN( star_out );
}

/*-------------------------------------------------------------------
   Take a list of filenames, convert them into "real" names
   (excising things like ../ and symbolic links), and then
   cast out duplicates.  09 Sep 1998 -- RWCox.
---------------------------------------------------------------------*/

THD_string_array * THD_normalize_flist( THD_string_array *star_in )
{
   THD_string_array *star_out , *star_qqq ;
   static char rpath[RPMAX] ;  /* 04 Mar 2009 [RWC]: 2048 ==> RPMAX */
   char *rp ;
   int ii , jj , nleft , skip_realpath=0 ;

ENTRY("THD_normalize_flist") ;

   if( star_in == NULL || star_in->num <= 0 ) RETURN( NULL );

   skip_realpath = AFNI_yesenv("AFNI_NOREALPATH") ;

   INIT_SARR(star_out) ;

   for( ii=0 ; ii < star_in->num ; ii++ ){
      if( skip_realpath ) rp = star_in->ar[ii] ;
      else                rp = realpath( star_in->ar[ii] , rpath ) ;

      if( rp == NULL && strchr(star_in->ar[ii],'+') != NULL ){ /* 10 Sep 2013 */
        char *sp ;
        jj = strlen(star_in->ar[ii]) ; sp = malloc(jj+32) ;
        strcpy(sp,star_in->ar[ii]) ;
        if( sp[jj-1] != '.' ) strcat(sp,".") ;
        strcat(sp,"HEAD") ;
        rp = realpath( sp , rpath ) ;
        free(sp) ;
      }

      if( rp != NULL ) ADDTO_SARR( star_out , rp ) ;
   }

   if( star_out->num == 0 ){ DESTROY_SARR(star_out) ; RETURN( NULL ); }

   nleft = 0 ;
   for( ii=0 ; ii < star_out->num ; ii++ ){
      rp = star_out->ar[ii] ;
      if( rp != NULL ){
         nleft++ ; jj = ii ;
         while( jj >= 0 ){
            jj = SARR_lookfor_string( star_out , rp , jj+1 , 0) ;
            if( jj >= 0 ) REMOVEFROM_SARR(star_out,jj) ;
         }

         for( jj=ii+1 ; jj < star_out->num ; jj++ ){
            if( THD_equiv_files(rp,star_out->ar[jj]) )
               REMOVEFROM_SARR(star_out,jj) ;
         }
      }
   }

   if( nleft == 0 ){ DESTROY_SARR(star_out) ; RETURN( NULL ); }

   if( nleft == star_out->num ) RETURN( star_out );

   INIT_SARR(star_qqq) ;
   for( ii=0 ; ii < star_out->num ; ii++ ){
      rp = star_out->ar[ii] ;
      if( rp != NULL ) ADDTO_SARR(star_qqq,rp) ;
   }

#if 0
fprintf(stderr,"\nTHD_normalize_flist: in=%d out=%d qqq=%d\n",
        star_in->num , star_out->num , star_qqq->num ) ;
#endif

   DESTROY_SARR(star_out) ; RETURN( star_qqq );
}

/*---------------------------------------------------------------
  Added 27 Jan 2000
-----------------------------------------------------------------*/

THD_string_array * THD_get_wildcard_filenames( char * pat )
{
   int nfiles , ii ;
   THD_string_array * star ;
   char ** gname=NULL ;

ENTRY("THD_get_wildcard_filenames") ;

   if( pat == NULL || strlen(pat) == 0 ) RETURN( NULL );

   MCW_warn_expand(0) ;
   MCW_file_expand( 1, &pat, &nfiles, &gname ) ;  /* find files */

   if( nfiles < 1 ){
       if( gname != NULL ) free(gname) ;
       RETURN( NULL );
   }

   INIT_SARR( star ) ;

   for( ii=0 ; ii < nfiles ; ii++ ){
      ADDTO_SARR( star , gname[ii] ) ;
   }

   MCW_free_expand( nfiles , gname ) ;
   RETURN( star );
}
