/*****************************************************************************
   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"

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

#define NPMAX 128

int main( int argc , char * argv[] )
{
   int iarg ;
   THD_3dim_dataset * dset ;
   float bper = 60.0 , bmin = 1 ;

   int nxyz , ii , kk , nbin , sval , sum , nbot , a,b,c , nbase,npeak,ntop , nvox ;
   int * fbin ;
   short * sfim ;
   int   kmin[NPMAX] , kmax[NPMAX] ;
   int   nmin        , nmax        ;

   /*-- help? --*/

   if( argc < 2 || strncmp(argv[1],"-help",4) == 0 ){
      fprintf(stderr,
             "Find the clipping point on a histogram of a 3D brick\n"
             "Usage: 3dhclip [options] dataset\n"
             "\n"
             "Options:\n"
             "  -bper bb   Means to take the base percentage point\n"
             "              on the cumulative histogram as 'bb'\n"
             "              [default bb = 60]\n"
             "  -bmin cc   Means to take the minimum value to consider\n"
             "              as 'cc' [default cc = 1]\n"
         ) ;

      printf("\n" MASTER_SHORTHELP_STRING ) ;

      PRINT_COMPILE_DATE ; exit(0) ;
   }

   /*-- process options --*/

   iarg = 1 ;
   while( iarg < argc && argv[iarg][0] == '-' ){

      if( strcmp(argv[iarg],"-bper") == 0 ){
         bper = strtod( argv[++iarg] , NULL ) ;
         if(bper<1 || bper>99){fprintf(stderr,"** Illegal -bper value\n");exit(1);}
         iarg++ ; continue ;
      }

      if( strcmp(argv[iarg],"-bmin") == 0 ){
         bmin = strtod( argv[++iarg] , NULL ) ;
         if(bmin<0){fprintf(stderr,"** Illegal -bmin value\n");exit(1);}
         iarg++ ; continue ;
      }

      fprintf(stderr,"** Illegal option: %s\n",argv[iarg]) ; exit(1) ;
   }

   /*-- load dataset --*/

   if( iarg >=  argc ){fprintf(stderr,"** No dataset?!\n");exit(1);}

   dset = THD_open_dataset(argv[iarg]) ;
   if( dset == NULL ){
      fprintf(stderr,"** Can't open dataset %s\n",argv[iarg]) ;
      exit(1) ;
   }

   if( DSET_BRICK_TYPE(dset,0) != MRI_short || DSET_BRICK_FACTOR(dset,0) != 0.0 ){
     fprintf(stderr,"** Program only works with short-value datasets!\n") ;
     exit(1) ;
   }

   DSET_load(dset) ;
   sfim = DSET_ARRAY(dset,0) ;
   if( sfim == NULL ){fprintf(stderr,"** Can't load dataset brick\n");exit(1);}

   /*-- make histogram of shorts --*/


   fbin = (int *) malloc( sizeof(int) * 32768 ) ;
   for( kk=0 ; kk < 32768 ; kk++ ) fbin[kk] = 0 ;

   nvox = 0 ; nxyz = DSET_NVOX(dset) ;

   for( ii=0 ; ii < nxyz ; ii++ ){
      kk = sfim[ii] ; if( kk >= 0 ){ fbin[kk]++ ; nvox++ ; }
   }

   DSET_unload(dset) ;

   /*-- find largest value --*/

   for( kk=32767 ; kk > 0 ; kk-- ) if( fbin[kk] > 0 ) break ;
   if( kk == 0 ){fprintf(stderr,"** All voxels are zero!\n");exit(1);}
   nbin = kk+1 ;

   /*-- find bper point in cumulative distribution --*/

   sval = 0.01 * bper * nvox ;
   sum  = 0 ;
   for( kk=0 ; kk < nbin ; kk++ ){
      sum += fbin[kk] ; if( sum >= sval ) break ;
   }
   nbot = kk ; if( nbot == 0 ) nbot = 1 ; if( bmin > nbot ) nbot = bmin ;
   if( nbot >= nbin-9 ){fprintf(stderr,"** Base point on histogram too high\n");exit(1);}

   /*-- smooth histogram --*/

   b = fbin[nbot-1] ; c = fbin[nbot] ;
   for( kk=nbot ; kk < nbin ; kk++ ){
      a = b ; b = c ; c = fbin[kk+1] ; fbin[kk] = 0.25*(a+c+2*b) ;
   }

   /*-- find minima and maxima above bper point --*/

   nmin = nmax = 0 ;
   for( kk=nbot+1 ; kk < nbin ; kk++ ){
      if( fbin[kk] < fbin[kk-1] && fbin[kk] < fbin[kk+1] && nmin < NPMAX ){
         kmin[nmin++] = kk ;
      } else if( fbin[kk] > fbin[kk-1] && fbin[kk] > fbin[kk+1] && nmax < NPMAX ){
         kmax[nmax++] = kk ;
      }
   }

#if 0
   for( kk=0 ; kk < nmin ; kk++ )
      printf("Min: %d has %d\n",kmin[kk],fbin[kmin[kk]]) ;

   for( kk=0 ; kk < nmax ; kk++ )
      printf("Max: %d has %d\n",kmax[kk],fbin[kmax[kk]]) ;
#endif

   /*-- find the largest two maxima --*/

   if( nmax == 0 ){fprintf(stderr,"** No maxima above base point\n");exit(1);}

   if( nmax <= 2 ){
      npeak = kmax[0] ; ntop = 0 ;
   } else {
      int f1,f2 , k1,k2 , fk , klow,kup ;

      k1 = 0 ; f1 = fbin[kmax[0]] ;
      k2 = 1 ; f2 = fbin[kmax[1]] ;
      if( f1 < f2 ){
         k1 = 1 ; f1 = fbin[kmax[1]] ;
         k2 = 0 ; f2 = fbin[kmax[0]] ;
      }

      for( kk=2 ; kk < nmax ; kk++ ){
         fk = fbin[kmax[kk]] ;
         if( fk > f1 ){
            f2 = f1 ; k2 = k1 ;
            f1 = fk ; k1 = kk ;
         } else if( fk > f2 ){
            f2 = fk ; k2 = kk ;
         }
      }
      npeak = MIN( kmax[k1] , kmax[k2] ) ;  /* smaller bin of the 2 top peaks */

      /* find valley between 2 peaks */

      ntop  = MAX( kmax[k1] , kmax[k2] ) ;

      fk = fbin[ntop] ; klow = ntop ;
      for( kk=ntop-1 ; kk >= npeak ; kk-- ){
         if( fbin[kk] < fk ){ fk = fbin[kk] ; klow = kk ; }
      }
      fk = 0.16 * fk ; kup = MIN( nbin-1 , ntop+3*(ntop-klow+2) ) ;
      for( kk=ntop+1 ; kk <= kup ; kk++ ) if( fbin[kk] < fk ) break ;
      ntop = kk ;
   }

   for( kk=npeak-1 ; kk > 0 ; kk-- )
      if( fbin[kk] < fbin[kk-1] && fbin[kk] < fbin[kk+1] ) break ;
   nbase = kk ;

   printf("dataset: %s -- ",argv[iarg]) ;
   printf("base = %d  peak = %d  top = %d\n",nbase,npeak,ntop) ;

   exit(0) ;
}
