/* Copyright (C) 2007 The giomm Development Team
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */

#include <glibmm/object.h>
#include <glibmm/priorities.h>
#include <glibmm/bytes.h>

#include <giomm/asyncresult.h>
#include <giomm/cancellable.h>

_DEFS(giomm,gio)
_PINCLUDE(glibmm/private/object_p.h)

namespace Gio
{

//TODO: Implement operator << and >> for streams?

/** Base class for implementing streaming input.
 *
 * @ingroup Streams
 *
 * @newin{2,16}
 */
class GIOMM_API InputStream : public Glib::Object
{
  _CLASS_GOBJECT(InputStream, GInputStream, G_INPUT_STREAM, Glib::Object, GObject, , , GIOMM_API)

protected:
  _CTOR_DEFAULT

public:
  _WRAP_METHOD(gssize read(void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable{?}),
               g_input_stream_read,
               errthrow)

  //TODO: for glibmm 2.17/18, we should decide whether to provide a read()
  // function as below, which would presumably read until EOL, or one with
  // an additional size parameter, at the same time taking into account
  // what operators >> and << (for OutputStream) will do.
  //TODO: gssize read(std::string& buffer, const Glib::RefPtr<Cancellable>& cancellable);
  //TODO: gssize read(std::string& buffer);

  _WRAP_METHOD(bool read_all(void* buffer, gsize count, gsize& bytes_read, const Glib::RefPtr<Cancellable>& cancellable{?}),
               g_input_stream_read_all,
               errthrow)

  //TODO: bool read_all(std::string& buffer, gsize count, gsize& bytes_read, const Glib::RefPtr<Cancellable>& cancellable);
  //TODO: bool read_all(std::string& buffer, gsize count, gsize& bytes_read)


  _WRAP_METHOD(Glib::RefPtr<Glib::Bytes> read_bytes(gsize count, const Glib::RefPtr<Cancellable>& cancellable), g_input_stream_read_bytes, errthrow)

  //TODO: Why not use _WRAP_METHOD() for this?
  /** Request an asynchronous read of @a count bytes from the stream into a
   * new Glib::Bytes. When the operation is finished @a slot will be called.
   * You can then call read_bytes_finish() to get the result of the
   * operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the new Glib::Bytes will be passed to the callback. It is
   * not an error if this is smaller than the requested size, as it can
   * happen e.g. near the end of a file, but generally we try to read as
   * many bytes as requested. Zero is returned on end of file (or if
   * @a count is zero), but never otherwise.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. The default priority is PRIORITY_DEFAULT.
   *
   * @param count The number of bytes that will be read from the stream.
   * @param slot Callback to call when the request is satisfied.
   * @param cancellable A Cancellable object.
   * @param io_priority The I/O priority of the request.
   *
   * @newin{2,34}
   */
  void read_bytes_async(gsize count, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Request an asynchronous read of @a count bytes from the stream into a
   * new Glib::Bytes. When the operation is finished @a slot will be called.
   * You can then call read_bytes_finish() to get the result of the
   * operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the new Glib::Bytes will be passed to the callback. It is
   * not an error if this is smaller than the requested size, as it can
   * happen e.g. near the end of a file, but generally we try to read as
   * many bytes as requested. Zero is returned on end of file (or if
   * @a count is zero), but never otherwise.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. The default priority is PRIORITY_DEFAULT.
   *
   * @param count The number of bytes that will be read from the stream.
   * @param slot Callback to call when the request is satisfied.h
   * @param io_priority The I/O priority of the request.
   *
   * @newin{2,34}
   */
  void read_bytes_async(gsize count, const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_input_stream_read_bytes_async)

  _WRAP_METHOD(Glib::RefPtr<Glib::Bytes> read_bytes_finish(const Glib::RefPtr<AsyncResult>& result), g_input_stream_read_bytes_finish, errthrow)



  _WRAP_METHOD(gssize skip(gsize count, const Glib::RefPtr<Cancellable>& cancellable{?}),
               g_input_stream_skip,
               errthrow)

  _WRAP_METHOD(bool close(const Glib::RefPtr<Cancellable>& cancellable{?}),
               g_input_stream_close,
               errthrow)


  /** Request an asynchronous read of @a count bytes from the stream into the buffer
   * starting at @a buffer. When the operation is finished @a slot will be called.
   * You can then call read_finish() to get the result of the
   * operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes read into the buffer will be passed to the
   * @a slot callback. It is not an error if this is not the same as the requested size, as it
   * can happen e.g. near the end of a file, but generally we try to read
   * as many bytes as requested. Zero is returned on end of file
   * (or if @a count is zero), but never otherwise.
   *
   * Any outstanding i/o request with higher priority (lower numerical value) will
   * be executed before an outstanding request with lower priority. Default
   * priority is PRIORITY_DEFAULT.
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param buffer A buffer to read data into (which should be at least count bytes long).
   * @param count The number of bytes that will be read from the stream.
   * @param slot Callback to call when the request is satisfied.
   * @param cancellable A Cancellable object.
   * @param io_priority The I/O priority of the request.
   */
  void read_async(void* buffer, gsize count, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Request an asynchronous read of @a count bytes from the stream into the buffer
   * starting at @a buffer. When the operation is finished @a slot will be called.
   * You can then call read_finish() to get the result of the
   * operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in a Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes read into the buffer will be passed to the
   * @a slot callback. It is not an error if this is not the same as the requested size, as it
   * can happen e.g. near the end of a file, but generally we try to read
   * as many bytes as requested. Zero is returned on end of file
   * (or if @a count is zero), but never otherwise.
   *
   * Any outstanding i/o request with higher priority (lower numerical value) will
   * be executed before an outstanding request with lower priority. Default
   * priority is PRIORITY_DEFAULT.
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param buffer A buffer to read data into (which should be at least count bytes long).
   * @param count The number of bytes that will be read from the stream.
   * @param slot Callback to call when the request is satisfied.
   * @param io_priority The I/O priority of the request.
   */
  void read_async(void* buffer, gsize count, const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_input_stream_read_async)

  _WRAP_METHOD(gssize read_finish(const Glib::RefPtr<AsyncResult>& result),
               g_input_stream_read_finish,
               errthrow)


  /** Request an asynchronous read of @a count bytes from the stream into the buffer
   * starting at @a buffer. This is the asynchronous equivalent of read_all().
   *
   * When the operation is finished @a slot will be called.
   * You can then call read_all_finish() to get the result of the
   * operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes read into the buffer will be passed to the
   * @a slot callback. It is not an error if this is not the same as the requested size, as it
   * can happen e.g. near the end of a file, but generally we try to read
   * as many bytes as requested. Zero is returned on end of file
   * (or if @a count is zero), but never otherwise.
   *
   * Any outstanding i/o request with higher priority (lower numerical value) will
   * be executed before an outstanding request with lower priority. Default
   * priority is PRIORITY_DEFAULT.
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param buffer A buffer to read data into (which should be at least count bytes long).
   * @param count The number of bytes that will be read from the stream.
   * @param slot Callback to call when the request is satisfied.
   * @param cancellable A Cancellable object.
   * @param io_priority The I/O priority of the request.
   */
  void read_all_async(void* buffer, gsize count, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Request an asynchronous read of @a count bytes from the stream into the buffer
   * starting at @a buffer. This is the asynchronous equivalent of read_all().
   *
   * When the operation is finished @a slot will be called.
   * You can then call read_all_finish() to get the result of the
   * operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in a Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes read into the buffer will be passed to the
   * @a slot callback. It is not an error if this is not the same as the requested size, as it
   * can happen e.g. near the end of a file, but generally we try to read
   * as many bytes as requested. Zero is returned on end of file
   * (or if @a count is zero), but never otherwise.
   *
   * Any outstanding i/o request with higher priority (lower numerical value) will
   * be executed before an outstanding request with lower priority. Default
   * priority is PRIORITY_DEFAULT.
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param buffer A buffer to read data into (which should be at least count bytes long).
   * @param count The number of bytes that will be read from the stream.
   * @param slot Callback to call when the request is satisfied.
   * @param io_priority The I/O priority of the request.
   */
  void read_all_async(void* buffer, gsize count, const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_input_stream_read_all_async)

  _WRAP_METHOD(bool read_all_finish(const Glib::RefPtr<AsyncResult>& result, gsize& bytes_read),
               g_input_stream_read_all_finish,
               errthrow)


  //TODO: Use std::size_type instead of gsize?

  /** Request an asynchronous skip of @a count bytes from the stream into the buffer
   * starting at @a buffer. When the operation is finished @a slot will be called.
   * You can then call skip_finish() to get the result of the operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes skipped will be passed to the
   * callback. It is not an error if this is not the same as the requested size, as it
   * can happen e.g. near the end of a file, but generally we try to skip
   * as many bytes as requested. Zero is returned on end of file
   * (or if @a count is zero), but never otherwise.
   *
   * Any outstanding i/o request with higher priority (lower numerical value) will
   * be executed before an outstanding request with lower priority. Default
   * priority is PRIORITY_DEFAULT.
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param count The number of bytes that will be skipped from the stream.
   * @param slot Callback to call when the request is satisfied.
   * @param cancellable A Cancellable object.
   * @param io_priority The I/O priority of the request.
   */
  void skip_async(gsize count, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Request an asynchronous skip of @a count bytes from the stream into the buffer
   * starting at @a buffer. When the operation is finished @a slot will be called.
   * You can then call skip_finish() to get the result of the operation.
   *
   * During an async request no other sync and async calls are allowed, and will
   * result in Gio::Error with PENDING being thrown.
   *
   * A value of @a count larger than MAXSSIZE will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes skipped will be passed to the
   * callback. It is not an error if this is not the same as the requested size, as it
   * can happen e.g. near the end of a file, but generally we try to skip
   * as many bytes as requested. Zero is returned on end of file
   * (or if @a count is zero), but never otherwise.
   *
   * Any outstanding i/o request with higher priority (lower numerical value) will
   * be executed before an outstanding request with lower priority. Default
   * priority is PRIORITY_DEFAULT.
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param count The number of bytes that will be skipped from the stream.
   * @param slot Callback to call when the request is satisfied.
   * @param io_priority The I/O priority of the request.
   */
  void skip_async(gsize count, const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_input_stream_skip_async)

  _WRAP_METHOD(gssize skip_finish(const Glib::RefPtr<AsyncResult>& result),
               g_input_stream_skip_finish,
               errthrow)

  /** Requests an asynchronous closes of the stream, releasing resources related to it.
   * When the operation is finished @a slot will be called.
   * You can then call close_finish() to get the result of the
   * operation.
   *
   * For behaviour details see close().
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param slot Callback to call when the request is satisfied.
   * @param cancellable A Cancellable object.
   * @param io_priority The I/O priority of the request.
   */
  void close_async(const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Requests an asynchronous closes of the stream, releasing resources related to it.
   * When the operation is finished @a slot will be called.
   * You can then call close_finish() to get the result of the
   * operation.
   *
   * For behaviour details see close().
   *
   * The asyncronous methods have a default fallback that uses threads to implement
   * asynchronicity, so they are optional for inheriting classes. However, if you
   * override one you must override all.
   *
   * @param slot Callback to call when the request is satisfied.
   * @param io_priority The I/O priority of the request.
   */
  void close_async(const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_input_stream_close_async)

  _WRAP_METHOD(gboolean close_finish(const Glib::RefPtr<AsyncResult>& result),
               g_input_stream_close_finish,
               errthrow)

  _WRAP_METHOD(bool is_closed() const, g_input_stream_is_closed, newin "2,50")
  _WRAP_METHOD(bool has_pending() const, g_input_stream_has_pending, newin "2,50")

protected:
  _WRAP_METHOD(bool set_pending(), g_input_stream_set_pending, errthrow, newin "2,50")
  _WRAP_METHOD(void clear_pending(), g_input_stream_clear_pending, newin "2,50")

#m4 _CONVERSION(`GCancellable*', `const Glib::RefPtr<Cancellable>&', `Glib::wrap($3, true)')
  _WRAP_VFUNC(gssize read(void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable), read_fn, errthrow, err_return_value -1)
  _WRAP_VFUNC(gssize skip(gsize count, const Glib::RefPtr<Cancellable>& cancellable), skip, errthrow, err_return_value -1)
  _WRAP_VFUNC(bool close(const Glib::RefPtr<Cancellable>& cancellable), close_fn, errthrow)
};

} // namespace Gio
