
// Heritage in C is wonderful

#include "Numerics_common_structs.h"

typedef struct {
  int id;
  PyObject* class_object;
} class_env_python;

typedef struct {
  int id;
  PyObject* env_compute_function;
  PyObject* env_compute_jacobian;
} functions_env_python;

typedef struct {
  int id;
  PyObject* env_compute_function;
  PyObject* env_compute_projection_on_set;
} functions_env_python_with_proj;


static void call_py_compute_nabla_Fvi(void *env, int n, double* z, NumericsMatrix* nabla_F);
static void call_py_compute_Fvi(void *env, int n, double* z, double* F);

static void call_py_compute_nabla_Fncp(void *env, int n, double* z, NumericsMatrix* nabla_F);
static void call_py_compute_Fncp(void *env, int n, double* z, double* F);

static void call_py_compute_nabla_Fmcp(void *env, int n, double* z, NumericsMatrix* nabla_Fmcp);
static void call_py_compute_Fmcp(void *env, int n, double* z, double* Fmcp);

#define PY_CALL_METHOD_OR_FUNCTION(ENV_STRUCT, METHOD_NAME, FIELD_FUNCTION, OUTPUT, ...) \
PyObject* py_out = NULL;\
switch (((env_target_lang*) ENV_STRUCT)->id)\
{\
  case ENV_IS_PYTHON_CLASS:\
  {\
    py_out = PyObject_CallMethodObjArgs(((class_env_python*) ENV_STRUCT)->class_object, SWIG_Python_str_FromChar((char *)METHOD_NAME), __VA_ARGS__, OUTPUT, NULL);\
    break;\
  }\
  case ENV_IS_PYTHON_FUNCTIONS:\
  {\
    py_out = PyObject_CallFunctionObjArgs(((functions_env_python*) ENV_STRUCT)->FIELD_FUNCTION, __VA_ARGS__, OUTPUT, NULL);\
    break;\
  }\
  default:\
  {\
    PyErr_SetString(PyExc_TypeError, "Unknown environment type");\
  }\
}\
if (!py_out)\
{\
  PyErr_PrintEx(0);\
}\
Py_XDECREF(py_out);

//////////////////////////////////////////////////////////////////////////////
// START copy from npy_3kcompat.h
// We copy those things since
//   - there is no guarantee that those functions are going to remain around
//   - MSVC chokes if we include npy_3kcompat.h and I don't want to investigate
// 
// --xhub
//////////////////////////////////////////////////////////////////////////////

#if PY_MAJOR_VERSION >= 3

#define PyString_Type PyBytes_Type
#define PyStringObject PyBytesObject
#define PyString_FromStringAndSize PyBytes_FromStringAndSize
#define PyString_AsStringAndSize PyBytes_AsStringAndSize
#define PyString_FromFormat PyBytes_FromFormat
#define PyString_Concat PyBytes_Concat
#define PyString_ConcatAndDel PyBytes_ConcatAndDel
#define PyString_GET_SIZE PyBytes_GET_SIZE

#define PyUString_Type PyUnicode_Type
#define PyUString_Check PyUnicode_Check
#define PyUStringObject PyUnicodeObject
#define PyUString_FromString PyUnicode_FromString
#define PyUString_FromStringAndSize PyUnicode_FromStringAndSize
#define PyUString_FromFormat PyUnicode_FromFormat
#define PyUString_Concat PyUnicode_Concat2
#define PyUString_ConcatAndDel PyUnicode_ConcatAndDel
#define PyUString_GET_SIZE PyUnicode_GET_SIZE
#define PyUString_Size PyUnicode_Size
#define PyUString_InternFromString PyUnicode_InternFromString
#define PyUString_Format PyUnicode_Format

#else

#define PyBytes_Type PyString_Type
#define PyBytes_Check PyString_Check
#define PyBytesObject PyStringObject
#define PyBytes_FromString PyString_FromString
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
#define PyBytes_AS_STRING PyString_AS_STRING
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
#define PyBytes_FromFormat PyString_FromFormat
#define PyBytes_Concat PyString_Concat
#define PyBytes_ConcatAndDel PyString_ConcatAndDel
#define PyBytes_AsString PyString_AsString
#define PyBytes_GET_SIZE PyString_GET_SIZE
#define PyBytes_Size PyString_Size

#define PyUString_Type PyString_Type
#define PyUString_Check PyString_Check
#define PyUStringObject PyStringObject
#define PyUString_FromString PyString_FromString
#define PyUString_FromStringAndSize PyString_FromStringAndSize
#define PyUString_FromFormat PyString_FromFormat
#define PyUString_Concat PyString_Concat
#define PyUString_ConcatAndDel PyString_ConcatAndDel
#define PyUString_GET_SIZE PyString_GET_SIZE
#define PyUString_Size PyString_Size
#define PyUString_InternFromString PyString_InternFromString
#define PyUString_Format PyString_Format

#endif /* NPY_PY3K */


static inline void
PyUnicode_ConcatAndDel(PyObject **left, PyObject *right)
{
    PyObject *newobj;
    newobj = PyUnicode_Concat(*left, right);
    Py_DECREF(*left);
    Py_DECREF(right);
    *left = newobj;
}

//////////////////////////////////////////////////////////////////////////////
// END copy from npy_3kcompat.h
//////////////////////////////////////////////////////////////////////////////

