/*
    GSK - a library to write servers
    Copyright (C) 1999    Dave Benson

    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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

    Contact:
        daveb@ffem.org <Dave Benson>
*/

#ifndef __GSK_ACTOR_STREAM_SOCKET_H_
#define __GSK_ACTOR_STREAM_SOCKET_H_

typedef struct _GskActorStreamSocket GskActorStreamSocket;
typedef struct _GskActorStreamSocketClass GskActorStreamSocketClass;

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include "gskactor.h"
#include "gskstreamsocket.h"
#include "gskbuffer.h"

/* --- type macros --- */
GtkType gsk_actor_stream_socket_get_type();
#define GSK_TYPE_ACTOR_STREAM_SOCKET			(gsk_actor_stream_socket_get_type ())
#define GSK_ACTOR_STREAM_SOCKET(obj)              (GTK_CHECK_CAST ((obj), GSK_TYPE_ACTOR_STREAM_SOCKET, GskActorStreamSocket))
#define GSK_ACTOR_STREAM_SOCKET_CLASS(klass)      (GTK_CHECK_CLASS_CAST ((klass), GSK_TYPE_ACTOR_STREAM_SOCKET, GskActorStreamSocketClass))
#define GSK_ACTOR_STREAM_SOCKET_GET_CLASS(obj)    (GSK_ACTOR_STREAM_SOCKET_CLASS(GTK_OBJECT(obj)->klass))
#define GSK_IS_ACTOR_STREAM_SOCKET(obj)           (GTK_CHECK_TYPE ((obj), GSK_TYPE_ACTOR_STREAM_SOCKET))
#define GSK_IS_ACTOR_STREAM_SOCKET_CLASS(klass)   (GTK_CHECK_CLASS_TYPE ((klass), GSK_TYPE_ACTOR_STREAM_SOCKET))

/* --- structures --- */
struct _GskActorStreamSocketClass 
{
  GskActorClass		actor_class;

  /* This function is called whenever a socket connects,
   * or if you `set_socket' with it already connected.
   */
  gboolean            (*on_connect)     (GskActorStreamSocket    *actor);

  /* Event handling */
  gboolean            (*handle_readable)(GskActorStreamSocket    *actor);
  gboolean            (*handle_writable)(GskActorStreamSocket    *actor);

  /* Timeout (after no events occur) handling. */
  gboolean            (*handle_timeout) (GskActorStreamSocket    *actor);
};

struct _GskActorStreamSocket 
{
  GskActor		actor;

  /*< read-only >*/
  GskStreamSocket      *socket;

  unsigned              fd_is_readable : 1;
  unsigned              fd_is_writable : 1;

  /*< private >*/

  /* --- the source id for the fd/socket handler in the main loop. --- */

  /* if read_fd == write_fd, just use one source */
  GskSource            *io_source;

  /* if read_fd != write_fd, we have to use two */
  GskSource            *in_io_source;
  GskSource            *out_io_source;

  /* --- the inactivity timeout handler in the main loop. --- */
  GskSource            *timer_source;

  /* which callbacks we are looking for. */
  unsigned              handle_read : 1;
  unsigned              handle_write : 1;

  /* whether to automatically remove this actor from the main loop
   * once !fd_is_readable and !fd_is_writable.  (This is the default)
   */
  unsigned              detach_once_incommunicado : 1;

  /* (ugly) flag to prevent the main loop from being removed twice 
   * (by the timeout-destroy during a removing-mainloop)
   */
  unsigned              removing_main_loop : 1;

  /* number of milliseconds without activity that trigger;
   * or 0 for no timeout.
   */
  guint                 timeout;
};

/* --- public methods --- */

/* NB: only call this once per actor */
void     gsk_actor_stream_socket_set_socket  (GskActorStreamSocket *actor,
                                              GskStreamSocket      *socket);

/* Adjust the inactivity timeout --- we will automatically remove
 * ourselves from the main loop when this happens.
 */
void     gsk_actor_stream_socket_set_timeout (GskActorStreamSocket *actor,
                                              guint                 timeout);

/* --- protected methods (for implementing derived classes only) --- */
void     gsk_actor_stream_socket_set_events  (GskActorStreamSocket *actor,
                                              gboolean              want_read,
                                              gboolean              want_write);
void     gsk_actor_stream_socket_handle_read (GskActorStreamSocket *actor,
                                              gboolean              want_read);
void     gsk_actor_stream_socket_handle_write(GskActorStreamSocket *actor,
                                              gboolean              want_write);

/* If this returns TRUE, but *num_read == -1, it means we were interrupted
 * or no data was actually read, but it isn't an error.
 */
gboolean gsk_actor_stream_socket_read        (GskActorStreamSocket *actor,
                                              char                 *buf,
					      int                   max_read,
					      int                  *num_read);
gboolean gsk_actor_stream_socket_write_from  (GskActorStreamSocket *actor,
					      GskBuffer            *outgoing,
					      int                  *err_number);
void     gsk_actor_stream_socket_stop        (GskActorStreamSocket *actor);
void     gsk_actor_stream_socket_stop_writing(GskActorStreamSocket *actor);
void     gsk_actor_stream_socket_stop_reading(GskActorStreamSocket *actor);


#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif
