#include "mrilib.h"
#include "thd.h"

/*******************************************************************/
/******** 03 Dec 2003: Read an MPEG file as an AFNI dataset ********/
/*******************************************************************/

/*-----------------------------------------------------------------*/
/*! Open an MPEG file as an unpopulated AFNI dataset.
    It will be populated in THD_load_mpeg().
-------------------------------------------------------------------*/

THD_3dim_dataset * THD_open_mpeg( char *hname )
{
   int nim , ii , datum_type ;
   MRI_IMARR *imar ;
   MRI_IMAGE *im ;
   char *eee ;
   THD_3dim_dataset *dset=NULL ;
   char prefix[THD_MAX_PREFIX] , *ppp ;
   THD_ivec3 nxyz , orixyz ;
   THD_fvec3 dxyz , orgxyz ;
   int iview ;
   int   nx,ny,nz,nt ;
   float dx,dy,dz,dt ;


ENTRY("THD_open_mpeg") ;

   /*-- count slices in the file --*/

   imar = mri_read_mpeg( hname ) ;
   if( imar == NULL ) RETURN(NULL) ;
   nim = IMARR_COUNT(imar) ;

   /*-- get data type for each voxel --*/

   im         = IMARR_SUBIM(imar,0) ;
   datum_type = im->kind ;

   /*-- compute dimensions of images, and number of images --*/

   nx = im->nx ;
   ny = im->ny ;
   DESTROY_IMARR(imar) ;
   if( nx < 2 || ny < 2 ) RETURN(NULL) ;

   eee = getenv("AFNI_MPEG_DATASETS") ;
   if( eee == NULL ) eee = "SPACE" ;
   switch( toupper(*eee) ){
     default:
     case 'T': nz = 1   ; nt = nim ; break ;
     case 'S': nz = nim ; nt = 1   ; break ;
   }

   /*-- voxel sizes --*/

   dx = dy = dz = dt = 1.0 ;

   /*-- make a dataset --*/

   dset = EDIT_empty_copy(NULL) ;

   dset->idcode.str[0] = 'M' ;  /* overwrite 1st 3 bytes */
   dset->idcode.str[1] = 'P' ;
   dset->idcode.str[2] = 'G' ;

   MCW_hash_idcode( hname , dset ) ;  /* 06 May 2005 */

   ppp = THD_trailname(hname,0) ;                   /* strip directory */
   MCW_strncpy( prefix , ppp , THD_MAX_PREFIX ) ;   /* to make prefix */

   nxyz.ijk[0] = nx ; dxyz.xyz[0] = dx ;  /* setup axes lengths and voxel sizes */
   nxyz.ijk[1] = ny ; dxyz.xyz[1] = dy ;
   nxyz.ijk[2] = nz ; dxyz.xyz[2] = dz ;

   /*-- set orientation --*/

   { char *ori = "LAI" ;
     int oxx,oyy,ozz ;
     if( ori == NULL || strlen(ori) < 3 ) ori = "LAI"; /* set default LPI */

     oxx = ORCODE(ori[0]); oyy = ORCODE(ori[1]); ozz = ORCODE(ori[2]);
     if( !OR3OK(oxx,oyy,ozz) ){
       oxx = ORI_L2R_TYPE; oyy = ORI_A2P_TYPE; ozz = ORI_I2S_TYPE; /* LAI? */
     }

     orixyz.ijk[0] = oxx ;
     orixyz.ijk[1] = oyy ;
     orixyz.ijk[2] = ozz ;
   }

   /*-- origin of coordinates --*/

   orgxyz.xyz[0] = -0.5 * (nx-1) * dx ;
   orgxyz.xyz[1] = -0.5 * (ny-1) * dy ;
   orgxyz.xyz[2] = -0.5 * (nz-1) * dz ;

   iview = VIEW_ORIGINAL_TYPE ;

   /* 10 Oct 2002: change voxel size signs, if axis orientation is negative */
   /*              [above, we assumed that axes were oriented in - to + way] */

   if( ORIENT_sign[orixyz.ijk[0]] == '-' ){
     dxyz.xyz[0]   = -dxyz.xyz[0]   ;
     orgxyz.xyz[0] = -orgxyz.xyz[0] ;
   }

   if( ORIENT_sign[orixyz.ijk[1]] == '-' ){
     dxyz.xyz[1]   = -dxyz.xyz[1]   ;
     orgxyz.xyz[1] = -orgxyz.xyz[1] ;
   }

   if( ORIENT_sign[orixyz.ijk[2]] == '-' ){
     dxyz.xyz[2]   = -dxyz.xyz[2]   ;
     orgxyz.xyz[2] = -orgxyz.xyz[2] ;
   }

   /*-- actually send the values above into the dataset header --*/

   EDIT_dset_items( dset ,
                      ADN_prefix      , prefix ,
                      ADN_datum_all   , datum_type ,
                      ADN_nxyz        , nxyz ,
                      ADN_xyzdel      , dxyz ,
                      ADN_xyzorg      , orgxyz ,
                      ADN_xyzorient   , orixyz ,
                      ADN_malloc_type , DATABLOCK_MEM_MALLOC ,
                      ADN_nvals       , nt ,
                      ADN_type        , HEAD_ANAT_TYPE ,
                      ADN_view_type   , iview ,
                      ADN_func_type   , ANAT_MRAN_TYPE ,
                    ADN_none ) ;

   if( nt > 1 )              /** pretend it is 3D+time **/
      EDIT_dset_items( dset ,
                         ADN_func_type, ANAT_EPI_TYPE ,
                         ADN_ntt      , nt ,
                         ADN_ttorg    , 0.0 ,
                         ADN_ttdel    , dt ,
                         ADN_ttdur    , 0.0 ,
                         ADN_tunits   , UNITS_SEC_TYPE ,
                       ADN_none ) ;

   /*-- flag to read data from disk using MPEG mode --*/

   dset->dblk->diskptr->storage_mode = STORAGE_BY_MPEG ;
   strcpy( dset->dblk->diskptr->brick_name , hname ) ;

   RETURN(dset) ;
}

/*---------------------------------------------------------------------*/
/*! Load an MPEG dataset from disk.
-----------------------------------------------------------------------*/

void THD_load_mpeg( THD_datablock *dblk )
{
   THD_diskptr *dkptr ;
   int nx,ny,nz,nv , nxy,nxyz,nxyzv , ibr,nbad , nbar ;
   void *ptr ;
   MRI_IMARR *imar ;
   MRI_IMAGE *im ;
   byte *bim , *bar ;

ENTRY("THD_load_mpeg") ;

   /*-- check inputs --*/

   if( !ISVALID_DATABLOCK(dblk)                       ||
       dblk->diskptr->storage_mode != STORAGE_BY_MPEG ||
       dblk->brick == NULL                              ) EXRETURN ;

   dkptr = dblk->diskptr ;

   imar = mri_read_mpeg( dkptr->brick_name ) ;
   if( imar == NULL ) EXRETURN ;

   /*-- allocate space for data --*/

   nx = dkptr->dimsizes[0] ;
   ny = dkptr->dimsizes[1] ;  nxy   = nx * ny   ;
   nz = dkptr->dimsizes[2] ;  nxyz  = nxy * nz  ;
   nv = dkptr->nvals       ;  nxyzv = nxyz * nv ;

   dblk->malloc_type = DATABLOCK_MEM_MALLOC ;

   /*-- malloc space for each brick separately --*/

   for( nbad=ibr=0 ; ibr < nv ; ibr++ ){
     if( DBLK_ARRAY(dblk,ibr) == NULL ){
       ptr = AFMALL(void, DBLK_BRICK_BYTES(dblk,ibr) ) ;
       mri_fix_data_pointer( ptr ,  DBLK_BRICK(dblk,ibr) ) ;
       if( ptr == NULL ) nbad++ ;
     }
   }

   /*-- if couldn't get them all, take our ball and go home in a snit --*/

   if( nbad > 0 ){
     fprintf(stderr,
             "\n** failed to malloc %d MPEG bricks out of %d\n\a",nbad,nv);
     for( ibr=0 ; ibr < nv ; ibr++ ){
       if( DBLK_ARRAY(dblk,ibr) != NULL ){
         free(DBLK_ARRAY(dblk,ibr)) ;
         mri_fix_data_pointer( NULL , DBLK_BRICK(dblk,ibr) ) ;
       }
     }
     DESTROY_IMARR(imar) ; EXRETURN ;
   }

   /*-- load data from image array into sub-brick arrays! --*/

   nbar = mri_datum_size( DBLK_BRICK_TYPE(dblk,0) ) * nx*ny ;
   if( nv == 1 ){                   /* all data goes into 1 sub-brick */
     bar = DBLK_ARRAY(dblk,0) ;
     for( ibr=0 ; ibr < nz ; ibr++ ){
       im = IMARR_SUBIM(imar,ibr) ; bim = mri_data_pointer(im) ;
       memcpy( bar , bim , nbar ) ;
       bar += nbar ;
     }
   } else {                         /* each slice is a separate sub-brick */
     for( ibr=0 ; ibr < nv ; ibr++ ){
       bar = DBLK_ARRAY(dblk,ibr) ;
       im = IMARR_SUBIM(imar,ibr) ; bim = mri_data_pointer(im) ;
       memcpy( bar , bim , nbar ) ;
     }
   }

   DESTROY_IMARR(imar) ;
   EXRETURN ;
}
