%module capi
#define __attribute__(__x__)
%{
#include "@top_srcdir@/include/team.h"

static int PythonCallBack(struct team_handle *th, void *func_priv,
                          team_change_type_mask_t type_mask);
void py_team_change_handler_register(struct team_handle *th,
                                     struct team_change_handler *handler,
                                     PyObject *priv);
void py_team_change_handler_unregister(struct team_handle *th,
                                       struct team_change_handler *handler,
                                       PyObject *priv);
%}

%include <cstring.i>
%include <stdint.i>
%include "typemaps.i"

%apply int *OUTPUT {uint32_t *ifindex};
%cstring_output_allocate(char **mode_name, )

%typemap(in) (char *ifname, unsigned int maxlen) {
    $2 = PyInt_AsLong($input);
    $1 = (char *) malloc(sizeof(char) * $2);
}

%typemap(freearg) (char *ifname, unsigned int maxlen) {
    if ($1) free($1);
}

%apply (char *STRING, int LENGTH) { (const char *addr, unsigned int addr_len) };
int team_hwaddr_set(struct team_handle *th, uint32_t ifindex, const char *addr, unsigned int addr_len);

%typemap(in) (char *addr, unsigned int addr_len) {
    $2 = PyInt_AsLong($input);
    $1 = (char *) malloc(sizeof(char) * $2);
}
%typemap(freearg) (char *addr, unsigned int addr_len) {
    if ($1) free($1);
}
%typemap(argout) (char *addr, unsigned int addr_len) {
    $result = SWIG_Python_AppendOutput($result, SWIG_FromCharPtrAndSize($1,$2));
}
%apply char *OUTPUT {char *addr};
int team_hwaddr_get(struct team_handle *th, uint32_t ifindex, char *addr, unsigned int addr_len);

%typemap(python, in) PyObject *PyFunc {
  if (!PyCallable_Check($input)) {
      PyErr_SetString(PyExc_TypeError, "Need a callable object!");
      return NULL;
  }
  $1 = $input;
}

%typemap(in) void (*func)(struct team_handle *, void *,
                          team_change_type_mask_t) {
    $1 = (void *) $input;
};

%{
struct _py_team_change_handler {
    struct team_change_handler handler;
    PyObject *orig_func;
    PyObject *orig_priv;
};
%}

%extend team_change_handler {
    team_change_handler(PyObject *func,
                        team_change_type_mask_t type_mask) {
        struct _py_team_change_handler *py_handler;

        py_handler = malloc(sizeof(*py_handler));
        if (!py_handler)
                return NULL;
        py_handler->handler.func = (void *) func;
        py_handler->handler.type_mask = type_mask;

        Py_XINCREF(py_handler->handler.func);
        return &py_handler->handler;
    }

    ~team_change_handler() {
        Py_XDECREF($self->func);
        free($self);
    }
}

void py_team_change_handler_register(struct team_handle *th,
                                     struct team_change_handler *handler,
                                     PyObject *priv);

void py_team_change_handler_unregister(struct team_handle *th,
                                       struct team_change_handler *handler,
                                       PyObject *priv);

%{
static int PythonCallBack(struct team_handle *th, void *func_priv,
                          team_change_type_mask_t type_mask)
{
    PyObject *arglist;
    PyObject *result;
    struct _py_team_change_handler *py_handler;
    int retval = 0;

    py_handler = (struct _py_team_change_handler *) func_priv;
    arglist = Py_BuildValue("(Oi)", py_handler->orig_priv, type_mask);

    result =  PyObject_CallObject(py_handler->orig_func, arglist);

    if (result == NULL)
        return -1;
    if (PyInt_Check(result))
        retval = PyInt_AsLong(result);
    if (arglist != NULL)
        Py_DECREF(arglist);
    Py_XDECREF(result);

    return retval;
}

void py_team_change_handler_register(struct team_handle *th,
                                     struct team_change_handler *handler,
                                     PyObject *priv)
{
    struct _py_team_change_handler *py_handler;

    py_handler = (struct _py_team_change_handler *) handler;
    py_handler->orig_func = (PyObject *) handler->func;
    py_handler->orig_priv = priv;
    handler->func = PythonCallBack;

    Py_XINCREF(py_handler->orig_func);
    Py_XINCREF(py_handler->orig_priv);
    team_change_handler_register(th, handler, handler);
}

void py_team_change_handler_unregister(struct team_handle *th,
                                       struct team_change_handler *handler,
                                       PyObject *priv)
{
    struct _py_team_change_handler *py_handler;

    py_handler = (struct _py_team_change_handler *) handler;
    Py_XDECREF(py_handler->orig_priv);
    Py_XDECREF(py_handler->orig_func);
    team_change_handler_unregister(th, handler, handler);
}
%}

%include @top_srcdir@/include/team.h
