/* Copyright (c) 2001-2009 by SoftIntegration, Inc. All Rights Reserved */
#include <ch.h>
#include <stdio.h>

#define MAXNUM 100 /* maximum length of the array of function */

/* type of pointer to function array */
typedef return_type2 (**pfuncArr_t)(data_type arg); 

static ChInterp_t interp;
/* C function to replace the Ch function pointer */
static return_type2 (*setarrayfunc_chdl_funarg[MAXNUM])(data_type arg);

/* save the function pointer from the Ch space */
static return_type2 (*setarrayfunc_chdl_funptr[MAXNUM])(data_type arg);

static return_type2 setarrayfunc_chdl_funarg0(data_type arg);
static return_type2 setarrayfunc_chdl_funarg1(data_type arg);
static return_type2 setarrayfunc_chdl_funarg2(data_type arg);
/* ... up to MAXNUM */

EXPORTCH return_type setarrayfunc_chdl(void *varg) {
  ChVaList_t ap;
  return_type retval;
  int i, n;
  pfuncArr_t parr_ch, parr_c = NULL;

  Ch_VaStart(interp, ap, varg);
  n = Ch_VaArg(interp, ap, int);

  /* get Ch array */
  parr_ch = Ch_VaArg(interp, ap, pfuncArr_t);
  if(parr_ch != NULL) {
    /* save Ch array */
    for(i = 0; i < n; i++) {
      setarrayfunc_chdl_funptr[i] = (int (*)(int num))parr_ch[i];
    }

    /* assign C function to the C array */ 
    setarrayfunc_chdl_funarg[0] = setarrayfunc_chdl_funarg0;
    setarrayfunc_chdl_funarg[1] = setarrayfunc_chdl_funarg1;
    setarrayfunc_chdl_funarg[2] = setarrayfunc_chdl_funarg2;
    /* ... up to MAXNUM */

    /* replace the Ch array with the C one,
       the NULL pointer can't be replaced */
    parr_c = (pfuncArr_t)setarrayfunc_chdl_funarg;
  }

  /* pass the C array with members of pointers to C functions 
     instead of the Ch one, the NULL pointer will not be replaced */
  retval = setarrayfunc(n, parr_c);

  Ch_VaEnd(interp, ap);
  return retval;
}

static return_type2 setarrayfunc_chdl_funarg0(data_type arg) {
  return_type2 retval;

  Ch_CallFuncByAddr(interp, (void*)setarrayfunc_chdl_funptr[0], &retval, arg);
  return retval;
}

static return_type2 setarrayfunc_chdl_funarg1(data_type arg) {
  return_type2 retval;

  Ch_CallFuncByAddr(interp, (void*)setarrayfunc_chdl_funptr[1], &retval, arg);
  return retval;
}

static return_type2 setarrayfunc_chdl_funarg2(data_type arg) {
  return_type2 retval;

  Ch_CallFuncByAddr(interp, (void*)setarrayfunc_chdl_funptr[2], &retval, arg);
  return retval;
}

/* ... up to MAXNUM */
