/*
 * Atom-4 Network Protocol utility functions
 * Header file
 *
 * $Id: net.h,v 1.8 2003/04/14 20:57:22 hsteoh Exp hsteoh $
 */

#ifndef NET_H
#define NET_H

#include <stdarg.h>
#include <stdlib.h>			// for size_t
#include <dlist.h>			// MUST be prog/lib version!
#include "event.h"


#define NET_LINE_LIMIT		1024	// as recommended by protocol
#define NET_BUFFER_SIZE		((NET_LINE_LIMIT)+1)


// A network message parser. This class is mainly for providing convenience
// message parsing functions.
class netparser {
  char *raw;				// [R]
  int rlen;				// length of *raw
  char *type;				// [R] first word of packet
  int curpos;				// current position in buffer

  void skip_spaces();
public:
  netparser(char *message=NULL);	// [R] *message MUST be null-terminated
  ~netparser();

  // Begin parsing a new message. Note that *message will be ALTERED as part
  // of the parsing process. The caller is responsible for saving a copy of
  // the original message if needed.
  void parse(char *message);

  // Abort parsing of current message, and reset parser state
  void reset();

  // Returns first word in packet. NULL if there is no word in packet.
  // Note that this does *not* consume any characters from the buffer.
  char *packet_type() { return type; }	// [R]

  // Calling this multiple times will retrieve individual arguments in the
  // packet.
  // - the first word in the packet is NEVER returned by this function;
  //   use packet_type() instead. The first word returned is always the
  //   first argument (i.e. second word in packet)
  // - Returns the empty string if there are no more arguments in the packet.
  char *next_word();			// [R]()

  // Returns the remainder of the packet. Note that this will consume all
  // remaining characters in packet. Returns NULL if there are no more
  // arguments left in the packet.
  char *get_rest();
};

// A generic network connection.
//
// Currently, this class implements line length limits and truncation as
// described in the protocol.
class netconn : public eventhandler {
  eventloop *loop;			// [R]
  int sock;				// network socket
  int sendlimit;			// max queued outgoing packets before
					// exception is thrown

  char rcvbuf[NET_BUFFER_SIZE];		// network buffer (circular buffer)
  size_t rcvbuf_end;			// index of first free byte in buffer

  odlist<char> sendqueue;		// outgoing packets waiting for
					// write-ready condition on socket

  int truncate:1;			// 1 if in truncate mode, 0 otherwise

  void scan_for_packets();		// scan buffer for completed packets
  void wrap_buffer(int start);		// shift buffer contents (start) bytes
					// backwards.
protected:
  // Conditions to be handled by derived class:
  // - process_packet() is called every time a completed packet is available
  // - disconnected() is called when we detect that the socket has been
  //   disconnected prematurely. The derived class should immediately
  //   trigger a cleanup process to remove this connection from the pool.
  virtual void process_packet(char *packet)=0;
  virtual void disconnected()=0;
public:
  netconn(int sock, eventloop *loop, int sendqueue_limit);
  virtual ~netconn();

  // Queue packet for sending
  int send_packet(char *fmt, ...);
  int vsend_packet(char *fmt, va_list args);

  // Access functions
  int sockfd() { return sock; }

  // Pure virtuals overridden from base class
  virtual void read_ready(eventloop *src, int fd);
  virtual void write_ready(eventloop *src, int fd);

  // Force sending of all queued outgoing packets. By default, send_packet()
  // only queues packets for sending, and waits until a write_ready() before
  // actually sending data into the socket. This function forces all pending
  // packets to be written into the socket.
  // NOTE: this function may block.
  void flush();
};


#endif // NET_H
