#include "afni.h"

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

#define DSETN_VERSION	"Version 1.1 <October, 2002>"

/***********************************************************************
  Plugin to provide extra datasets' timeseries in place of first
************************************************************************/
/*----------------------------------------------------------------------
 * history:
 *
 * 1.1  October 28, 2002 - rickr
 *   - register for RECEIVE_DSETCHANGE messages
 *   - update global dset list from g_id list (upon message reception)
 *----------------------------------------------------------------------
*/

char * DSETN_main     ( PLUGIN_interface *) ;
void   DSETN_func     ( MRI_IMAGE * ) ;
void   DSETN_dset_recv( int why, int np, int * ijk, void * aux ) ;

static int  set_global_dsets_from_ids( void );

#undef USE_WHERE

static char helpstring[] =
   " Purpose: Control the 'Dataset#N' 1D timeseries function\n"
   "\n"
   " Dataset = a 3D+time dataset from which to extract data\n"
   " Color   = color to overlay in AFNI graph window\n"
   "\n"
   " Usage:\n"
   " 1) Choose in this plugin the 3D+time datasets you want to graph,\n"
   "     and their overlay colors.  Then press 'Set+Keep'.\n"
   " 2) In an AFNI graph window, choose 'Tran 1D' to be 'Dataset#N'.\n"
   "     This will cause the time series chosen here to replace the\n"
   "     time series of the dataset being graphed.\n"
   " 3) Optionally, you can set 'Double Plot' to 'Overlay' in the\n"
   "     AFNI graph window - this will then also show the time series\n"
   "     from the current AFNI graph window.\n"
   "\n"
   " Note that changes in this plugin interface are not communicated\n"
   " to AFNI itself until you press one of the 'Set' buttons.\n"
#ifdef USE_WHERE
   "\n"
   " Justify = Left  means to put timeseries data at start of output array\n"
   "           Right means to put timeseries data at end of output array\n"
   "\n"
   " Fill    = Extend means to copy the last value\n"
   "           Zero   means to fill with zeros\n"
   "\n"
   " Justify and Fill are only used when the number of points in the input\n"
   " dataset doesn't match the number of points in the timeseries being replaced.\n"
   " Let M = length of dataset, N = length of timeseries,\n"
   " ts[] = timeseries array, ds[] = dataset array.\n"
   "\n"
   " Case: M < N (too little data to fill timeseries)\n"
   "    Left: ts[i] = ds[i]    i=0..M-1                        Data goes to left\n"
   "                = ds[M-1]  i=M..N-1 if Extend              edge of timeseries\n"
   "                = 0.0      i=M..N-1 if Zero\n"
   "   Right: ts[i] = ds[0]    i=0..J-1 if Extend (with J=N-M) Data goes to right\n"
   "                = 0.0      i=0..J-1 if Zero                edge of timeseries\n"
   "                = ds[i-J]  i=J..N-1\n"
   " Case: M > N (too much data for timeseries)\n"
   "    Left: ts[i] = ds[i]    i=0..N-1                        Left data to ts[]\n"
   "   Right: ts[i] = ds[i+J]  i=0..N-1 (with J=M-N)           Right data to ts[]\n"
#endif
   "\n"
   " -- RWCox - 29 Mar 2002\n"
;

#define NMAX 9  /* max number of time series */

static THD_3dim_dataset *dset[NMAX] ;
static MCW_idcode        g_id[NMAX] ;	/* for re-establishing dset values */
static int               ovc [NMAX] ;
static int               g_dset_recv = -1 ;         /* for AFNI messaging  */
static int               g_valid_data = 0 ;         /* is the data usable  */

#ifdef USE_WHERE
static int justify = 0 ;
static int fill    = 0 ;
#endif

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

static char *lr[2] = { "Left" , "Right" } ;
static char *ez[2] = { "Extend" , "Zero" } ;

static PLUGIN_interface *plint=NULL ;

static void DSETN_func_init(void)   /* 21 Jul 2003 */
{
   PLUG_startup_plugin_CB( NULL , (XtPointer)plint , NULL ) ;
}


DEFINE_PLUGIN_PROTOTYPE

PLUGIN_interface * PLUGIN_init( int ncall )
{
   int id ;

ENTRY("PLUGIN_init:Dataset#N") ;

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

   AFNI_register_nD_function ( 1 , "Dataset#N" , (generic_func *)DSETN_func ,
                               NEEDS_DSET_INDEX|PROCESS_MRI_IMAGE ) ;
   AFNI_register_nD_func_init( 1 , (generic_func *) DSETN_func_init ) ;  /* 21 Jul 2003 */

   plint = PLUTO_new_interface( "Dataset#N", "Controls 1D function Dataset#N",
                                 helpstring, PLUGIN_CALL_VIA_MENU, DSETN_main  ) ;

   PLUTO_add_hint( plint , "Controls 1D function Dataset#N" ) ;

   PLUTO_set_sequence( plint , "A:funcs:dataset#N" ) ;

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

   for( id=0 ; id < NMAX ; id++ ){
     PLUTO_add_option( plint , "Input" , "Input" , FALSE ) ;
     PLUTO_add_dataset(plint , "Dataset" ,
                                      ANAT_ALL_MASK , FUNC_ALL_MASK ,
                                      DIMEN_4D_MASK | BRICK_ALLREAL_MASK ) ;
     PLUTO_add_overlaycolor( plint , "Color" ) ;
   }

#ifdef USE_WHERE
   PLUTO_add_option( plint , "Where" , "Where" , FALSE ) ;
   PLUTO_add_string( plint, "Justify", 2, lr, justify ) ;

   PLUTO_add_option( plint , "How" , "How" , FALSE ) ;
   PLUTO_add_string( plint, "Fill", 2, ez, fill ) ;
#endif

   /* init the global lists */
   for ( id=0 ; id < NMAX ; id++ ){
	dset[id] = NULL;
	ZERO_IDCODE(g_id[id]);
   }

   RETURN( plint ) ;
}

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

char * DSETN_main( PLUGIN_interface * plint )
{
   MCW_idcode *idc ;
   char *str , *tag ;
   int id=0 ;

ENTRY( "DSETN_main" ) ;

   if( plint == NULL )
      RETURN("***********************\n"
             "DSETN_main:  NULL input\n"
             "***********************") ;

   for( id=0 ; id < NMAX ; id++ ){   /* 18 Mar 2004: renullification */
     dset[id] = NULL ;
     ZERO_IDCODE(g_id[id]);
   }

   id = 0 ;

   while( (tag=PLUTO_get_optiontag(plint)) != NULL ){

      /* Input */

      if( strcmp(tag,"Input") == 0 ){
        idc      = PLUTO_get_idcode(plint) ;
        dset[id] = PLUTO_find_dset(idc) ;

	if ( ! ISVALID_DSET( dset[id] ) )
	    RETURN("******************************\n"
		   "DSETN_main:  bad input dataset\n"
		   "******************************") ;

	g_id[id] = *idc ;
        ovc [id] = PLUTO_get_overlaycolor(plint) ;
        id++ ; continue ;
      }

#ifdef USE_WHERE
      /* Where */

      if( strcmp(tag,"Where") == 0 ){
        str = PLUTO_get_string(plint) ;
        justify = (strcmp(str,lr[0]) != 0) ;
        continue ;
      }

      /* How */

      if( strcmp(tag,"How") == 0 ){
        str = PLUTO_get_string(plint) ;
        fill = (strcmp(str,ez[0]) != 0) ;
        continue ;
      }
#endif

   }

   if ( id <= 0 )			/* no data - nothing to do */
       RETURN( NULL ) ;

   g_valid_data = 1 ;			/* valid data, woohooo!    */

   if ( g_dset_recv < 0 )
       g_dset_recv = AFNI_receive_init( plint->im3d, RECEIVE_DSETCHANGE_MASK,
					DSETN_dset_recv, plint ,
                                       "DSETN_dset_recv" ) ;
   if ( g_dset_recv < 0 )
     RETURN("*************************************\n"
 	    "DSETN_main:  failed AFNI_receive_init\n"
	    "*************************************") ;

   PLUTO_force_redisplay() ;
   RETURN( NULL );
}

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

void DSETN_dset_recv( int why, int np, int * ijk, void * aux )
{
    PLUGIN_interface * plint = (PLUGIN_interface *)aux;

ENTRY( "DSETN_dset_recv" );

    switch ( why )
    {
	default:
	{
	    fprintf( stderr, "warning: DSETN_dset_recv() called with invalid "
			     "why code, %d\n", why );
	    EXRETURN;
	}

	case RECEIVE_ALTERATION:   /* may take effect before DSETCHANGE */
	case RECEIVE_DSETCHANGE:
	{
	    /* start by noting the number of valid data sets */
	    int num_valid = set_global_dsets_from_ids( );

	    if ( g_valid_data != 1 || num_valid <= 0 )
	    {
		/* shut the plugin down - "he's only _mostly_ dead" */

		g_valid_data = 0;

		AFNI_receive_control( plint->im3d, g_dset_recv,
				      EVERYTHING_SHUTDOWN, NULL );
		g_dset_recv = -1;
		PLUTO_popup_worker( plint,
					"Warning: plugin 'Dataset#N'\n"
					"has lost its dataset links.\n"
					"To plot 1-D overlays, please\n"
					"re-run the plugin.",
				    MCW_USER_KILL | MCW_TIMER_KILL ) ;
	    }
	}
    }

    EXRETURN;
}

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

void DSETN_func( MRI_IMAGE *qim )
{
   int id , ny , nxtop=0 , ijk , ii ;
   MRI_IMARR *tar ;
   MRI_IMAGE *tsim , *zim ;
   float *tsar , *dar ;
   int ovi[NMAX] ;
   char str[16+4*NMAX] ;

ENTRY( "DSETN_func" );

   if ( g_valid_data != 1 )
       EXRETURN ;				  /* nothing to do */

   INIT_IMARR(tar) ;
   ijk = AFNI_needs_dset_ijk() ;          /* voxel index from AFNI */

   for( id=0 ; id < NMAX ; id++ ){
     if( ISVALID_DSET(dset[id]) ){
       tsim = THD_extract_series( ijk,dset[id], 0 ) ;  /* get data */
       if( tsim == NULL ) continue ;
       ovi[IMARR_COUNT(tar)] = ovc[id] ;
       ADDTO_IMARR(tar,tsim) ;
       nxtop = MAX(nxtop,tsim->nx) ;
     }
   }

   ny = IMARR_COUNT(tar) ;

   if( ny == 0 || nxtop < 2 ){ DESTROY_IMARR(tar); EXRETURN; } /* no data */

   if( ny == 1 ){                                  /* one dataset */
     tsim = IMARR_SUBIM(tar,0); FREE_IMARR(tar);
     mri_move_guts(qim,tsim);
     sprintf(str,"color: %d",ovi[0]) ; mri_add_name(str,qim) ;
     EXRETURN;
   }
                                             /* multiple datasets */

   tsim = mri_new( nxtop , ny , MRI_float ) ;
   tsar = MRI_FLOAT_PTR(tsim) ;
   strcpy(str,"color:") ;
   for( id=0 ; id < ny ; id++ ){
      zim = IMARR_SUBIM(tar,id) ;
      dar = MRI_FLOAT_PTR(zim) ;
      memcpy( tsar , dar , sizeof(float)*zim->nx) ;
      if( zim->nx < nxtop ){   /* 18 Mar 2004: fill with infinity */
        for( ii=zim->nx ; ii < nxtop ; ii++ ) tsar[ii] = WAY_BIG ;
      }
      tsar += nxtop ;
      sprintf(str+strlen(str)," %d",ovi[id]) ;
   }

   DESTROY_IMARR(tar) ;
   mri_move_guts(qim,tsim) ; mri_add_name(str,qim) ;
   EXRETURN;
}

static int set_global_dsets_from_ids( void )
{
    THD_3dim_dataset * dptr;
    int idcount, num_valid = 0;

ENTRY( "set_global_dsets_from_ids" );

    for ( idcount = 0; idcount < NMAX; idcount++ )
    {
	if ( ! ISZERO_IDCODE( g_id[idcount] ) )
	{
	    dptr = PLUTO_find_dset( &g_id[idcount] );
	    if ( ! ISVALID_DSET( dptr ) )
	    {
		dptr = NULL;
		ZERO_IDCODE( g_id[idcount] );	/* lost dataset    */
	    }
	    else				/* a good one      */
		num_valid++;
	}
	else					/* just being safe */
	    dptr = NULL;

	dset[idcount] = dptr;
    }

    RETURN( num_valid );
}


syntax highlighted by Code2HTML, v. 0.9.1