/* -*- Mode: C; c-basic-offset: 4 -*-
 * vi:si:et:sw=4:sts=4:ts=4
 *
 * gst-python
 * Copyright (C) 2005 Edward Hervey
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 * 
 * Author: Edward Hervey <edward@fluendo.com>
 */
%%
ignore
  gst_bus_create_watch
  gst_bus_sync_signal_handler
  gst_bus_async_signal_func
%%
headers
static GstBusSyncReply
bus_sync_handler (GstBus *bus, GstMessage *message, gpointer user_data)
{
    PyGILState_STATE state;
    GstBusSyncReply    res;
    PyObject    *py_userdata;
    PyObject    *py_msg;
    PyObject    *callback, *args;
    PyObject    *ret;
    gint        i, len;

    g_return_val_if_fail (user_data != NULL, GST_BUS_PASS);

    state = pyg_gil_state_ensure ();

    py_userdata = (PyObject *) user_data;
    py_msg = pygstminiobject_new (GST_MINI_OBJECT (message));
    callback = PyTuple_GetItem (py_userdata, 0);

    /* Using N we give away our references to the args tuple */
    args = Py_BuildValue ("(NN)",
                          pygobject_new (G_OBJECT (bus)),
                          py_msg);

    /* add all *args to the args tuple object */
    len = PyTuple_Size (py_userdata);
    for (i = 1; i < len; ++i) {
        PyObject *tuple = args;
        args = PySequence_Concat (tuple, PyTuple_GetItem (py_userdata, i));
        Py_DECREF (tuple);
    }
    ret = PyObject_CallObject (callback, args);

    if (!ret) {
        PyErr_Print ();
        res = GST_BUS_PASS;
    } else {
        if (ret == Py_None) {
            PyErr_SetString (PyExc_TypeError,
                "callback should return a BusSyncReply");
            PyErr_Print ();
            res = GST_BUS_PASS;    
        } else if (pyg_enum_get_value (GST_TYPE_BUS_SYNC_REPLY, ret,
                                       (gint *) &res))
            res = GST_BUS_PASS;

        Py_DECREF (ret);
    }
    Py_DECREF (args);

    pyg_gil_state_release (state);

    return res;
}

static gboolean
bus_func (GstBus *bus, GstMessage *message, gpointer user_data)
{
    PyGILState_STATE state;
    gboolean    res;
    PyObject    *py_userdata;
    PyObject    *py_msg;
    PyObject    *callback, *args;
    PyObject    *ret;
    gint        i, len;

    g_return_val_if_fail (user_data != NULL, TRUE);

    GST_DEBUG_OBJECT (bus, "dispatching message %p", message);

    state = pyg_gil_state_ensure ();

    py_userdata = (PyObject *) user_data;
    g_assert (PyTuple_Check (py_userdata));

    py_msg = pygstminiobject_new (GST_MINI_OBJECT (message));
    callback = PyTuple_GetItem (py_userdata, 0);

    /* Using N we give away our references to the args tuple */
    args = Py_BuildValue ("(NN)",
                          pygobject_new (G_OBJECT (bus)),
                          py_msg);
    g_assert (args);

    /* add all *args to the args tuple object */
    len = PyTuple_Size (py_userdata);
    for (i = 1; i < len; ++i) {
        PyObject *item;
        PyObject *tuple = args;

        item = PyTuple_GetItem (py_userdata, i);
        g_assert (item);

        args = PySequence_Concat (tuple, item);
        g_assert (args);

        Py_DECREF (tuple);
    }
    ret = PyObject_CallObject(callback, args);

    if (!ret) {
        PyErr_Print ();
        res = TRUE;
    } else {
        if (ret == Py_None) {
            PyErr_SetString (PyExc_TypeError,
                "callback should return True or False");
            PyErr_Print ();
            res = TRUE;
        } else 
            res = PyObject_IsTrue (ret);
        Py_DECREF (ret);
    }
    Py_DECREF (args);

    pyg_gil_state_release (state);

    GST_DEBUG_OBJECT (bus, "dispatched message %p", message);

    return res;
}

%%
override gst_bus_set_sync_handler args
static PyObject *
_wrap_gst_bus_set_sync_handler (PyGObject *self, PyObject *args)
{
    PyObject *callback = NULL;
    PyObject *cbargs = NULL;
    PyObject *data = NULL;
    PyObject *old_data = NULL;
    gint len;
    static GQuark sync_handler_data_quark = 0;

    len = PyTuple_Size(args);

    if (len < 1) {
	PyErr_SetString(PyExc_TypeError, "Bus requires at least 1 arg");
	return NULL;
    }

    if (sync_handler_data_quark == 0)
	sync_handler_data_quark = \
			g_quark_from_static_string("PyGst::BusSyncHandlerData");

    callback = PySequence_GetItem(args, 0);
    if (callback != Py_None) {
	if (!PyCallable_Check(callback)) {
	    Py_DECREF (callback);
	    PyErr_SetString(PyExc_TypeError, "callback is not callable");
	    return NULL;
	}

	cbargs = PySequence_GetSlice(args, 1, len);
	if (cbargs == NULL) {
	    Py_DECREF (callback);
	    return NULL;
	}

	data = Py_BuildValue("(ON)", callback, cbargs);
	Py_DECREF (cbargs);
	if (data == NULL) {
	    Py_DECREF (callback);
	    return NULL;
	}

	old_data = g_object_get_qdata (self->obj, sync_handler_data_quark);
	if (old_data != NULL) {
	   Py_DECREF (old_data);
	}

	g_object_set_qdata (self->obj, sync_handler_data_quark, data);

	gst_bus_set_sync_handler (GST_BUS (self->obj),
				  (GstBusSyncHandler) bus_sync_handler,
				  data);
    } else {
	old_data = g_object_get_qdata (self->obj, sync_handler_data_quark);
	if (old_data != NULL) {
	    Py_DECREF (old_data);
	}

	g_object_set_qdata (self->obj, sync_handler_data_quark, NULL);

	gst_bus_set_sync_handler (GST_BUS (self->obj), NULL, NULL);
    }

    Py_DECREF (callback);

    Py_INCREF(Py_None);
    return Py_None;
}
%%
override gst_bus_add_watch args
static PyObject *
_wrap_gst_bus_add_watch (PyGObject *self, PyObject *args)
{
    PyObject *callback, *cbargs = NULL, *data;
    guint sigid;
    guint len;

    len = PyTuple_Size(args);

    if (len < 1) {
        PyErr_SetString(PyExc_TypeError, "Bus.add_watch requires at least 1 argument");
        return NULL;
    }

    callback = PySequence_GetItem(args, 0);
    if (!PyCallable_Check(callback)) {
        PyErr_SetString(PyExc_TypeError, "callback is not callable");
        return NULL;
    }
    cbargs = PySequence_GetSlice(args, 1, len);
    if (cbargs == NULL)
        return NULL;
    /* FIXME: thomas: I'm pretty sure the second N needs to be O */
    data = Py_BuildValue("(ON)", callback, cbargs);
    if (data == NULL)
        return NULL;

    sigid = gst_bus_add_watch_full (GST_BUS (self->obj), G_PRIORITY_DEFAULT,
        (GstBusFunc) bus_func, data, (GDestroyNotify)pyg_destroy_notify);

    return PyInt_FromLong(sigid);
}
%%
override gst_bus_add_signal_watch kwargs
static PyObject *
_wrap_gst_bus_add_signal_watch(PyGObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "priority", NULL };
    int priority = G_PRIORITY_DEFAULT;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:GstBus.add_signal_watch", kwlist, &priority))
        return NULL;
    pyg_begin_allow_threads;
    gst_bus_add_signal_watch_full(GST_BUS(self->obj), priority);
    pyg_end_allow_threads;
    Py_INCREF(Py_None);
    return Py_None;
}