/* Copyright (C) 2007 The gtkmm 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 <giomm/asyncresult.h>
#include <giomm/cancellable.h>
#include <giomm/inputstream.h>

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

namespace Gio
{

_WRAP_ENUM(OutputStreamSpliceFlags, GOutputStreamSpliceFlags, NO_GTYPE, decl_prefix GIOMM_API)

/** Base class for implementing streaming output.
 *
 * @ingroup Streams
 *
 * @newin{2,16}
 */
class GIOMM_API OutputStream : public Glib::Object
{
  _CLASS_GOBJECT(OutputStream, GOutputStream, G_OUTPUT_STREAM, Glib::Object, GObject, , , GIOMM_API)

protected:
  _CTOR_DEFAULT

public:

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

  /** Tries to write @a count  bytes from @a buffer  into the stream. Will block
   * during the operation.
   *
   * If count is zero returns zero and does nothing. 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 written to the stream is returned.
   * It is not an error if this is not the same as the requested size, as it
   * can happen e.g. on a partial i/o error, or if the there is not enough
   * storage in the stream. All writes either block until at least one byte
   * is written, so zero is never returned (unless @a count  is zero).
   *
   * On error -1 is returned.
   * @param buffer The buffer containing the data to write.
   * @param cancellable Cancellable object.
   * @return Number of bytes written, or -1 on error.
   */
  gssize write(const std::string& buffer, const Glib::RefPtr<Cancellable>& cancellable);

  /** Tries to write @a count  bytes from @a buffer  into the stream. Will block
   * during the operation.
   *
   * If string that is larger than MAXSSIZE bytes will cause a Gio::Error with INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes written to the stream is returned.
   * It is not an error if this is not the same as the requested size, as it
   * can happen e.g. on a partial i/o error, or if the there is not enough
   * storage in the stream. All writes either block until at least one byte
   * is written, so zero is never returned (unless @a count  is zero).
   *
   * On error -1 is returned.
   * @param buffer The buffer containing the data to write.
   * @return Number of bytes written, or -1 on error.
   */
  gssize write(const std::string& buffer);


  _WRAP_METHOD(bool write_all(const void* buffer, gsize count, gsize& bytes_written, const Glib::RefPtr<Cancellable>& cancellable{?}),
               g_output_stream_write_all,
               errthrow)

  /** Tries to write @a count  bytes from @a buffer into the stream. Will block
   * during the operation.
   *
   * This function is similar to write(), except it tries to
   * write as many bytes as requested, only stopping on an error.
   *
   * On a successful write of @a count  bytes, <tt>true</tt> is returned, and @a bytes_written
   * is set to @a count .
   *
   * If there is an error during the operation <tt>false</tt> is returned and @a error
   * is set to indicate the error status, @a bytes_written  is updated to contain
   * the number of bytes written into the stream before the error occured.
   * @param buffer The buffer containing the data to write.
   * @param bytes_written Location to store the number of bytes that was
   * written to the stream.
   * @param cancellable Cancellable object.
   * @return <tt>true</tt> on success, <tt>false</tt> if there was an error.
   */
  bool write_all(const std::string& buffer, gsize& bytes_written, const Glib::RefPtr<Cancellable>& cancellable);

  /** Tries to write @a count  bytes from @a buffer into the stream. Will block
   * during the operation.
   *
   * This function is similar to write(), except it tries to
   * write as many bytes as requested, only stopping on an error.
   *
   * On a successful write of @a count  bytes, <tt>true</tt> is returned, and @a bytes_written
   * is set to @a count .
   *
   * If there is an error during the operation <tt>false</tt> is returned and @a error
   * is set to indicate the error status, @a bytes_written  is updated to contain
   * the number of bytes written into the stream before the error occured.
   * @param buffer The buffer containing the data to write.
   * @param bytes_written Location to store the number of bytes that was
   * written to the stream.
   * @return <tt>true</tt> on success, <tt>false</tt> if there was an error.
   */
  bool write_all(const std::string& buffer, gsize& bytes_written);

  _WRAP_METHOD(gssize write_bytes(const Glib::RefPtr<const Glib::Bytes>& bytes, const Glib::RefPtr<Cancellable>& cancellable{?}), g_output_stream_write_bytes, errthrow)

  /** Request an asynchronous write of the data in @a bytes to the stream.
   * When the operation is finished @a slot will be called. You can
   * then call write_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 Glib:Bytes larger than MAXSSIZE will cause a Gio::Error with
   * INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes written will be passed to the
   * callback @a slot. It is not an error if this is not the same as the
   * requested size, as it can happen e.g. on a partial I/O error,
   * but generally we try to write as many bytes as requested.
   *
   * You are guaranteed that this method will never fail with
   * IO_ERROR_WOULD_BLOCK - if the stream can't accept more data, the
   * method will just wait until this changes.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. Default priority is Glib::PRIORITY_DEFAULT.
   *
   * For the synchronous, blocking version of this function, see write_bytes().
   *
   * @param bytes The bytes to
   * @param slot Callback slot to call when the request is satisfied.
   * @param cancellable Cancellable object.
   * @param io_priority The io priority of the request.
   *
   * @newin{2,34}
   */
  void write_bytes_async(const Glib::RefPtr<const Glib::Bytes>& bytes, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Request an asynchronous write of the data in @a bytes to the stream.
   * When the operation is finished @a slot will be called. You can
   * then call write_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 Glib:Bytes larger than MAXSSIZE will cause a Gio::Error with
   * INVALID_ARGUMENT to be thrown.
   *
   * On success, the number of bytes written will be passed to the
   * callback @a slot. It is not an error if this is not the same as the
   * requested size, as it can happen e.g. on a partial I/O error,
   * but generally we try to write as many bytes as requested.
   *
   * You are guaranteed that this method will never fail with
   * IO_ERROR_WOULD_BLOCK - if the stream can't accept more data, the
   * method will just wait until this changes.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. Default priority is Glib::PRIORITY_DEFAULT.
   *
   * For the synchronous, blocking version of this function, see write_bytes().
   *
   * @param bytes The bytes to
   * @param slot Callback slot to call when the request is satisfied.
   * @param io_priority The io priority of the request.
   *
   * @newin{2,34}
   */
  void write_bytes_async(const Glib::RefPtr<const Glib::Bytes>& bytes, const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_output_stream_write_bytes_async)

  _WRAP_METHOD(gssize write_bytes_finish(const Glib::RefPtr<AsyncResult>& result), g_output_stream_write_bytes_finish, errthrow)

  /** Splices an input stream into an output stream.
   *
   * @param source An InputStream.
   * @param flags A set of OutputStreamSpliceFlags.
   * @param cancellable A Cancellable object.
   * ignore.
   * @return A #gssize containing the size of the data spliced.
   */
  gssize splice(const Glib::RefPtr<InputStream>& source, const Glib::RefPtr<Cancellable>& cancellable, OutputStreamSpliceFlags flags = OUTPUT_STREAM_SPLICE_NONE);

  /** Splices an input stream into an output stream.
   *
   * @param source An InputStream.
   * @param flags A set of OutputStreamSpliceFlags.
   * ignore.
   * @return A #gssize containing the size of the data spliced.
   */
  gssize splice(const Glib::RefPtr<InputStream>& source, OutputStreamSpliceFlags flags = OUTPUT_STREAM_SPLICE_NONE);
  _IGNORE(g_output_stream_splice)

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

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

  /** Request an asynchronous write of @a count bytes from @a buffer into
   * the stream. When the operation is finished @a slot will be called.
   * You can then call write_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 written will be passed to the
   * callback @a slot. It is not an error if this is not the same as the
   * requested size, as it can happen e.g. on a partial I/O error,
   * but generally we try to write as many bytes as requested.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. Default priority is Glib::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.
   *
   * For the synchronous, blocking version of this function, see
   * write().
   *
   * Note that no copy of @a buffer will be made, so it must stay valid
   * until @a slot is called. See write_bytes_async()
   * for a Glib::Bytes version that will automatically hold a reference to
   * the contents (without copying) for the duration of the call.
   *
   * @param buffer The buffer containing the data to write.
   * @param count The number of bytes to write
   * @param slot Callback slot to call when the request is satisfied.
   * @param cancellable Cancellable object.
   * @param io_priority The io priority of the request.
   */
  void write_async(const void* buffer, gsize count, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Request an asynchronous write of @a count bytes from @a buffer into
   * the stream. When the operation is finished @a slot will be called.
   * You can then call write_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 written will be passed to the
   * callback @a slot. It is not an error if this is not the same as the
   * requested size, as it can happen e.g. on a partial I/O error,
   * but generally we try to write as many bytes as requested.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. Default priority is Glib::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.
   *
   * For the synchronous, blocking version of this function, see
   * write().

   * Note that no copy of @a buffer will be made, so it must stay valid
   * until @a slot is called. See write_bytes_async()
   * for a Glib::Bytes version that will automatically hold a reference to
   * the contents (without copying) for the duration of the call.
   *
   * @param buffer The buffer containing the data to write.
   * @param count The number of bytes to write
   * @param slot Callback slot to call when the request is satisfied.
   * @param io_priority The io priority of the request.
   */
  void write_async(const void* buffer, gsize count, const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_output_stream_write_async)

  _WRAP_METHOD(gssize write_finish(const Glib::RefPtr<AsyncResult>& result),
               g_output_stream_write_finish,
               errthrow)


  /** Request an asynchronous write of @a count bytes from @a buffer into
   * the stream. When the operation is finished @a slot will be called.
   * You can then call write_all_finish() to get the result of the
   * operation.
   *
   * This is the asynchronous version of write_all().
   *
   * 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 written will be passed to the
   * callback @a slot. It is not an error if this is not the same as the
   * requested size, as it can happen e.g. on a partial I/O error,
   * but generally we try to write as many bytes as requested.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. Default priority is Glib::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.
   *
   * For the synchronous, blocking version of this function, see
   * write().
   *
   * Note that no copy of @a buffer will be made, so it must stay valid
   * until @a slot is called.
   *
   * @param buffer The buffer containing the data to write.
   * @param count The number of bytes to write
   * @param slot Callback slot to call when the request is satisfied.
   * @param cancellable Cancellable object.
   * @param io_priority The io priority of the request.
   */
  void write_all_async(const void* buffer, gsize count, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Request an asynchronous write of @a count bytes from @a buffer into
   * the stream. When the operation is finished @a slot will be called.
   * You can then call write_finish() to get the result of the
   * operation.
   *
   * This is the asynchronous version of write_all().
   *
   * 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 written will be passed to the
   * callback @a slot. It is not an error if this is not the same as the
   * requested size, as it can happen e.g. on a partial I/O error,
   * but generally we try to write as many bytes as requested.
   *
   * Any outstanding I/O request with higher priority (lower numerical
   * value) will be executed before an outstanding request with lower
   * priority. Default priority is Glib::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.
   *
   * For the synchronous, blocking version of this function, see
   * write().
   *
   * Note that no copy of @a buffer will be made, so it must stay valid
   * until @a slot is called.
   *
   * @param buffer The buffer containing the data to write.
   * @param count The number of bytes to write
   * @param slot Callback slot to call when the request is satisfied.
   * @param io_priority The io priority of the request.
   */
  void write_all_async(const void* buffer, gsize count, const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_output_stream_write_all_async)

  _WRAP_METHOD(bool write_all_finish(const Glib::RefPtr<AsyncResult>& result, gsize& bytes_written),
               g_output_stream_write_all_finish,
               errthrow)


  /** Splices a stream asynchronously.
   *  When the operation is finished @a slot will be called.
   * You can then call splice_finish() to get the result of the
   * operation.
   *
   * For the synchronous, blocking version of this function, see
   * splice().
   *
   * @param source An InputStream.
   * @param slot Callback slot to call when the request is satisfied.
   * @param cancellable Cancellable object.
   * @param flags A set of OutputStreamSpliceFlags.
   * @param io_priority The io priority of the request.
   */
  void splice_async(const Glib::RefPtr<InputStream>& source, const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, OutputStreamSpliceFlags flags = OUTPUT_STREAM_SPLICE_NONE, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Splices a stream asynchronously.
   *  When the operation is finished @a slot will be called.
   * You can then call splice_finish() to get the result of the
   * operation.
   *
   * For the synchronous, blocking version of this function, see
   * splice().
   *
   * @param source An InputStream.
   * @param slot Callback slot to call when the request is satisfied.
   * @param flags A set of OutputStreamSpliceFlags.
   * @param io_priority The io priority of the request.
   */
  void splice_async(const Glib::RefPtr<InputStream>& source, const SlotAsyncReady& slot, OutputStreamSpliceFlags flags = OUTPUT_STREAM_SPLICE_NONE, int io_priority = Glib::PRIORITY_DEFAULT);

  _IGNORE(g_output_stream_splice_async)

  _WRAP_METHOD(gssize splice_finish(const Glib::RefPtr<AsyncResult>& result),
               g_output_stream_splice_finish,
               errthrow)

  /** Flushes a stream asynchronously.
   * When the operation is finished the @a slot will be called, giving the results.
   * You can then call flush_finish() to get the result of the operation.
   * For behaviour details see flush().
   *
   * @param slot Callback slot to call when the request is satisfied.
   * @param cancellable Cancellable object.
   * @param io_priority The io priority of the request.
   */
  void flush_async(const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Flushes a stream asynchronously.
   * When the operation is finished the @a slot will be called, giving the results.
   * You can then call flush_finish() to get the result of the operation.
   * For behaviour details see flush().
   *
   * @param slot Callback slot to call when the request is satisfied.
   * @param io_priority The io priority of the request.
   */
  void flush_async(const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_output_stream_flush_async)

  _WRAP_METHOD(bool flush_finish(const Glib::RefPtr<AsyncResult>& result),
               g_output_stream_flush_finish,
               errthrow)

  /** Requests an asynchronous close of the stream, releasing resources related to it.
   * When the operation is finished the @a slot will be called, giving the results.
   * 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 slot to call when the request is satisfied.
   * @param cancellable Cancellable object.
   * @param io_priority The io priority of the request.
   */
  void close_async(const SlotAsyncReady& slot, const Glib::RefPtr<Cancellable>& cancellable, int io_priority = Glib::PRIORITY_DEFAULT);

  /** Requests an asynchronous close of the stream, releasing resources related to it.
   * When the operation is finished the @a slot will be called, giving the results.
   * 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 slot to call when the request is satisfied.
   * @param io_priority The io priority of the request.
   */
  void close_async(const SlotAsyncReady& slot, int io_priority = Glib::PRIORITY_DEFAULT);
  _IGNORE(g_output_stream_close_async)

  _WRAP_METHOD(bool close_finish(const Glib::RefPtr<AsyncResult>& result),
               g_output_stream_close_finish,
               errthrow)

  _WRAP_METHOD(bool is_closed() const, g_output_stream_is_closed, newin "2,50")
  _WRAP_METHOD(bool is_closing() const, g_output_stream_is_closing, newin "2,50")
  _WRAP_METHOD(bool has_pending() const, g_output_stream_has_pending, newin "2,50")

protected:
  _WRAP_METHOD(bool set_pending(), g_output_stream_set_pending, errthrow, newin "2,50")
  _WRAP_METHOD(void clear_pending(), g_output_stream_clear_pending, newin "2,50")

  //TODO: When we can break ABI, add vfuncs. See https://bugzilla.gnome.org/show_bug.cgi?id=572471
#m4 _CONVERSION(`GCancellable*', `const Glib::RefPtr<Cancellable>&', `Glib::wrap($3, true)')
#m4 _CONVERSION(`GInputStream*', `const Glib::RefPtr<InputStream>&', `Glib::wrap($3, true)')
  //_WRAP_VFUNC(gssize write(const void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable), write_fn, errthrow, err_return_value -1)
  //_WRAP_VFUNC(gssize splice(const Glib::RefPtr<InputStream>& source, const Glib::RefPtr<Cancellable>& cancellable{.}, OutputStreamSpliceFlags flags{.}), splice, errthrow, err_return_value -1)
  //_WRAP_VFUNC(bool flush(const Glib::RefPtr<Cancellable>& cancellable), flush, errthrow)
  //_WRAP_VFUNC(bool close(const Glib::RefPtr<Cancellable>& cancellable), close_fn, errthrow)
};

} // namespace Gio
