/*
 * Threshold Module, copies node data from input to output,
 * applying threshold function.
 * Designed as example of simple data filter module,
 * allocating new output field, and copying in
 * data from an input port.
 *
 * Author: Nick Trout, January 15, 1996
 *
 * Revision:  2 February 96 Ian Curington: FLD call restructure
 *
 * Revision: 27 May 1997 Paul G Lever: uses generated include files, rather
 *   than explicit avs includes or process specific include directives.
 *
 */

/* ----------------------------------------------------------------------
 * Note: This include file is generated by Express when the module is 
 * compiled. It avoids including "user.h" or "express.h" directly, so 
 * that the module may be moved across the processes by changing the V
 * properties in the library.
 * ----------------------------------------------------------------------
 */

#include "iac_proj/thresh/gen.h"

/*
 ***** MACROS *****
 */

/*
 * Error path: use ERRerror instead of printf,
 * since it reports nested context in messages
 */
#define ERROR(MESS) { ERRerror("Threshold",1,ERR_ORIG, MESS); return 0; }
#define SILENT_RTN(MESS) { return 0; }



/*********************************
 * Express Module Entry Point    *
 *********************************/

int
ThresholdNodeData(OMobj_id ThresholdNodeData_id, OMevent_mask event_mask, int seq_num)
{
   /***********************/
   /*  Declare variables  */
   /***********************/

   OMobj_id     in_id;
   int          in_ncomp, in_comp_count, in_veclen;
   int          in_data_type, in_ndata;
   char         *in_data;
   OMobj_id     out_id;
   char         *out_data;
   double       minimum;
   double       maximum;

   /* declare variables for all the different data types used */

   int           i;
   unsigned char *r_byte, *w_byte, min_byte, max_byte;
   char          *r_char, *w_char, min_char, max_char;
   short         *r_short, *w_short, min_short, max_short;
   int           *r_int, *w_int, min_int, max_int;
   float         *r_float, *w_float, min_float, max_float;
   double        *r_double, *w_double, min_double, max_double;


   /***********************/
   /*  Get input values   */
   /***********************/

   /* Get minimum's value */
   if (OMget_name_real_val(ThresholdNodeData_id,     /* id of whole module */
                          OMstr_to_name("minimum"), /* name of param */
                          &minimum) != 1)           /* return value */
      ERROR("Could not get minimum range value.");

   /* Get maximum's value */
   if (OMget_name_real_val(ThresholdNodeData_id,     /* id of whole module */
                          OMstr_to_name("maximum"), /* name of param */
                          &maximum) != 1)           /* return value */
      ERROR("Could not get maximum range value.");


   /* Get the field id's so we can access the fields */

   /* Get field id */
   in_id= OMfind_subobj(ThresholdNodeData_id, OMstr_to_name("in"), OM_OBJ_RD);

   /* Get field id */
   out_id= OMfind_subobj(ThresholdNodeData_id, OMstr_to_name("out"), OM_OBJ_RW);


   /* Copy the number of data components (nnode_data) */

   /* Get number of node data components */
   FLDget_node_data_ncomp (in_id, &in_ncomp);

   /* Set number of node data components */
   FLDset_node_data_ncomp (out_id, in_ncomp);


   /* For each node data component get veclen, type and data array itself */

   for (in_comp_count=0; in_comp_count < in_ncomp; in_comp_count++) {

      /* Copy the vector length of the node data across */

      /* Get veclen */
      FLDget_node_data_veclen (in_id, in_comp_count, &in_veclen);

      /* Set veclen to same as input data */
      FLDset_node_data_veclen (out_id, in_comp_count, in_veclen);


      /* Get data array and data_type which is one of the following: 
         DTYPE_BYTE, DTYPE_CHAR, DTYPE_SHORT, 
         DTYPE_INT, DTYPE_FLOAT, DTYPE_DOUBLE */

      if (FLDget_node_data (in_id,              /* field object id */
                           in_comp_count,      /* node_data[in_comp_count] */
                           &in_data_type,      /* data type returned */
                           &in_data,           /* pointer to data (char *) */
                           &in_ndata,          /* number of data elements */
                           OM_GET_ARRAY_RD)    /* we are reading the data */
         != 1)
       ERROR("Could not get field node data.");



      /***
      printf("Type: %d, size: %d", in_data_type, in_ndata);
       ***/

      /*
       * Allocate New Output Array
       *  - same size & type as input array 
       */
      if ((out_data= (char *)ARRalloc(NULL,           /* always null */
                                     in_data_type,   /* requested data type */
                                     in_ndata,       /* requested size */
                                     NULL)) == NULL) /* always null */
       ERROR("Could not allocate memory for thresholded array.");


      /* We will have to deal with each type of data seperately */

      /* Define a generic macro to deal with all of the data types */

#define GENERIC_THRESH(D_TYPE,RPTR,WPTR,MIN,MAX) \
      MIN= (D_TYPE)minimum; \
      MAX= (D_TYPE)maximum; \
      RPTR= (D_TYPE *)in_data; \
      WPTR= (D_TYPE *)out_data; \
      for (i= 0; i < in_ndata; i++) \
        WPTR[i]= ((RPTR[i] < MIN || RPTR[i] > MAX) ? (D_TYPE)0 : RPTR[i]);

      switch (in_data_type) {

        case DTYPE_CHAR:
          GENERIC_THRESH( char, r_char, w_char, min_char, max_char )
         break;

       case DTYPE_BYTE:
          GENERIC_THRESH( unsigned char, r_byte, w_byte, min_byte, max_byte )
         break;
          
       case DTYPE_SHORT:
         GENERIC_THRESH( short, r_short, w_short, min_short, max_short )
         break;

       case DTYPE_INT:
         GENERIC_THRESH( int, r_int, w_int, min_int, max_int )
         break;

       case DTYPE_FLOAT:
         GENERIC_THRESH( float, r_float, w_float, min_float, max_float )
         break;

       case DTYPE_DOUBLE:
         GENERIC_THRESH( double, r_double, w_double, min_double, max_double )
         break;

       default:
         ERROR("Node data is of an unknown data type.");
      }

      /* Set the output node_data's values. Since we are using ARRAY_FREE mode,
        the OM will handle the array from now on and there is no need for us
        to free it (like the in_data array). */

      if (FLDset_node_data (out_id,            /* output field id */
                            in_comp_count,     /* which component */
                            out_data,          /* pointer to output data */
                            in_data_type,      /* data type flag */
                           in_ndata,          /* number of data elements */
                            OM_SET_ARRAY_FREE) != 1)
       ERROR("Could not set thresholded node data.");

      /*  release our dependency on the input data pointer */
      /*  this should be done for each data component */
      ARRfree((char *)in_data);

   }
   

   /*
    * return to Object Manager with success flag
    */
   return(1);
}