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

/*---------------------------------------------------------------------------*/
/*
  This program extracts 2D image files from an AFNI 3D dataset.

  File:    from3d.c
  Author:  B. Douglas Ward
  Date:    30 August 1996

  Mod:     Added call to AFNI_logger.
  Date:    15 August 2001

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

#define PROGRAM_NAME "from3d"                        /* name of this program */
#define PROGRAM_AUTHOR "B. Douglas Ward"                   /* program author */
#define PROGRAM_INITIAL "30 August 1996"  /* date of initial program release */
#define PROGRAM_LATEST "15 August 2001"     /* date of last program revision */

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

#include "mrilib.h"

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

void Syntax(void)
{
   printf(
    "Usage:   from3d [options] -input fname -prefix rname\n"
    "Purpose: Extract 2D image files from a 3D AFNI dataset.\n"
    "Options:\n"
    "-v             Print out verbose information during the run.\n"
    "-nsize         Adjust size of 2D data file to be NxN, by padding\n"
    "                 with zeros, where N is a power of 2.\n"
    "-raw           Write images in 'raw' format (just the data bytes)\n"
    "                 N.B.: there will be no header information saying\n"
    "                       what the image dimensions are - you'll have\n"
    "                       to get that information from the x and y\n"
    "                       axis information output by 3dinfo.\n"
    "-float         Write images as floats, no matter what they are in\n"
    "                 the dataset itself.\n"
    "-zfirst num    Set 'num' = number of first z slice to be extracted.\n"
    "                 (default = 1)\n"
    "-zlast num     Set 'num' = number of last z slice to be extracted.\n"
    "                 (default = largest)\n"
    "-tfirst num    Set 'num' = number of first time slice to be extracted.\n"
    "                 (default = 1)\n"
    "-tlast num     Set 'num' = number of last time slice to be extracted.\n"
    "                 (default = largest)\n"
    "-input fname   Read 3D dataset from file 'fname'.\n"
    "                 'fname' may include a sub-brick selector list.\n"
    "-prefix rname  Write 2D images using prefix 'rname'.\n"
    "\n"
    "               (-input and -prefix are non-optional options: they)\n"
    "               (must be present or the program will not execute. )\n"
    "\n"
    "N.B.: * Image data is extracted directly from the dataset bricks.\n"
    "         If a brick has a floating point scaling factor, it will NOT\n"
    "         be applied.\n"
    "      * Images are extracted parallel to the xy-plane of the dataset\n"
    "         orientation (which can be determined by program 3dinfo).\n"
    "         This is the order in which the images were input to the\n"
    "         dataset originally, via to3d.\n"
    "      * If either of these conditions is unacceptable, you can also\n"
    "         try to use the Save:bkg function from an AFNI image window.\n"
   ) ;
   exit(0) ;
}

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

void F3D_initialize_user_data ( int Argc, char * Argv[],
   RwcBoolean * verbose, RwcBoolean * nsize, RwcBoolean * raw, RwcBoolean * do_floats ,
   int * zfirst, int * zlast, int * tfirst, int * tlast,
   char * input_filename, char * prefix_filename )
{
   const int BIGNUMBER = 100000;
   int nopt;
   float ftemp;

   /*----- Does user request help menu? -----*/
   if (Argc < 2 || strncmp(Argv[1],"-help",4) == 0) Syntax();

   /*----- Add to program log -----*/
   machdep(); AFNI_logger (PROGRAM_NAME,Argc,Argv); 

   /* --- set default values --- */
   *verbose = FALSE;
   *nsize = FALSE;
   *raw   = FALSE;      /* 05 Jan 2000 */
   *do_floats = FALSE ; /* 05 Jan 2000 */
   *zfirst = 1;
   *zlast = BIGNUMBER;
   *tfirst = 1;
   *tlast = BIGNUMBER;
   strcpy(input_filename, "");
   strcpy(prefix_filename, "");


   /* --- scan options --- */
   nopt = 1 ;
   while ( nopt < Argc && Argv[nopt][0] == '-' )
   {

      /* --- verbose option --- */
      if ( strncmp(Argv[nopt],"-v",2) == 0 )
      {
         *verbose = TRUE;
         nopt++ ;
         continue;
      }

      /* --- nsize option --- */
      if ( strncmp(Argv[nopt],"-nsize",4) == 0 )
      {
         *nsize = TRUE;
         nopt++ ;
         continue;
      }

      /* --- raw option [05 Jan 2000]--- */
      if ( strncmp(Argv[nopt],"-raw",4) == 0 )
      {
         *raw = TRUE;
         nopt++ ;
         continue;
      }

      /* --- float option [05 Jan 2000]--- */
      if ( strncmp(Argv[nopt],"-float",4) == 0 )
      {
         *do_floats = TRUE;
         nopt++ ;
         continue;
      }

      /* --- zfirst option --- */
      if ( strncmp(Argv[nopt],"-zfirst",4) == 0 )
      {
         if( ++nopt >= Argc ) ERROR_exit("-zfirst needs an argument") ;
         ftemp = strtod( Argv[nopt] , NULL ) ;
         *zfirst = (int) ftemp ;
         nopt++ ;
         continue ;
      }

      /* --- zlast option --- */
      if ( strncmp(Argv[nopt],"-zlast",4) == 0 )
      {
         if( ++nopt >= Argc ) ERROR_exit("-zlast needs an argument") ;
         ftemp = strtod( Argv[nopt] , NULL ) ;
         *zlast = (int) ftemp ;
         nopt++ ;
         continue ;
      }

      /* --- tfirst option --- */
      if ( strncmp(Argv[nopt],"-tfirst",4) == 0 )
      {
         if( ++nopt >= Argc ) ERROR_exit("-tfirst needs an argument") ;
         ftemp = strtod( Argv[nopt] , NULL ) ;
         *tfirst = (int) ftemp ;
         nopt++ ;
         continue ;
      }

      /* --- tlast option --- */
      if ( strncmp(Argv[nopt],"-tlast",4) == 0 )
      {
         if( ++nopt >= Argc ) ERROR_exit("-tlast needs an argument") ;
         ftemp = strtod( Argv[nopt] , NULL ) ;
         *tlast = (int) ftemp ;
         nopt++ ;
         continue ;
      }

      /* --- input file name --- */
      if ( strncmp(Argv[nopt],"-input",4) == 0 )
      {
         if ( ++nopt >= Argc ) ERROR_exit("-input needs a name") ;
         strcpy ( input_filename , Argv[nopt] ) ;
         nopt++ ; continue ;
      }

      /* --- prefix name --- */
      if ( strncmp(Argv[nopt],"-prefix",4) == 0 )
      {
         if ( ++nopt >= Argc ) ERROR_exit("-prefix needs a name") ;
         strcpy ( prefix_filename , Argv[nopt] ) ;
         nopt++ ; continue ;
      }

      /* --- exception --- */
      ERROR_exit("Illegal input");

   }  /* nopt */

   /* --- check for valid inputs --- */
   if (*zfirst > *zlast)
      ERROR_exit ("Cannot have zfirst > zlast");
   if (*tfirst > *tlast)
      ERROR_exit ("Cannot have tfirst > tlast");
   if (!strcmp(input_filename,""))
      ERROR_exit ("Must specify input file name. ");
   if (!strcmp(prefix_filename,""))
      ERROR_exit ("Must specify prefix file name.");

   return;
}

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

int main( int argc , char * argv[] )
{
   /* --- variable declarations --- */
   THD_3dim_dataset * dset ;
   THD_diskptr * dskptr;
   int nx, ny, nz, nv;
   RwcBoolean verbose, nsize, raw, do_floats;
   int ok;
   MRI_IMAGE * im, * im2d, * tim2d , * fim2d ;
   MRI_TYPE kind;
   int ibr, iz, count;
   int zfirst, zlast, tfirst, tlast;
   char input_filename[THD_MAX_NAME],
        prefix_filename[THD_MAX_NAME],
        output_filename[THD_MAX_NAME],
        str[THD_MAX_NAME];

  
  /*----- Identify software -----*/
#if 0
  printf ("\n\n");
  printf ("Program:          %s \n", PROGRAM_NAME);
  printf ("Author:           %s \n", PROGRAM_AUTHOR); 
  printf ("Initial Release:  %s \n", PROGRAM_INITIAL);
  printf ("Latest Revision:  %s \n", PROGRAM_LATEST);
  printf ("\n");
#endif

   PRINT_VERSION("from3d") ; AUTHOR(PROGRAM_AUTHOR) ; mainENTRY("from3d main") ; machdep() ;

   /* --- get user command line inputs --- */
   F3D_initialize_user_data (argc, argv,
      &verbose, &nsize,&raw,&do_floats,
      &zfirst, &zlast, &tfirst, &tlast,
      input_filename, prefix_filename );

   /* --- open 3D dataset --- */
   dset = THD_open_dataset( input_filename ) ;
   if( dset == NULL )  ERROR_exit ("Unable to open input file") ;
   if ( verbose )  printf("\n" "3D Dataset File:    %s\n" , input_filename ) ;

   /* --- load data block --- */
   ok = THD_load_datablock( dset->dblk );
   if ( !ok )  ERROR_exit ("Unable to load data block") ;

   /* --- get data dimensions --- */
   dskptr = dset->dblk->diskptr;
   nx = dskptr->dimsizes[0];
   ny = dskptr->dimsizes[1];
   nz = dskptr->dimsizes[2];
   nv = dskptr->nvals;
   if ( verbose )
      printf ("nx = %d  ny = %d  nz = %d  nv = %d\n",   nx, ny, nz, nv);

   /* --- check for valid user inputs --- */
   if (zfirst < 1) zfirst = 1;
   if (zlast > nz) zlast = nz;
   if (tfirst < 1) tfirst = 1;
   if (tlast > nv) tlast = nv;
   if (zfirst > nz)  ERROR_exit ("No data selected -- zfirst too large.");
   if (zlast < 1)    ERROR_exit ("No data selected -- zlast too small.");
   if (tfirst > nv)  ERROR_exit ("No data selected -- tfirst too large.");
   if (tlast < 1)    ERROR_exit ("No data selected -- tlast too small.");

   /* --- get data type --- */
   kind = IMAGE_IN_IMARR ( dset->dblk->brick, 0 ) -> kind;
   if ( verbose ){
      printf ("Input data type : %s\n", MRI_TYPE_name[kind]);
      if( do_floats && kind != MRI_float )
         printf ("Output data type: float\n") ;
   }

   /* --- create 2D data pointer --- */
   im2d = mri_new_vol_empty ( nx, ny, 1, kind );

   count = 0;
   for ( ibr = tfirst-1 ; ibr < tlast ; ibr++ )
   {
      for ( iz = zfirst-1 ; iz < zlast ; iz++ )
      {
         /* --- set 2D data pointer into 3D dataset --- */
         im = IMAGE_IN_IMARR ( dset->dblk->brick, ibr );
         switch ( kind )
         {
            case MRI_byte :
               mri_set_data_pointer(im2d, MRI_BYTE_PTR(im) + iz*nx*ny) ;
            break;
            case MRI_short :
               mri_set_data_pointer(im2d, MRI_SHORT_PTR(im) + iz*nx*ny) ;
            break;
            case MRI_int :
               mri_set_data_pointer(im2d, MRI_INT_PTR(im) + iz*nx*ny) ;
            break;
            case MRI_float :
               mri_set_data_pointer(im2d, MRI_FLOAT_PTR(im) + iz*nx*ny) ;
            break;
            case MRI_double :
               mri_set_data_pointer(im2d, MRI_DOUBLE_PTR(im) + iz*nx*ny) ;
            break;
            case MRI_complex :
               mri_set_data_pointer(im2d, MRI_COMPLEX_PTR(im) + iz*nx*ny) ;
            break;
            case MRI_rgb :
               mri_set_data_pointer(im2d, MRI_RGB_PTR(im) + 3*iz*nx*ny) ;
            break;
            default :
               ERROR_exit ("Illegal data type encountered.");
         }

         /* --- create 2D data file name --- */
         strcpy ( output_filename, prefix_filename );
         if ( nv > 1 )
            sprintf ( str, "%02d.%04d", iz+1, ibr+1 );
         else
            if ( nz > 999 )
               sprintf ( str, ".%04d", iz+1 );
            else
               sprintf ( str, ".%03d", iz+1 );
         strcat ( output_filename, str );

         /* --- write 2D data file --- */
         if ( verbose )
            printf ( "Writing%s2D image: %s\n",
                      (raw) ? " raw " : " " , output_filename );

         fim2d = (nsize) ? mri_nsize(im2d) : im2d ;

         if( do_floats ){
            tim2d = mri_to_float(fim2d) ;
            if( fim2d != im2d ) mri_free(fim2d) ;
            fim2d = tim2d ;
         }

         ok = (raw)? mri_write_raw( output_filename, fim2d )
                   : mri_write    ( output_filename, fim2d ) ;

         if( fim2d != im2d ) mri_free(fim2d) ;

         count += ok ;

      }  /* --- iz --- */
   }  /* --- ibr --- */

   if ( verbose )  printf ("Created %d 2D image files.\n", count);

   /* --- clean up --- */
   free ( im2d );
   THD_delete_3dim_dataset( dset , False ) ;

   exit(0) ;
}
