#ifndef MATH_SCANNER_FUNC_HEADER
#define MATH_SCANNER_FUNC_HEADER

enum MATH_FUNCTION_ARG_TYPE {
  MATH_FUNCTION_ARG_TYPE_DOUBLE,
  MATH_FUNCTION_ARG_TYPE_STRING,
  MATH_FUNCTION_ARG_TYPE_ARRAY,
  MATH_FUNCTION_ARG_TYPE_STRING_ARRAY,
  MATH_FUNCTION_ARG_TYPE_ARRAY_COMMON,
  MATH_FUNCTION_ARG_TYPE_VARIABLE,
  MATH_FUNCTION_ARG_TYPE_STRING_VARIABLE,
  MATH_FUNCTION_ARG_TYPE_VARIABLE_COMMON,
  MATH_FUNCTION_ARG_TYPE_PROC,
};

enum MATH_FUNCTION_TYPE {
  MATH_FUNCTION_TYPE_NORMAL, MATH_FUNCTION_TYPE_POSITIONAL, MATH_FUNCTION_TYPE_CALLBACK
};

typedef int (* math_function) (MathFunctionCallExpression *exp, MathEquation *eq, MathValue *r);

struct math_function_parameter {
  int argc;
  int side_effect;
  enum MATH_FUNCTION_TYPE type;
  math_function func;
  enum MATH_FUNCTION_ARG_TYPE *arg_type;
  MathExpression *opt_usr, *base_usr;
  char *name;
};

int math_scanner_is_func(int chr);
int math_add_basic_function(MathEquation *eq);

int math_func_array_moving_average(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_float_array(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_split_float(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_substring(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_each_with_index(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_truncate(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_prepend(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_reverse(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_compare(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_replace(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_average(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_compact(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_length(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_append(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_insert(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_getobj_string(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_stdevp(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_float(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_strip(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_match(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_erase(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_split(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_getobj_array(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_clear(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_sumsq(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_stdev(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_down(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_join(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_copy(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_zetam1_int(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_mjd2month(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_sum(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_min(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array_max(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_parameter(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_string_up(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_unix2mjd(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_mjd2year(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_mjd2wday(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_mjd2yday(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_isnormal(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_zeta_int(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_mjd2unix(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_strftime(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_mjd2day(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_zip_map(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_isundef(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_isbreak(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_unshift(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sprintf(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_icbeta(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_unless(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_filter(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_reduce(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_iscont(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_zetam1(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
#ifdef HAVE_LIBGSL
int math_func_choose(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_string(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_printf(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_getobj(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_gauss(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_round(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_expm1(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_log1p(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_asinh(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_acosh(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_atanh(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_srand(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_theta(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_delta(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_gamma(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_icgam(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_times(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_rsort(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_index(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_array(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_isnan(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_progn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_prog1(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_prog2(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_shift(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sumsq(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sign(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_frac(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sqrt(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_ln1p(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_asin(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_acos(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_atan(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sinh(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_cosh(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_tanh(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_rand(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_erfc(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_qinv(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_beta(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sort(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_size(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_find(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_each(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_zeta(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_push(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_time(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_fmod(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_puts(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_abs(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_int(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_min(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_max(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sqr(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_exp(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_log(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sin(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_cos(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_tan(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_erf(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_lgn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_mjd(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_neq(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_not(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_and(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_xor(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_for(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_dif(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_sum(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_map(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_zip(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_jnu(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
#ifdef HAVE_LIBGSL
int math_func_ynu(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
#ifdef HAVE_LIBGSL
int math_func_inu(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
#ifdef HAVE_LIBGSL
int math_func_knu(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_pop(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_ln(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_ei(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_jn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_yn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_pn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_hn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_tn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_eq(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_ge(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_gt(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_le(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_lt(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_or(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_rm(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_cm(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_am(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
int math_func_if(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#ifdef HAVE_LIBGSL
int math_func_in(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
#ifdef HAVE_LIBGSL
int math_func_kn(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
#ifdef HAVE_LIBGSL
int math_func_yl(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
#ifdef HAVE_LIBGSL
int math_func_jl(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
int math_func_m(MathFunctionCallExpression *exp, MathEquation *eq, MathValue *rval);
#endif
