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

typedef int (*pf_t)(); /* function pointer type */
static ChInterp_t interp;
static void *diff_arg_chdl_funptr;

static int diff_arg_chdl_funarg0() {
  int retval;

  Ch_CallFuncByAddr(interp, diff_arg_chdl_funptr, &retval);
  return retval;
}

static int diff_arg_chdl_funarg1(int num) {
  int retval;

  Ch_CallFuncByAddr(interp, diff_arg_chdl_funptr, &retval, num);
  return retval;
}

static int diff_arg_chdl_funarg2(int num1, int num2) {
  int retval;

  Ch_CallFuncByAddr(interp, diff_arg_chdl_funptr, &retval, num1, num2);
  return retval;
}

static int diff_arg_chdl_funarg3(int num1, ...) {
  int retval;
  va_list ap;
  ChVaList_t ap_ch;
  int x;
  double d;

  va_start(ap, num1);
  ap_ch = Ch_VarArgsCreate(interp);
  if(num1 >= 1) {
    x = va_arg(ap, int);
    Ch_VarArgsAddArg(interp, &ap_ch, CH_INTTYPE, x);
  }
  if(num1 == 2) {
    d = va_arg(ap, double);
    Ch_VarArgsAddArg(interp, &ap_ch, CH_DOUBLETYPE, d);
  }
  Ch_CallFuncByAddr(interp, diff_arg_chdl_funptr, &retval, num1, ap_ch);
  Ch_VarArgsDelete(interp, ap_ch);
  return retval;
}

EXPORTCH int diff_arg_chdl(void *varg) {
  ChVaList_t ap;
  int retval;
  int arg1, argnum;
  pf_t handle_ch, handle_c = NULL;

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

  /* get argument number of the Ch function */
  argnum = Ch_VaFuncArgNum(interp, ap);
  if(argnum == INT_MAX)
     printf("\npassed varaible number arg\n");
  else
     printf("\nargnum = %d\n", argnum);
  /* get the Ch function pointer */
  handle_ch = Ch_VaArg(interp, ap, pf_t);

  if(handle_ch != NULL) {
    /* replace the Ch array with the proper C one,
       the NULL pointer can't be replaced */
    if(argnum == 0) {
      handle_c = diff_arg_chdl_funarg0;
    }
    else if(argnum == 1) {
      handle_c = diff_arg_chdl_funarg1;
    }
    else if(argnum == 2) {
      handle_c = diff_arg_chdl_funarg2;
    }
    else if(argnum == INT_MAX) {
      handle_c = (pf_t)diff_arg_chdl_funarg3;
    }
    diff_arg_chdl_funptr = (void *)handle_ch;
  }

  /* pass the proper C function pointer 
     instead of the Ch one, 
     the NULL pointer will not be replaced.
     If the Ch function has more than 2 argument, 
     except for INT_MAX, NULL will be passed. */
  retval = diff_arg(arg1, handle_c);

  Ch_VaEnd(interp, ap);
  return retval;
}

