#include "afni.h"

#ifndef ALLOW_PLUGINS
#  error "Plugins not properly set up -- see machdep.h"
#endif

/***********************************************************************
  Plugin to plot averages over ROIs.
************************************************************************/

static int                tsgraph_num=0 ;
static MEM_topshell_data *tsgraph_mtd=NULL ;

static void ROIPLOT_tsgraph_draw   (void) ;
static void ROIPLOT_tsgraph_mtdkill( MEM_topshell_data * mp ) ;

static char * ROIPLOT_main( PLUGIN_interface * ) ;

static char helpstring[] =
   " Purpose: Plot averages over ROIs.\n"
   "\n"
   " INPUTS\n"
   " ------\n"
   " Source: Defines where the data to be averaged over the ROIs comes from.\n"
   "   Dataset = Where to get time series values from\n"
   "   Start   = 1st sub-brick index to extract\n"
   "   Stop    = Last sub-brick index to extract\n"
   "\n"
   " Two methods are available to define the ROIs from which dataset values\n"
   " will be extracted.  Only one of these can be used at a time:\n"
   "\n"
   " Cluster: Clusters of contiguous voxels are extracted (as in 3dclust),\n"
   " -------- and these are used for the ROIs.\n"
   "   From   = Dataset to define the clusters in\n"
   "   Index  = Sub-brick index to define the clusters in\n"
   "   Thresh = Minimum value to accept in the sub-brick\n"
   "   rmm   }= Clustering radius and\n"
   "   vmul  }= minimum cluster volume\n"
   "\n"
   " Values: ROIs are defined by common values stored in a dataset, as\n"
   " ------- might be generated by the 'Draw Dataset' plugin.\n"
   "   From   = Dataset to define the ROIs\n"
   "   Index  = Sub-brick index to define the ROIs\n"
   "   Min   }= Range of values to\n"
   "   Max   }= use for the ROIS\n"
   " *** N.B.: Values selection is NOT YET IMPLEMENTED ***\n"
   "\n"
   " Author -- RW Cox - April 2002"
;

/***********************************************************************
   Set up the interface to the user
************************************************************************/


DEFINE_PLUGIN_PROTOTYPE

PLUGIN_interface * PLUGIN_init( int ncall )
{
   PLUGIN_interface * plint ;

   if( ncall > 0 ) return NULL ;  /* only one interface */

   CHECK_IF_ALLOWED("ROIPLOT","ROI Plot") ;  /* 30 Sep 2016 */

   /*-- set titles and call point --*/

   plint = PLUTO_new_interface( "ROI Plot" , "Plot Average Timeseries over ROI",
                                 helpstring ,
                                 PLUGIN_CALL_VIA_MENU ,
                                 (cptr_func *)ROIPLOT_main  ) ;

   PLUTO_short_choose(plint) ;
   PLUTO_short_number(plint) ;

   PLUTO_add_hint( plint , "Plot Average Timeseries over ROI" ) ;

   PLUTO_set_sequence( plint , "A:afniinfo:dset" ) ;

   PLUTO_set_runlabels( plint , "Plot+Keep" , "Plot+Close" ) ;  /* 04 Nov 2003 */

   /*-- first line of input --*/

   PLUTO_add_option( plint , "Source" , "Source" , TRUE ) ;
   PLUTO_add_dataset(plint , "Timeseries" ,
                                    ANAT_ALL_MASK , FUNC_ALL_MASK ,
                                    DIMEN_4D_MASK | BRICK_ALLREAL_MASK ) ;

   PLUTO_add_number( plint , "Start" , 0,99999,0 , 0    ,1 ) ;
   PLUTO_add_number( plint , "Stop"  , 0,99999,0 , 99999,1 ) ;

   /*-- second line of input --*/

   PLUTO_add_option( plint  , "Cluster" , "Cluster" , FALSE ) ;
   PLUTO_add_dataset( plint , "From" ,
                                    ANAT_ALL_MASK , FUNC_ALL_MASK ,
                                    DIMEN_ALL_MASK | BRICK_ALLREAL_MASK ) ;
   PLUTO_add_number( plint , "Index" , 0,99999,0 ,  0,1 ) ;
   PLUTO_add_number( plint , "Thresh", 0,9999 ,1 ,  1,1 ) ;
   PLUTO_add_number( plint , "rmm"   , 0,99   ,1 , 11,1 ) ;
   PLUTO_add_number( plint , "vmul"  , 0,9999,-1 , 20,1 ) ;

   /*-- third line of input --*/

   PLUTO_add_option( plint  , "Values" , "Values" , FALSE ) ;
   PLUTO_add_dataset( plint , "From" ,
                                    ANAT_ALL_MASK , FUNC_ALL_MASK ,
                                    DIMEN_ALL_MASK | BRICK_ALLREAL_MASK ) ;
   PLUTO_add_number( plint , "Index" , 0,99999,0 ,  0,1 ) ;
   PLUTO_add_number( plint , "Min"   , 0,99999,0 , 0    ,1 ) ;
   PLUTO_add_number( plint , "Max"   , 0,99999,0 , 99999,1 ) ;

   return plint ;
}

/***************************************************************************
  Main routine for this plugin (will be called from AFNI).
****************************************************************************/

static char * ROIPLOT_main( PLUGIN_interface * plint )
{
   MCW_idcode *idc ;
   THD_3dim_dataset *input_dset , *mask_dset ;
   int iv_start,iv_stop , nvox , iv_mask ;
   float thr,rmm,vmul    , dx,dy,dz ;
   int val_min , val_max , nx,ny,nz , ii,jj , nt,nc ;
   char *tag ;
   MCW_cluster_array *clustar ;
   MRI_IMAGE *flim ;
   float     *flar , **yar , *xar , xcm,ycm,zcm ;
   char      **nam_yyy ;
   MEM_plotdata * mp ;

#define MAX_NC 7

   /*--------------------------------------------------------------------*/
   /*----- Check inputs from AFNI to see if they are reasonable-ish -----*/

   if( plint == NULL )
      return "*************************\n"
             "ROIPLOT_main:  NULL input\n"
             "*************************"  ;

   /*-- read 1st line --*/

   PLUTO_next_option(plint) ;
   idc        = PLUTO_get_idcode(plint) ;
   input_dset = PLUTO_find_dset(idc) ;
   if( input_dset == NULL )
      return "*********************************\n"
             "ROIPLOT_main:  bad Source dataset\n"
             "*********************************"  ;

   iv_start = (int) PLUTO_get_number(plint) ;
   iv_stop  = (int) PLUTO_get_number(plint) ;
   if( iv_stop >= DSET_NVALS(input_dset) ) iv_stop = DSET_NVALS(input_dset)-1 ;
   if( iv_start >= iv_stop )
      return "***********************************\n"
             "ROIPLOT_main:  bad Start/Stop range\n"
             "***********************************" ;
   DSET_load(input_dset) ;
   if( DSET_ARRAY(input_dset,iv_stop) == NULL )
      return "****************************************\n"
             "ROIPLOT_main:  can't load Source dataset\n"
             "****************************************"  ;

   nx   = input_dset->daxes->nxx ; dx = fabs(input_dset->daxes->xxdel) ;
   ny   = input_dset->daxes->nyy ; dy = fabs(input_dset->daxes->yydel) ;
   nz   = input_dset->daxes->nzz ; dz = fabs(input_dset->daxes->zzdel) ;
   nvox = nx*ny*nz ;

   /*-- read next lines --*/

   tag = PLUTO_get_optiontag(plint) ;
   if( tag == NULL )
      return "***********************************"
             "ROIPLOT_main: no ROI selection made\n"
             "***********************************"   ;

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

   if( strcmp(tag,"Cluster") == 0 ){
     float *vfim ;
     MCW_cluster_array *clbig ;
     MCW_cluster *cl ;
     int ptmin ;

     idc       = PLUTO_get_idcode(plint) ;
     mask_dset = PLUTO_find_dset(idc) ;
     if( mask_dset == NULL )
       return "**********************************\n"
              "ROIPLOT_main:  bad Cluster dataset\n"
              "**********************************"  ;
     if( DSET_NVOX(mask_dset) != nvox )
       return "******************************************************\n"
              "ROIPLOT_main:  Source and Cluster datasets don't match\n"
              "******************************************************"  ;
     iv_mask = (int) PLUTO_get_number(plint) ;
     if( iv_mask >= DSET_NVALS(mask_dset) )
       return "********************************\n"
              "ROIPLOT_main:  bad Cluster index\n"
              "*********************************"  ;
     DSET_load(mask_dset) ;
     if( DSET_ARRAY(mask_dset,iv_mask) == NULL )
        return "*****************************************\n"
               "ROIPLOT_main:  can't load Cluster dataset\n"
               "*****************************************\n" ;

     thr  = PLUTO_get_number(plint) ;
     rmm  = PLUTO_get_number(plint) ;
     vmul = PLUTO_get_number(plint) ;

     vfim = (float *) malloc(sizeof(float)*nx*ny*nz) ;
     EDIT_coerce_scale_type( nvox ,
                             DSET_BRICK_FACTOR(mask_dset,iv_mask) ,
                             DSET_BRICK_TYPE(mask_dset,iv_mask) ,
                             DSET_ARRAY(mask_dset,iv_mask) ,
                             MRI_float , vfim ) ;
     if( thr > 0.0 ){
       for( ii=0 ; ii < nvox ; ii++ )
         if( fabs(vfim[ii]) < thr ) vfim[ii] = 0.0 ;
     }

     clustar = MCW_find_clusters( nx,ny,nz , dx,dy,dz ,
                                  MRI_float , vfim , rmm ) ;
     free(vfim) ;

     if( clustar == NULL )
        return "********************************\n"
               "ROIPLOT_main:  no Clusters found\n"
               "********************************\n" ;

     /* edit for volume */

     ptmin = (int) (vmul / (dx*dy*dz) + 0.99) ;
     INIT_CLARR(clbig) ;
     for( ii=0 ; ii < clustar->num_clu ; ii++ ){
       cl = clustar->clar[ii] ;
       if( cl != NULL && cl->num_pt >= ptmin ){ /* big enough */
          ADDTO_CLARR(clbig,cl) ;               /* copy pointer */
          clustar->clar[ii] = NULL ;            /* null out original */
       }
     }
     DESTROY_CLARR(clustar) ;
     clustar = clbig ;
     if( clustar == NULL || clustar->num_clu == 0 ){
       printf("** NO CLUSTERS FOUND ***\n") ;
       if( clustar != NULL ) DESTROY_CLARR(clustar) ;
       return "********************************\n"
              "ROIPLOT_main:  no Clusters found\n"
              "********************************\n" ;
     }
     SORT_CLARR(clustar) ;

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

   } else if( strcmp(tag,"Values") == 0 ){
     idc       = PLUTO_get_idcode(plint) ;
     mask_dset = PLUTO_find_dset(idc) ;
     if( mask_dset == NULL )
       return "*********************************\n"
              "ROIPLOT_main:  bad Values dataset\n"
              "*********************************"  ;
     if( DSET_NVOX(mask_dset) != nvox )
       return "*****************************************************\n"
              "ROIPLOT_main:  Source and Values datasets don't match\n"
              "*****************************************************"  ;
     iv_mask = (int) PLUTO_get_number(plint) ;
     if( iv_mask >= DSET_NVALS(mask_dset) )
       return "*******************************\n"
              "ROIPLOT_main:  bad Values index\n"
              "********************************"  ;
     DSET_load(mask_dset) ;
     if( DSET_ARRAY(mask_dset,iv_mask) == NULL )
        return "****************************************\n"
               "ROIPLOT_main:  can't load Values dataset\n"
               "****************************************\n" ;

     val_min = (int) PLUTO_get_number(plint) ;
     val_max = (int) PLUTO_get_number(plint) ;
     if( val_max < val_min ) val_max = val_min ;

     /* must build cluster here */

     return "****************************************\n"
            "ROIPLOT_main:  Values NOT IMPLEMENT YET!\n"
            "****************************************\n" ;

   } else {
     return "*******************************\n"
            "ROIPLOT_main: no ROI selection?\n"
            "********************************"  ;
   }

   /* check for too many options */

   tag = PLUTO_get_optiontag(plint) ;
   if( tag != NULL )
      PLUTO_popup_transient(plint,"\n"
                                  "+++++++ WARNING ++++++++\n"
                                  " Using Cluster option;\n"
                                  " Ignoring Values option\n"  ) ;

   /* extract average time series */

   flim = THD_average_timeseries( clustar , input_dset ) ;

   if( flim == NULL ){
     DESTROY_CLARR(clustar) ;
     return "***********************************************\n"
            "ROIPLOT_main:  Can't extract average timeseries\n"
            "***********************************************\n" ;
   }

   nc   = flim->ny ; if( nc > MAX_NC ) nc = MAX_NC ;
   nt   = flim->nx ;
   flar = MRI_FLOAT_PTR(flim) ;
   yar  = (float **) malloc(sizeof(float *)*nc) ;
   for( ii=0 ; ii < nc ; ii++ ) yar[ii] = flar + (ii*nt+iv_start) ;
   xar  = (float *) malloc(sizeof(float)*nt) ;
   for( ii=0 ; ii < nt ; ii++ ) xar[ii] = ii ;
   nam_yyy = (char **) malloc(sizeof(char *)*nc) ;
   for( ii=0 ; ii < nc ; ii++ ){
      xcm = ycm = zcm = 0.0 ;
      for( jj=0 ; jj < clustar->clar[ii]->num_pt ; jj++ ){
        xcm += clustar->clar[ii]->i[ii] ;
        ycm += clustar->clar[ii]->j[ii] ;
        zcm += clustar->clar[ii]->k[ii] ;
      }
      xcm /= clustar->clar[ii]->num_pt ;
      ycm /= clustar->clar[ii]->num_pt ;
      zcm /= clustar->clar[ii]->num_pt ;
      nam_yyy[ii] = malloc(256) ;
      sprintf(nam_yyy[ii],"%d voxels\n"
                          "_{ijk: %d %d %d}" ,
              clustar->clar[ii]->num_pt ,
              (int)(xcm+0.499) , (int)(ycm+0.499) , (int)(zcm+0.499) ) ;
   }
   DESTROY_CLARR(clustar);

   mp = plot_ts_mem( iv_stop-iv_start+1 , xar+iv_start ,
                     nc,TSP_SEPARATE_YBOX,yar ,
                     NULL,NULL,NULL,nam_yyy ) ;

   for( ii=0 ; ii < nc ; ii++ ) free(nam_yyy[ii]) ;
   free(nam_yyy);
   free(xar); free(yar); mri_free(flim);

   if( mp == NULL )
     return "******************************************\n"
            "ROIPLOT_main:  Can't create in-memory plot\n"
            "******************************************\n" ;

   memplot_to_topshell( plint->im3d->dc->display , mp , NULL ) ;

   return NULL ;
}

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

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