/*
    GSK - a library to write servers
    Copyright (C) 1999-2000 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>
*/


/*
 * GskActorParser:  a buffered actor which slices (in very simple ways)
 *                  its input up, and calls the "on_parse" virtual.
 */

#ifndef __GSK_ACTOR_PARSER_H_
#define __GSK_ACTOR_PARSER_H_

typedef struct _GskActorParser GskActorParser;
typedef struct _GskActorParserClass GskActorParserClass;

#include "gskactor.h"

/* --- type macros --- */
GtkType gsk_actor_parser_get_type();
#define GSK_TYPE_ACTOR_PARSER		   (gsk_actor_parser_get_type ())
#define GSK_ACTOR_PARSER(obj)              (GTK_CHECK_CAST ((obj), GSK_TYPE_ACTOR_PARSER, GskActorParser))
#define GSK_ACTOR_PARSER_CLASS(klass)      (GTK_CHECK_CLASS_CAST ((klass), GSK_TYPE_ACTOR_PARSER, GskActorParserClass))
#define GSK_ACTOR_PARSER_GET_CLASS(obj)    (GSK_ACTOR_PARSER_CLASS(GTK_OBJECT(obj)->klass))
#define GSK_IS_ACTOR_PARSER(obj)           (GTK_CHECK_TYPE ((obj), GSK_TYPE_ACTOR_PARSER))
#define GSK_IS_ACTOR_PARSER_CLASS(klass)   (GTK_CHECK_CLASS_TYPE ((klass), GSK_TYPE_ACTOR_PARSER))

#include "gskactorbuffered.h"

/* --- class structure --- */
struct _GskActorParserClass {
  GskActorBufferedClass klass;
  /*
   * on_parse(parser, parsed_data, parsed_data_len)
   *   This function is invoked whenever a piece
   *   on input is parsed.
   * 
   *   Parameters:
   *     parser       The parser which finished the token.
   *     parsed_data  The data we parsed.
   *     parsed_len   The amount of data we parsed in bytes.
   */
  gboolean            (*on_parse)(GskActorParser *parser,
                                  void           *parsed_data,
                                  guint           parsed_len);
};

/* --- parsing options --- */
/*
 * GskActorParserMode
 * 
 * `parse_mode' in the GskActorParser.
 * 
 * Various ways we can parse:
 * 
 *   TERMINATED      Variable-length strings ending w/ a specific char.
 *   BINARY          Fixed-length binary records.
 *   LENGTH_PREFIXED Store a 32-bit number indicating
 *                   the total size of the request.
 */
typedef enum {
  GSK_ACTOR_PARSER_TERMINATED = 100,
  GSK_ACTOR_PARSER_BINARY,
  GSK_ACTOR_PARSER_LENGTH_PREFIXED
} GskActorParserMode;

/* --- structures --- */
struct _GskActorParser
{
  GskActorBuffered actor;

  /* A GskActorParserMode specifying which type of
   * record we are parsing. */
  GskActorParserMode parse_mode;

  /* Various parsing mechanisms. */
  /*< private >*/
  union
  {
    struct
    {
      char terminal_char;
      gboolean chomp;
    }
    character_separated;
    struct
    {
      int total_length;
    }
    binary;
    struct
    {
      int prefix_bytes;
      GskByteOrder byte_order;
      int length_offset;
    }
    length_prefixed;
  }
  parser;

  guint had_eof : 1;

  guint input_block_count : 31;

  /* Data that doesn't yet end the record, but is pending. */
  GskBuffer parse_buffer;
};

/* --- setting the parse mode
       (to be used by the implementations of derived classes) --- */

/* Functions to specify what kind of token `on_parse' will
 * be invoked on next.
 *
 * It is perfectly safe to call this from within an
 * on_parse handler-- it will just affect the next token,
 * of course. */
void    gsk_actor_parser_parse_line           (GskActorParser *actor_parser,
                                               int             terminal_char,
                                               gboolean        chomp);
void    gsk_actor_parser_parse_binary         (GskActorParser *actor_parser,
                                               int             length);

/* Parse modes where the length is transmitted first,
 * then raw data of that specified length is transmitted.
 *
 * prefix_bytes  is how many bytes (up to 4) the length header is 
 * byte_order    is the byte order (aka endianness) of the length header;
 *               G_BYTE_ORDER is native endian which is always either
 *               G_LITTLE_ENDIAN or G_BIG_ENDIAN.
 * length_offset is the number of bytes to add to the length header 
 *               to get the actual length. [XXX: clarify this!]
 */
void    gsk_actor_parser_parse_length_prefixed(GskActorParser *actor_parser,
                                               int             prefix_bytes,
                                               GskByteOrder    byte_order,
                                               int             length_offset);

/* --- blocking the parse process --- */

/* Prevent `on_parse' from being invoked,
 * until the paired unblock_input is run.
 */
void    gsk_actor_parser_block_input          (GskActorParser *actor_parser);
void    gsk_actor_parser_unblock_input        (GskActorParser *actor_parser);

#ifndef GSK_DISABLE_COMPAT
#define GSK_ACTOR_PARSER_BIG_ENDIAN    G_BIG_ENDIAN
#define GSK_ACTOR_PARSER_LITTLE_ENDIAN G_LITTLE_ENDIAN
#define GskActorParserByteOrder        GskByteOrder
#endif

#endif
