/* -*- mode: c -*- */

/* Licensed under a 3-clause BSD style license - see LICENSE.rst */

/* "core.c" is auto-generated by erfa_generator.py from the template
   "core.c.templ". Do *not* edit "core.c" directly, instead edit
   "core.c.templ" and run erfa_generator.py from the source directory to
   update it. */


#include "Python.h"
#include "numpy/arrayobject.h"
#include "erfa.h"


#if PY_MAJOR_VERSION >= 3
#define PY3K 1
#else
#define PY3K 0
#endif


typedef struct {
    PyObject_HEAD
    NpyIter *iter;
} _NpyIterObject;


#define MODULE_DOCSTRING \
    "This module contains the C part of the ERFA python wrappers.\n" \
    "This implements only the inner iterator loops, while the heavy lifting\n" \
    "happens in Python in core.py\n\n" \
    "For more about the module and how to use it, see the ``core.py``\n" \
    "docstrings."


{%- for func in funcs %}

static PyObject *Py_{{ func.pyname }}(PyObject *self, PyObject *args, PyObject *kwds)
{
    {%- for arg in func.args_by_inout('in|inout|out|ret|stat') %}
    {{ arg.ctype_ptr }} _{{ arg.name }};
    {%- endfor %}
    {%- if func.args_by_inout('stat')|length > 0 %}
    int stat_ok = 1;
    {%- endif %}
    NpyIter *it = ((_NpyIterObject *)args)->iter;
    char **dataptrarray = NpyIter_GetDataPtrArray(it);
    NpyIter_IterNextFunc *iternext = NpyIter_GetIterNext(it, NULL);

    Py_BEGIN_ALLOW_THREADS

    do {
        {%- for arg in func.args_by_inout('in|inout|out') %}
        _{{ arg.name }} = (({{ arg.ctype }} *)(dataptrarray[{{ func.args.index(arg) }}])){%- if arg.ctype_ptr[-1] != '*' %}[0]{%- endif %};
        {%- endfor %}

        {{ func.args_by_inout('ret|stat')|map(attribute='name')|surround('_', ' = ')|join }}{{func.name}}({{ func.args_by_inout('in|inout|out')|map(attribute='name')|prefix('_')|join(', ') }});

        {%- for arg in func.args_by_inout('ret|stat') %}
        *(({{ arg.ctype_ptr }} *)(dataptrarray[{{ func.args.index(arg) }}])) = _{{ arg.name }};
        {%- endfor %}

        {%- for arg in func.args_by_inout('stat') %}
        if (_{{ arg.name }}) {
            stat_ok = 0;
        }
        {%- endfor %}
    } while (iternext(it));

    Py_END_ALLOW_THREADS

    {%- if func.args_by_inout('stat')|length > 0 %}
    if (stat_ok) {
        Py_RETURN_TRUE;
    } else {
        Py_RETURN_FALSE;
    }
    {%- else %}
    Py_RETURN_NONE;
    {%- endif %}
}

{%- endfor %}

static PyMethodDef module_functions[] = {
    {%- for func in funcs %}
    { "_" "{{ func.pyname }}", (PyCFunction)Py_{{ func.pyname }}, METH_O, NULL },
    {%- endfor %}
    { NULL }
};

struct module_state
{
    int _dummy;
};

#if PY3K

static struct PyModuleDef moduledef = {
    PyModuleDef_HEAD_INIT,
    "_core",
    MODULE_DOCSTRING,
    sizeof(struct module_state),
    module_functions,
    NULL,
    NULL,
    NULL,
    NULL
};

#define INITERROR return NULL

PyMODINIT_FUNC PyInit__core(void)

#else
#define INITERROR return

PyMODINIT_FUNC init_core(void)
#endif

{
    PyObject *m;

#if PY3K
    m = PyModule_Create(&moduledef);
#else
    m = Py_InitModule3("_core", module_functions, MODULE_DOCSTRING);
#endif

    if (m == NULL) {
        INITERROR;
    }

    import_array();

#if PY3K
    return m;
#endif
}
