/*****************************************************************************
 *                              Dependencies                                 *
 *****************************************************************************/

#include <string.h>
#include <inttypes.h>
#include <Python.h>
#define PY_ARRAY_UNIQUE_SYMBOL pyclassfiller_ARRAY_API
#define NO_IMPORT_ARRAY
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#include "numpy/arrayobject.h"
#include "gsys/cfc.h"


/* This macro for numeric types, same variable used by PyArg_ParseTuple
   and sent to Fortran */
#define PYCLASSFILLER_SET_NUMERIC(attribute,type,format)                    \
PyObject* pyclassfiller_set_##attribute##_C                                 \
  (PyObject *self, PyObject *args, PyObject *kwds) {                        \
  type arg;                                                                 \
  int error;                                                                \
  void CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(type *, int *);       \
                                                                            \
  if (! PyArg_ParseTuple(args,format,&arg))                                 \
      return NULL;                                                          \
                                                                            \
  error = 0;                                                                \
  CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(&arg,&error);              \
                                                                            \
  if (error) {                                                              \
    PyErr_SetString(PyExc_Exception,"Error while executing set_attribute"); \
    return NULL;                                                            \
  }                                                                         \
                                                                            \
  Py_RETURN_NONE;                                                           \
}

/* This macro for numeric types, different variable used by
   PyArg_ParseTuple and sent to Fortran */
#define PYCLASSFILLER_SET_NUMERIC2(attribute,ptype,format,ftype)            \
PyObject* pyclassfiller_set_##attribute##_C                                 \
  (PyObject *self, PyObject *args, PyObject *kwds) {                        \
  ptype parg;                                                               \
  ftype farg;                                                               \
  int error;                                                                \
  void CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(ftype *, int *);      \
                                                                            \
  if (! PyArg_ParseTuple(args,format,&parg))                                \
      return NULL;                                                          \
                                                                            \
  farg = (ftype)parg;                                                     \
  error = 0;                                                                \
  CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(&farg,&error);             \
                                                                            \
  if (error) {                                                              \
    PyErr_SetString(PyExc_Exception,"Error while executing set_attribute"); \
    return NULL;                                                            \
  }                                                                         \
                                                                            \
  Py_RETURN_NONE;                                                           \
}

/* This macro for character string, same variable used by PyArg_ParseTuple
   and sent to Fortran */
#define PYCLASSFILLER_SET_STRING(attribute)                                 \
PyObject* pyclassfiller_set_##attribute##_C                                 \
  (PyObject *self, PyObject *args, PyObject *kwds) {                        \
  char *arg;                                                                \
  int error;                                                                \
  void CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(char *, int *, int);  \
                                                                            \
  if (! PyArg_ParseTuple(args,"s",&arg))                                    \
      return NULL;                                                          \
                                                                            \
  error = 0;                                                                \
  CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(arg,&error,strlen(arg));   \
                                                                            \
  if (error) {                                                              \
    PyErr_SetString(PyExc_Exception,"Error while executing set_attribute"); \
    return NULL;                                                            \
  }                                                                         \
                                                                            \
  Py_RETURN_NONE;                                                           \
}


/* This macro suited for 1D floats (single precision) */
#define PYCLASSFILLER_SET_FLOAT_1D(attribute)                                     \
PyObject* pyclassfiller_set_##attribute##_C                                       \
  (PyObject *self, PyObject *args, PyObject *kwds) {                              \
  PyArrayObject *array;                                                           \
  npy_intp nelem;                                                                 \
  int error;                                                                      \
  float *arrayptr;                                                                \
  void CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(float *, int *, int *);     \
                                                                                  \
  if (! PyArg_ParseTuple(args,"O",&array))                                        \
      return NULL;                                                                \
                                                                                  \
  if (! PyArray_Check(array)) {                                                   \
    PyErr_SetString(PyExc_Exception,"Input object must be an array");             \
    return NULL;                                                                  \
  } else if (PyArray_NDIM(array) != 1) {                                          \
    PyErr_SetString(PyExc_Exception,"Input array must be 1D");                    \
    return NULL;                                                                  \
  } else if (PyArray_TYPE(array) != NPY_FLOAT32) {                                \
    PyErr_SetString(PyExc_Exception,"Input array must have type numpy.float32");  \
    return NULL;                                                                  \
  } else if (! PyArray_ISCONTIGUOUS(array)) {                                     \
    PyErr_SetString(PyExc_Exception,"Input array must be contiguous in memory");  \
    return NULL;                                                                  \
  }                                                                               \
                                                                                  \
  arrayptr = PyArray_GETPTR1(array, (npy_intp) 0);                                \
  nelem = PyArray_SIZE(array);                                                    \
  error = 0;                                                                      \
  CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(arrayptr,(int *) &nelem,&error); \
                                                                                  \
  if (error) {                                                                    \
    PyErr_SetString(PyExc_Exception,"Error while executing set_attribute");       \
    return NULL;                                                                  \
  }                                                                               \
                                                                                  \
  Py_RETURN_NONE;                                                                 \
}


/* This macro suited for 1D floats (double precision) */
#define PYCLASSFILLER_SET_DOUBLE_1D(attribute)                                    \
PyObject* pyclassfiller_set_##attribute##_C                                       \
  (PyObject *self, PyObject *args, PyObject *kwds) {                              \
  PyArrayObject *array;                                                           \
  npy_intp nelem;                                                                 \
  int error;                                                                      \
  double *arrayptr;                                                               \
  void CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(double *, int *, int *);    \
                                                                                  \
  if (! PyArg_ParseTuple(args,"O",&array))                                        \
      return NULL;                                                                \
                                                                                  \
  if (! PyArray_Check(array)) {                                                   \
    PyErr_SetString(PyExc_Exception,"Input object must be an array");             \
    return NULL;                                                                  \
  } else if (PyArray_NDIM(array) != 1) {                                          \
    PyErr_SetString(PyExc_Exception,"Input array must be 1D");                    \
    return NULL;                                                                  \
  } else if (PyArray_TYPE(array) != NPY_FLOAT64) {                                \
    PyErr_SetString(PyExc_Exception,"Input array must have type numpy.float64");  \
    return NULL;                                                                  \
  } else if (! PyArray_ISCONTIGUOUS(array)) {                                     \
    PyErr_SetString(PyExc_Exception,"Input array must be contiguous in memory");  \
    return NULL;                                                                  \
  }                                                                               \
                                                                                  \
  arrayptr = PyArray_GETPTR1(array, (npy_intp) 0);                                \
  nelem = PyArray_SIZE(array);                                                    \
  error = 0;                                                                      \
  CFC_EXPORT_NAME(pyclassfiller_set_##attribute)(arrayptr,(int *) &nelem,&error); \
                                                                                  \
  if (error) {                                                                    \
    PyErr_SetString(PyExc_Exception,"Error while executing set_attribute");       \
    return NULL;                                                                  \
  }                                                                               \
                                                                                  \
  Py_RETURN_NONE;                                                                 \
}


/*****************************************************************************
 *                             Function bodies                               *
 *****************************************************************************/

/*** Present sections ***/

PYCLASSFILLER_SET_NUMERIC(presec,int,"i");

/*** General ***/

/* Use PY_LONG_LONG for PyArg_ParseTuple "L", and use int64_t for Fortran I*8 */
PYCLASSFILLER_SET_NUMERIC2(gen_num,PY_LONG_LONG,"L",int64_t);
PYCLASSFILLER_SET_NUMERIC(gen_ver,int,"i");
PYCLASSFILLER_SET_STRING(gen_teles);
PYCLASSFILLER_SET_NUMERIC(gen_dobs,int,"i");
PYCLASSFILLER_SET_NUMERIC(gen_dred,int,"i");
PYCLASSFILLER_SET_NUMERIC(gen_kind,int,"i");
PYCLASSFILLER_SET_NUMERIC(gen_qual,int,"i");
/* Use PY_LONG_LONG for PyArg_ParseTuple "L", and use int64_t for Fortran I*8 */
PYCLASSFILLER_SET_NUMERIC2(gen_scan,PY_LONG_LONG,"L",int64_t);
PYCLASSFILLER_SET_NUMERIC(gen_subscan,int,"i");
PYCLASSFILLER_SET_NUMERIC(gen_ut,double,"d");
PYCLASSFILLER_SET_NUMERIC(gen_st,double,"d");
PYCLASSFILLER_SET_NUMERIC(gen_az,float,"f");
PYCLASSFILLER_SET_NUMERIC(gen_el,float,"f");
PYCLASSFILLER_SET_NUMERIC(gen_tau,float,"f");
PYCLASSFILLER_SET_NUMERIC(gen_tsys,float,"f");
PYCLASSFILLER_SET_NUMERIC(gen_time,float,"f");
PYCLASSFILLER_SET_NUMERIC(gen_xunit,int,"i");

/*** Position ***/

PYCLASSFILLER_SET_STRING(pos_sourc);
PYCLASSFILLER_SET_NUMERIC(pos_system,int,"i");
PYCLASSFILLER_SET_NUMERIC(pos_equinox,float,"f");
PYCLASSFILLER_SET_NUMERIC(pos_proj,int,"i");
PYCLASSFILLER_SET_NUMERIC(pos_lam,double,"d");
PYCLASSFILLER_SET_NUMERIC(pos_bet,double,"d");
PYCLASSFILLER_SET_NUMERIC(pos_projang,double,"d");
PYCLASSFILLER_SET_NUMERIC(pos_lamof,float,"f");
PYCLASSFILLER_SET_NUMERIC(pos_betof,float,"f");

/*** Spectroscopy ***/

PYCLASSFILLER_SET_STRING(spe_line);
PYCLASSFILLER_SET_NUMERIC(spe_nchan,int,"i");
PYCLASSFILLER_SET_NUMERIC(spe_restf,double,"d");
PYCLASSFILLER_SET_NUMERIC(spe_image,double,"d");
PYCLASSFILLER_SET_NUMERIC(spe_doppler,double,"d");
PYCLASSFILLER_SET_NUMERIC(spe_rchan,double,"d");
PYCLASSFILLER_SET_NUMERIC(spe_fres,double,"d");
PYCLASSFILLER_SET_NUMERIC(spe_vres,double,"d");
PYCLASSFILLER_SET_NUMERIC(spe_voff,double,"d");
PYCLASSFILLER_SET_NUMERIC(spe_bad,float,"f");
PYCLASSFILLER_SET_NUMERIC(spe_vtype,int,"i");
PYCLASSFILLER_SET_NUMERIC(spe_vconv,int,"i");

/*** Switching ***/

PYCLASSFILLER_SET_NUMERIC(swi_nphas,int,"i");
PYCLASSFILLER_SET_DOUBLE_1D(swi_decal);
PYCLASSFILLER_SET_FLOAT_1D(swi_duree);
PYCLASSFILLER_SET_FLOAT_1D(swi_poids);
PYCLASSFILLER_SET_NUMERIC(swi_swmod,int,"i");
PYCLASSFILLER_SET_FLOAT_1D(swi_ldecal);
PYCLASSFILLER_SET_FLOAT_1D(swi_bdecal);


/*** Calibration ***/

PYCLASSFILLER_SET_NUMERIC(cal_beeff,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_foeff,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_gaini,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_h2omm,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_pamb,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_tamb,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_tatms,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_tchop,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_tcold,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_taus,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_taui,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_tatmi,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_trec,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_cmode,int,"i");
PYCLASSFILLER_SET_NUMERIC(cal_atfac,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_alti,float,"f");
PYCLASSFILLER_SET_FLOAT_1D(cal_count);
PYCLASSFILLER_SET_NUMERIC(cal_lcalof,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_bcalof,float,"f");
PYCLASSFILLER_SET_NUMERIC(cal_geolong,double,"d");
PYCLASSFILLER_SET_NUMERIC(cal_geolat,double,"d");


/*** Continuum Drift ***/

PYCLASSFILLER_SET_NUMERIC(dri_freq,double,"d");
PYCLASSFILLER_SET_NUMERIC(dri_width,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_npoin,int,"i");
PYCLASSFILLER_SET_NUMERIC(dri_rpoin,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_tref,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_aref,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_apos,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_tres,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_ares,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_bad,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_ctype,int,"i");
PYCLASSFILLER_SET_NUMERIC(dri_cimag,double,"d");
PYCLASSFILLER_SET_NUMERIC(dri_colla,float,"f");
PYCLASSFILLER_SET_NUMERIC(dri_colle,float,"f");


/*** Data ***/

PYCLASSFILLER_SET_FLOAT_1D(datay);
