#include "mrilib.h"

int main( int argc , char * argv[] )
{
   int iarg ;
   THD_3dim_dataset *inset , *outset ;
   int add_I=0 , add_S=0 , add_A=0 , add_P=0 , add_L=0 , add_R=0 ;
   int RLsiz=0, APsiz=0, ISsiz=0 ; /* 23 Mar 2004 */
   char * prefix="zeropad" ;

   int add_z=0 ;   /* 07 Feb 2001 */
   int mm_flag=0 ; /* 13 Feb 2001 */
   int flag ;

   THD_3dim_dataset *mset=NULL ; /* 14 May 2002 */

   /*-- help? --*/

   if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
      printf("Usage: 3dZeropad [options] dataset\n"
             "Adds planes of zeros to a dataset (i.e., pads it out).\n"
             "\n"
             "Options:\n"
             "  -I n = adds 'n' planes of zero at the Inferior edge\n"
             "  -S n = adds 'n' planes of zero at the Superior edge\n"
             "  -A n = adds 'n' planes of zero at the Anterior edge\n"
             "  -P n = adds 'n' planes of zero at the Posterior edge\n"
             "  -L n = adds 'n' planes of zero at the Left edge\n"
             "  -R n = adds 'n' planes of zero at the Right edge\n"
             "  -z n = adds 'n' planes of zeros on EACH of the\n"
             "          dataset z-axis (slice-direction) faces\n"
             "\n"
             " -RL a = These options specify that planes should be added/cut\n"
             " -AP b = symmetrically to make the resulting volume have\n"
             " -IS c = 'a', 'b', and 'c' slices in the respective directions.\n"
             "\n"
             " -mm   = pad counts 'n' are in mm instead of slices:\n"
             "         * each 'n' is an integer\n"
             "         * at least 'n' mm of slices will be added/removed:\n"
             "            n =  3 and slice thickness = 2.5 mm ==> 2 slices added\n"
             "            n = -6 and slice thickness = 2.5 mm ==> 3 slices removed\n"
             "\n"
             " -master mset = match the volume described in dataset 'mset':\n"
             "                * mset must have the same orientation and grid\n"
             "                   spacing as dataset to be padded\n"
             "                * the goal of -master is to make the output dataset\n"
             "                   from 3dZeropad match the spatial 'extents' of\n"
             "                   mset (cf. 3dinfo output) as much as possible,\n"
             "                   by adding/subtracting slices as needed.\n"
             "                * you can't use -I,-S,..., or -mm with -master\n"
             "\n"
             " -prefix ppp = write result into dataset with prefix 'ppp'\n"
             "                 [default = 'zeropad']\n"
             "\n"
             "Nota Bene:\n"
             " * You can use negative values of n to cut planes off the edges\n"
             "     of a dataset.  At least one plane must be added/removed\n"
             "     or the program won't do anything.\n"
             " * Anat parent and Talairach markers are NOT preserved in the\n"
             "     new dataset.\n"
#if 0
             " * If the old dataset has z-slice-dependent time offsets, and\n"
             "     if new z-planes are added, all the slice-dependent time\n"
             "     offsets will be removed.\n"
#else
             " * If the old dataset has z-slice-dependent time offsets, and\n"
             "     if new (zero filled) z-planes are added, the time offsets\n"
             "     of the new slices will be set to zero.\n"
#endif
             " * You can use program '3dinfo' to find out how many planes\n"
             "     a dataset has in each direction.\n"
             " * Program works for byte-, short-, float-, and complex-valued\n"
             "     datasets.\n"
             " * You can use a sub-brick selector on the input dataset.\n"
             " * 3dZeropad won't overwrite an existing dataset (I hope).\n"
             "\n"
             " Author: RWCox - July 2000\n"
           ) ;
      exit(0) ;
   }

   mainENTRY("3dZeropad main"); machdep(); AFNI_logger("3dZeropad",argc,argv);
   PRINT_VERSION("3dZeropad") ;

   /*-- read command line options --*/

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

      /*- -I, -S, etc. -*/

      if( strlen(argv[iarg]) == 2 ){
         switch( argv[iarg][1] ){
            case 'I': add_I = (int) strtod(argv[++iarg],NULL) ; break ;
            case 'S': add_S = (int) strtod(argv[++iarg],NULL) ; break ;
            case 'A': add_A = (int) strtod(argv[++iarg],NULL) ; break ;
            case 'P': add_P = (int) strtod(argv[++iarg],NULL) ; break ;
            case 'L': add_L = (int) strtod(argv[++iarg],NULL) ; break ;
            case 'R': add_R = (int) strtod(argv[++iarg],NULL) ; break ;

            /* 07 Feb 2001: slice-direction is special */

            case 'z':
            case 'Z': add_z = (int) strtod(argv[++iarg],NULL) ; break ;

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

         if( mset != NULL ){
           fprintf(stderr,"** 3dZeropad: Can't use %s with -master!\n",argv[iarg-1]) ;
           exit(1) ;
         }

         iarg++ ; continue ;  /* skip to next argument */
      }

      /*- -RL, -AP, -IS [23 Mar 2004] -*/

      if( strcmp(argv[iarg],"-RL") == 0 || strcmp(argv[iarg],"-LR") == 0 ){
        if( add_R || add_L || mset != NULL ){
          fprintf(stderr,"** 3dZeropad: Can't use -RL with -R, -L, or -master!\n");
          exit(1) ;
        }
        RLsiz = (int) strtod(argv[++iarg],NULL) ;
        if( RLsiz < 1 ){
          fprintf(stderr,"** 3dZeropad: value after -RL is illegal!\n") ;
          exit(1) ;
        }
        iarg++ ; continue ;
      }

      if( strcmp(argv[iarg],"-AP") == 0 || strcmp(argv[iarg],"-PA") == 0 ){
        if( add_A || add_P || mset != NULL ){
          fprintf(stderr,"** 3dZeropad: Can't use -AP with -A, -P, or -master!\n");
          exit(1) ;
        }
        APsiz = (int) strtod(argv[++iarg],NULL) ;
        if( APsiz < 1 ){
          fprintf(stderr,"** 3dZeropad: value after -AP is illegal!\n") ;
          exit(1) ;
        }
        iarg++ ; continue ;
      }

      if( strcmp(argv[iarg],"-IS") == 0 || strcmp(argv[iarg],"-SI") == 0 ){
        if( add_S || add_I || mset != NULL ){
          fprintf(stderr,"** 3dZeropad: Can't use -IS with -I, -S, or -master!\n");
          exit(1) ;
        }
        ISsiz = (int) strtod(argv[++iarg],NULL) ;
        if( ISsiz < 1 ){
          fprintf(stderr,"** 3dZeropad: value after -IS is illegal!\n") ;
          exit(1) ;
        }
        iarg++ ; continue ;
      }

      /*- -mm -*/

      if( strcmp(argv[iarg],"-mm") == 0 ){
         if( mset != NULL ){
           fprintf(stderr,"** 3dZeropad: Can't use %s with -master!\n",argv[iarg]) ;
           exit(1) ;
         }
         mm_flag = 1 ;
         iarg++ ; continue ;
      }

      /*- -prefix -*/

      if( strcmp(argv[iarg],"-prefix") == 0 ){
         prefix = argv[++iarg] ;
         if( !THD_filename_ok(prefix) ){
            fprintf(stderr,"** 3dZeropad: Illegal string after -prefix!\n"); exit(1) ;
         }
         iarg++ ; continue ;
      }

      /*-- -master [14 May 2002] --*/

      if( strcmp(argv[iarg],"-master") == 0 ){
        if( add_I || add_S || add_A || mm_flag ||
            add_P || add_R || add_L || add_z   ||
            RLsiz || APsiz || ISsiz              ){

          fprintf(stderr,"** 3dZeropad: Can't use -master with -I,-S,-A,-P,-R,-L, or -mm!\n");
          exit(1) ;
        }
        if( mset != NULL ){
          fprintf(stderr,"** 3dZeropad: Can't use -master twice!\n"); exit(1);
        }

        mset = THD_open_dataset( argv[++iarg] ) ;
        if( !ISVALID_DSET(mset) ){
          fprintf(stderr,"** 3dZeropad: Can't open -master %s\n",argv[iarg]); exit(1);
        }
         iarg++ ; continue ;
      }

      /*- what the hell? -*/

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

   /*- check to see if the user asked for something, anything -*/

   if( mset == NULL ){
    if( add_I==0 && add_S==0 && add_P==0 &&
        add_A==0 && add_L==0 && add_R==0 && add_z==0 &&
        RLsiz==0 && APsiz==0 && ISsiz==0               ){

      fprintf(stderr,"++ 3dZeropad: All inputs are zero? Making a copy!\n") ;
    }
   }

   /* check for conflicts [23 Mar 2004] */

   if( RLsiz > 0 && (add_R || add_L || add_z) ){
     fprintf(stderr,"** 3dZeropad: Can't use -R or -L or -z with -RL!\n"); exit(1);
   }
   if( APsiz > 0 && (add_A || add_P || add_z) ){
     fprintf(stderr,"** 3dZeropad: Can't use -A or -P or -z with -AP!\n"); exit(1);
   }
   if( ISsiz > 0 && (add_I || add_S || add_z) ){
     fprintf(stderr,"** 3dZeropad: Can't use -I or -S or -z with -IS!\n"); exit(1);
   }

   /*-- read the input dataset --*/

   if( iarg >= argc ){
      fprintf(stderr,"** 3dZeropad: No input dataset on command line!\n"); exit(1);
   }

#if 0
   if( strncmp(argv[iarg],"3dcalc(",7) == 0 ){
      fprintf(stderr,"** 3dZeropad: Can't use '3dcalc()' input datasets here!\n"); exit(1);
   }
#endif

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

#if 0
   if( DSET_IS_MASTERED(inset) ){
      fprintf(stderr,"** 3dZeropad: Can't use partial datasets!\n"); exit(1);
   }
#endif

   /*-- 14 May 2002: use master dataset now? --*/

   if( mset != NULL ){
     THD_dataxes *max=mset->daxes, *iax=inset->daxes ;
     int nerr=0 ;
     float mxbot,mybot,mzbot , mxtop,mytop,mztop , mdx,mdy,mdz ;
     float ixbot,iybot,izbot , ixtop,iytop,iztop , idx,idy,idz ;
     int   mnx,mny,mnz , inx,iny,inz ;
     int   add_xb,add_xt , add_yb,add_yt , add_zb,add_zt ;

     /* check if datasets are oriented the same */

     if( max->xxorient != iax->xxorient ||
         max->yyorient != iax->yyorient ||
         max->zzorient != iax->zzorient   ){

       fprintf(stderr,"** 3dZeropad: Master and Input datasets not oriented the same!\n");
       nerr++ ;
     }

     /* check if datasets have same voxel dimensions */

     mdx = max->xxdel ; mdy = max->yydel ; mdz = max->zzdel ;
     idx = iax->xxdel ; idy = iax->yydel ; idz = iax->zzdel ;
     mnx = max->nxx   ; mny = max->nyy   ; mnz = max->nzz   ;
     inx = iax->nxx   ; iny = iax->nyy   ; inz = iax->nzz   ;

     if( fabs(mdx-idx) > 0.01*fabs(mdx) ||
         fabs(mdy-idy) > 0.01*fabs(mdy) ||
         fabs(mdz-idz) > 0.01*fabs(mdz)   ){

       fprintf(stderr,"** 3dZeropad: Master and Input datasets don't have same voxel size!\n");
       nerr++ ;
     }

     if( nerr ) exit(1) ;

     /* calculate coords at top and bottom of each dataset */

     mxbot = max->xxorg ; mxtop = mxbot + mnx*mdx ;
     mybot = max->yyorg ; mytop = mybot + mny*mdy ;
     mzbot = max->zzorg ; mztop = mzbot + mnz*mdz ;

     ixbot = iax->xxorg ; ixtop = ixbot + inx*idx ;
     iybot = iax->yyorg ; iytop = iybot + iny*idy ;
     izbot = iax->zzorg ; iztop = izbot + inz*idz ;

     /* calculate amount to add/trim at each face */

     add_xb = (int) rint((ixbot-mxbot)/idx) ;
     add_xt = (int) rint((mxtop-ixtop)/idx) ;
     add_yb = (int) rint((iybot-mybot)/idy) ;
     add_yt = (int) rint((mytop-iytop)/idy) ;
     add_zb = (int) rint((izbot-mzbot)/idz) ;
     add_zt = (int) rint((mztop-iztop)/idz) ;

     /* map trims from x,y,z to RL,AP,IS coords */

     switch( iax->xxorient ){
       case ORI_R2L_TYPE: add_R = add_xb ; add_L = add_xt ; break ;
       case ORI_L2R_TYPE: add_L = add_xb ; add_R = add_xt ; break ;
       case ORI_I2S_TYPE: add_I = add_xb ; add_S = add_xt ; break ;
       case ORI_S2I_TYPE: add_S = add_xb ; add_I = add_xt ; break ;
       case ORI_A2P_TYPE: add_A = add_xb ; add_P = add_xt ; break ;
       case ORI_P2A_TYPE: add_P = add_xb ; add_A = add_xt ; break ;
     }

     switch( iax->yyorient ){
       case ORI_R2L_TYPE: add_R = add_yb ; add_L = add_yt ; break ;
       case ORI_L2R_TYPE: add_L = add_yb ; add_R = add_yt ; break ;
       case ORI_I2S_TYPE: add_I = add_yb ; add_S = add_yt ; break ;
       case ORI_S2I_TYPE: add_S = add_yb ; add_I = add_yt ; break ;
       case ORI_A2P_TYPE: add_A = add_yb ; add_P = add_yt ; break ;
       case ORI_P2A_TYPE: add_P = add_yb ; add_A = add_yt ; break ;
     }

     switch( iax->zzorient ){
       case ORI_R2L_TYPE: add_R = add_zb ; add_L = add_zt ; break ;
       case ORI_L2R_TYPE: add_L = add_zb ; add_R = add_zt ; break ;
       case ORI_I2S_TYPE: add_I = add_zb ; add_S = add_zt ; break ;
       case ORI_S2I_TYPE: add_S = add_zb ; add_I = add_zt ; break ;
       case ORI_A2P_TYPE: add_A = add_zb ; add_P = add_zt ; break ;
       case ORI_P2A_TYPE: add_P = add_zb ; add_A = add_zt ; break ;
     }

     fprintf(stderr,"++ 3dZeropad -master => -I %d -S %d -A %d -P %d -R %d -L %d\n",
             add_I,add_S,add_A,add_P,add_R,add_L ) ;

     DSET_delete(mset) ;
   }

   /*-- 07 Feb 2001: if -z was used, fix that now --*/

   if( add_z != 0 ){
      switch( inset->daxes->zzorient ){
         case ORI_R2L_TYPE:
         case ORI_L2R_TYPE:
            if( add_R != 0 && add_R != add_z ) fprintf(stderr,"++ 3dZeropad: -z overrides -R\n");
            if( add_L != 0 && add_L != add_z ) fprintf(stderr,"++ 3dZeropad: -z overrides -L\n");
            add_R = add_L = add_z ;
         break ;

         case ORI_P2A_TYPE:
         case ORI_A2P_TYPE:
            if( add_P != 0 && add_P != add_z ) fprintf(stderr,"++ 3dZeropad: -z overrides -P\n");
            if( add_A != 0 && add_A != add_z ) fprintf(stderr,"++ 3dZeropad: -z overrides -A\n");
            add_P = add_A = add_z ;
         break ;

         case ORI_I2S_TYPE:
         case ORI_S2I_TYPE:
            if( add_I != 0 && add_I != add_z ) fprintf(stderr,"++ 3dZeropad: -z overrides -I\n");
            if( add_I != 0 && add_S != add_z ) fprintf(stderr,"++ 3dZeropad: -z overrides -S\n");
            add_I = add_S = add_z ;
         break ;
      }
   }

   /*-- 23 Mar 2004: expand/contract if ordered --*/

   if( RLsiz > 0 ){
     int nold=0 ;
          if( inset->daxes->xxorient == ORI_R2L_TYPE || inset->daxes->xxorient == ORI_L2R_TYPE )
       nold = inset->daxes->nxx ;
     else if( inset->daxes->yyorient == ORI_R2L_TYPE || inset->daxes->yyorient == ORI_L2R_TYPE )
       nold = inset->daxes->nyy ;
     else if( inset->daxes->zzorient == ORI_R2L_TYPE || inset->daxes->zzorient == ORI_L2R_TYPE )
       nold = inset->daxes->nzz ;
     if( nold > 0 ){
       add_R = (RLsiz-nold) / 2 ;
       add_L = RLsiz-(nold+add_R) ;
     }
   }

   if( APsiz > 0 ){
     int nold=0 ;
          if( inset->daxes->xxorient == ORI_A2P_TYPE || inset->daxes->xxorient == ORI_P2A_TYPE )
       nold = inset->daxes->nxx ;
     else if( inset->daxes->yyorient == ORI_A2P_TYPE || inset->daxes->yyorient == ORI_P2A_TYPE )
       nold = inset->daxes->nyy ;
     else if( inset->daxes->zzorient == ORI_A2P_TYPE || inset->daxes->zzorient == ORI_P2A_TYPE )
       nold = inset->daxes->nzz ;
     if( nold > 0 ){
       add_A = (APsiz-nold) / 2 ;
       add_P = APsiz-(nold+add_A) ;
     }
   }

   if( ISsiz > 0 ){
     int nold=0 ;
          if( inset->daxes->xxorient == ORI_I2S_TYPE || inset->daxes->xxorient == ORI_S2I_TYPE )
       nold = inset->daxes->nxx ;
     else if( inset->daxes->yyorient == ORI_I2S_TYPE || inset->daxes->yyorient == ORI_S2I_TYPE )
       nold = inset->daxes->nyy ;
     else if( inset->daxes->zzorient == ORI_I2S_TYPE || inset->daxes->zzorient == ORI_S2I_TYPE )
       nold = inset->daxes->nzz ;
     if( nold > 0 ){
       add_I = (ISsiz-nold) / 2 ;
       add_S = ISsiz-(nold+add_I) ;
     }
   }

   /*-- 04 Oct 2000: all the real work is now in thd_zeropad.c --*/

   flag = ZPAD_PURGE ;
   if( mm_flag ) flag |= ZPAD_MM ;

   outset = THD_zeropad( inset ,
                         add_I, add_S, add_A, add_P, add_L, add_R,
                         prefix , flag ) ;

   if( THD_deathcon() && THD_is_file(DSET_HEADNAME(outset)) ){
      fprintf(stderr,
              "** 3dZeropad: output file %s already exists - FATAL ERROR!\n",
              DSET_HEADNAME(outset) ) ;
      exit(1) ;
   }

   if( outset == NULL ){
      fprintf(stderr,"** 3dZeropad: Some error occurred in processing!\n") ;
      exit(1) ;
   }

   tross_Copy_History( inset , outset ) ;             /* 31 Jan 2001 - RWCox */
   tross_Make_History( "3dZeropad" , argc,argv , outset ) ;

   DSET_write(outset) ;
   fprintf(stderr,"++ output dataset: %s\n",DSET_BRIKNAME(outset)) ;
   exit(0) ;
}


syntax highlighted by Code2HTML, v. 0.9.1