/* -*- Mode: C; c-basic-offset: 4 -*-
 * pygobject - Python bindings for GObject
 * Copyright (C) 2008  Johan Dahlin
 *
 *   ginputstream.override: module overrides for GInputStream
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 */
%%
headers
#define BUFSIZE 8192

%%
override g_input_stream_read kwargs
static PyObject *
_wrap_g_input_stream_read(PyGObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "count", "cancellable", NULL };
    PyGObject *pycancellable = NULL;
    PyObject *v;
    GCancellable *cancellable;
    long count = -1;
    GError *error = NULL;
    size_t bytesread, buffersize, chunksize;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
                                     "|lO:InputStream.read",
                                     kwlist, &count,
                                     &pycancellable))
        return NULL;

    buffersize = (count < 0 ? BUFSIZE : count);

    if (!pygio_check_cancellable(pycancellable, &cancellable))
        return NULL;

    v = PyString_FromStringAndSize((char *)NULL, buffersize);
    if (v == NULL)
        return NULL;

    bytesread = 0;
    for (;;)
        {
            pyg_begin_allow_threads;
            errno = 0;
            chunksize = g_input_stream_read(G_INPUT_STREAM(self->obj),
                                            PyString_AS_STRING((PyStringObject *)v) + bytesread,
                                            buffersize - bytesread, cancellable,
                                            &error);
            pyg_end_allow_threads;

            if (pyg_error_check(&error)) {
		Py_DECREF(v);
		return NULL;
	    }
	    if (chunksize == 0) {
		/* End of file. */
                break;
	    }

            bytesread += chunksize;
            if (bytesread < buffersize) {
		/* g_input_stream_read() decided to not read full buffer.  We
		 * then return early too, even if 'count' is less than 0.
		 */
                break;
	    }

            if (count < 0) {
		buffersize += BUFSIZE;
		if (_PyString_Resize(&v, buffersize) < 0)
		    return NULL;
	    }
            else {
                /* Got what was requested. */
                break;
	    }
        }

    if (bytesread != buffersize)
        _PyString_Resize(&v, bytesread);

    return v;
}
%%
override g_input_stream_read_all kwargs
static PyObject *
_wrap_g_input_stream_read_all(PyGObject *self, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = { "count", "cancellable", NULL };
    PyGObject *pycancellable = NULL;
    PyObject *v;
    GCancellable *cancellable;
    long count = -1;
    GError *error = NULL;
    size_t bytesread, buffersize, chunksize;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
                                     "|lO:InputStream.read",
                                     kwlist, &count,
                                     &pycancellable))
        return NULL;

    buffersize = (count < 0 ? BUFSIZE : count);

    if (!pygio_check_cancellable(pycancellable, &cancellable))
        return NULL;

    v = PyString_FromStringAndSize((char *)NULL, buffersize);
    if (v == NULL)
        return NULL;

    bytesread = 0;
    for (;;)
        {
            pyg_begin_allow_threads;
            errno = 0;
            g_input_stream_read_all(G_INPUT_STREAM(self->obj),
				    PyString_AS_STRING((PyStringObject *)v) + bytesread,
				    buffersize - bytesread,
				    &chunksize,
				    cancellable, &error);
            pyg_end_allow_threads;

            if (pyg_error_check(&error)) {
		Py_DECREF(v);
		return NULL;
	    }

            bytesread += chunksize;
            if (bytesread < buffersize || chunksize == 0) {
		/* End of file. */
                break;
	    }

            if (count < 0) {
		buffersize += BUFSIZE;
		if (_PyString_Resize(&v, buffersize) < 0)
		    return NULL;
	    }
            else {
                /* Got what was requested. */
                break;
	    }
        }

    if (bytesread != buffersize)
        _PyString_Resize(&v, bytesread);

    return v;
}
%%
override g_input_stream_read_async kwargs
static PyObject *
_wrap_g_input_stream_read_async(PyGObject *self,
                                PyObject *args,
                                PyObject *kwargs)
{
    static char *kwlist[] = { "count", "callback", "io_priority",
                              "cancellable", "user_data", NULL };
    long count = -1;
    int io_priority = G_PRIORITY_DEFAULT;
    PyGObject *pycancellable = NULL;
    GCancellable *cancellable;
    PyGIONotify *notify;

    notify = pygio_notify_new();

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
                                     "lO|iOO:InputStream.read_async",
                                     kwlist,
                                     &count,
                                     &notify->callback,
                                     &io_priority,
                                     &pycancellable,
                                     &notify->data))
        goto error;

    if (!pygio_notify_callback_is_valid(notify))
        goto error;

    if (!pygio_check_cancellable(pycancellable, &cancellable))
        goto error;

    if (!pygio_notify_allocate_buffer(notify, count))
        goto error;

    pygio_notify_reference_callback(notify);
    pygio_notify_attach_to_result(notify);

    g_input_stream_read_async(G_INPUT_STREAM(self->obj),
                              notify->buffer,
                              notify->buffer_size,
                              io_priority,
                              cancellable,
                              (GAsyncReadyCallback) async_result_callback_marshal,
                              notify);

    Py_INCREF(Py_None);
    return Py_None;

 error:
    pygio_notify_free(notify);
    return NULL;
}
%%
override g_input_stream_read_finish kwargs
static PyObject *
_wrap_g_input_stream_read_finish(PyGObject *self,
                                 PyObject *args,
                                 PyObject *kwargs)
{
    static char *kwlist[] = { "result", NULL };
    PyGObject *result;
    GError *error = NULL;
    Py_ssize_t bytesread;
    PyGIONotify *notify;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
                                     "O!:gio.InputStream.read_finish",
                                     kwlist, &PyGAsyncResult_Type, &result))
        return NULL;

    bytesread = g_input_stream_read_finish(G_INPUT_STREAM(self->obj),
                                           G_ASYNC_RESULT(result->obj), &error);

    if (pyg_error_check(&error))
        return NULL;

    if (bytesread == 0)
        return PyString_FromString("");

    notify = pygio_notify_get_attached(result);
    return PyString_FromStringAndSize(notify->buffer, bytesread);
}
%%
override g_input_stream_close_async kwargs
static PyObject *
_wrap_g_input_stream_close_async(PyGObject *self,
                                 PyObject *args,
                                 PyObject *kwargs)
{
    static char *kwlist[] = { "callback", "io_priority", "cancellable",
                              "user_data", NULL };
    int io_priority = G_PRIORITY_DEFAULT;
    PyGObject *pycancellable = NULL;
    GCancellable *cancellable;
    PyGIONotify *notify;

    notify = pygio_notify_new();

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
                                     "O|iOO:InputStream.close_async",
                                     kwlist,
                                     &notify->callback,
                                     &io_priority,
                                     &pycancellable,
                                     &notify->data))
        goto error;

    if (!pygio_notify_callback_is_valid(notify))
        goto error;

    if (!pygio_check_cancellable(pycancellable, &cancellable))
        goto error;

    pygio_notify_reference_callback(notify);

    g_input_stream_close_async(G_INPUT_STREAM(self->obj),
                               io_priority,
                               cancellable,
                               (GAsyncReadyCallback)async_result_callback_marshal,
                               notify);

    Py_INCREF(Py_None);
    return Py_None;

 error:
    pygio_notify_free(notify);
    return NULL;
}
%%
override g_input_stream_skip_async kwargs
static PyObject *
_wrap_g_input_stream_skip_async(PyGObject *self,
                                PyObject *args,
                                PyObject *kwargs)
{
    static char *kwlist[] = { "count", "callback", "io_priority",
                              "cancellable", "user_data", NULL };
    long count = -1;
    int io_priority = G_PRIORITY_DEFAULT;
    PyGObject *pycancellable = NULL;
    GCancellable *cancellable;
    PyGIONotify *notify;

    notify = pygio_notify_new();

    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
                                     "lO|iOO:InputStream.skip_async",
                                     kwlist,
                                     &count,
                                     &notify->callback,
                                     &io_priority,
                                     &pycancellable,
                                     &notify->data))
        goto error;

    if (!pygio_notify_callback_is_valid(notify))
        goto error;

    if (!pygio_check_cancellable(pycancellable, &cancellable))
        goto error;

    pygio_notify_reference_callback(notify);
    

    g_input_stream_skip_async(G_INPUT_STREAM(self->obj),
                              count,
                              io_priority,
                              cancellable,
                              (GAsyncReadyCallback) async_result_callback_marshal,
                              notify);

    Py_INCREF(Py_None);
    return Py_None;

 error:
    pygio_notify_free(notify);
    return NULL;
}
