#include "gskpacketqueue.h"
#include "gskmacros.h"

static GObjectClass *parent_class = NULL;

static void
gsk_packet_queue_finalize (GObject *object)
{
  GskPacketQueue *queue = GSK_PACKET_QUEUE (object);
  if (queue->bound_address != NULL)
    g_object_unref (queue->bound_address);
  (*parent_class->finalize) (object);
}

/* --- functions --- */
static void
gsk_packet_queue_init (GskPacketQueue *packet_queue)
{
}
static void
gsk_packet_queue_class_init (GskPacketQueueClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  parent_class = g_type_class_peek_parent (class);
  object_class->finalize = gsk_packet_queue_finalize;
}

GType gsk_packet_queue_get_type()
{
  static GType packet_queue_type = 0;
  if (!packet_queue_type)
    {
      static const GTypeInfo packet_queue_info =
      {
	sizeof(GskPacketQueueClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gsk_packet_queue_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
	sizeof (GskPacketQueue),
	0,		/* n_preallocs */
	(GInstanceInitFunc) gsk_packet_queue_init,
	NULL		/* value_table */
      };
      packet_queue_type = g_type_register_static (GSK_TYPE_IO,
                                                  "GskPacketQueue",
						  &packet_queue_info, 
						  G_TYPE_FLAG_ABSTRACT);
    }
  return packet_queue_type;
}

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

/**
 * gsk_packet_queue_bind:
 * @queue: the packet queue to bind to a particular address.
 * @address: the address to receive packets from.
 * @error: optional error return value.
 *
 * Bind a packet queue to receive on a particular address.
 *
 * returns: whether the bind call succeeded.
 */
gboolean
gsk_packet_queue_bind   (GskPacketQueue    *queue,
			 GskSocketAddress  *address,
			 GError           **error)
{
  GskPacketQueueClass *class = GSK_PACKET_QUEUE_GET_CLASS (queue);
  if (class->bind == NULL)
    {
      g_set_error (error, GSK_G_ERROR_DOMAIN,
                   GSK_ERROR_BIND_UNAVAILABLE,
		   _("no bind method for %s"),
		   g_type_name (G_OBJECT_TYPE (queue)));
      return FALSE;
    }
  if (! (*class->bind) (queue, address, error))
    {
      if (error && !*error)
	g_set_error (error, GSK_G_ERROR_DOMAIN,
		     GSK_ERROR_BIND_FAILED,
		     _("bind on %s failed, no specific error message"),
		     g_type_name (G_OBJECT_TYPE (queue)));
      return FALSE;
    }
  gsk_packet_queue_set_bound_addresss (queue, address);
  return TRUE;
}

/**
 * gsk_packet_queue_read:
 * @queue: to try to read a packet from
 * @save_address: whether to create a remote address indication.
 * @error: optional error return value.
 *
 * Read a packet from the queue, optionally tracking whence it came.
 *
 * returns: a new packet, or NULL on error or if no packet was available.
 */
GskPacket *
gsk_packet_queue_read   (GskPacketQueue    *queue,
			 gboolean           save_address,
			 GError           **error)
{
  GskPacketQueueClass *class = GSK_PACKET_QUEUE_GET_CLASS (queue);
  g_return_val_if_fail (!save_address || queue->allow_address, NULL);
  return (*class->read) (queue, save_address, error);
}

/**
 * gsk_packet_queue_write:
 * @queue: to try to write a packet to
 * @out: outgoing packet.
 * @error: optional error return value.
 *
 * Try and write a packet to the queue.
 * If the packet has no address, then the packet-queue must allow_no_address.
 * If the packet has an address, then the packet-queue must allow_address.
 *
 * returns: whether the write succeeded.
 */
gboolean
gsk_packet_queue_write  (GskPacketQueue    *queue,
			 GskPacket         *out,
			 GError           **error)
{
  GskPacketQueueClass *class = GSK_PACKET_QUEUE_GET_CLASS (queue);
  g_return_val_if_fail (out->dst_address == NULL || queue->allow_address, FALSE);
  g_return_val_if_fail (out->dst_address != NULL || queue->allow_no_address, FALSE);
  return (*class->write) (queue, out, error);
}

/* --- protected methods --- */
/**
 * gsk_packet_queue_set_bound_addresss:
 * @queue: queue to mark
 * @address: address to which the queue has been bound.
 *
 * Set the bound_address member of the packet-queue safely.
 *
 * This should only be called by implementations
 * which automatically bind to certain addresses.
 */
void
gsk_packet_queue_set_bound_addresss (GskPacketQueue   *queue,
				     GskSocketAddress *address)
{
  GskSocketAddress *old_address = queue->bound_address;
  queue->bound_address = address;
  if (address != NULL)
    g_object_ref (address);
  if (old_address != NULL)
    g_object_unref (old_address);
}


syntax highlighted by Code2HTML, v. 0.9.1