/*
    GSK - a library to write servers
    Copyright (C) 2001 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_XMLRPC_PROCESSOR_H_
#define __GSK_XMLRPC_PROCESSOR_H_

/* A GSK implementation of ``XMLRPC'', cf http://www.xml-rpc.com/ */

#include <glib.h>
#include <gsk/gskgtk.h>
#include "gskxmlrmiserverconfig.h"

typedef struct _GskXmlrpcProcessor GskXmlrpcProcessor;
typedef struct _GskXmlrpcNamespace GskXmlrpcNamespace;
typedef struct _GskXmlrpcParam GskXmlrpcParam;
typedef union _GskXmlrpcValue GskXmlrpcValue;
typedef struct _GskXmlrpmTypedValue GskXmlrpmTypedValue;

typedef gpointer (*GskXmlrpcNewFunc)    (gpointer              new_data);
typedef void     (*GskXmlrpcFunc)       (...);
typedef void     (*GskXmlrpcMarshaller) (GskXmlrpcParam      **params,
                                         GskXmlrpcValue       *values,
                                         gpointer              marshal_data,
                                         gpointer              user_data,
                                         GArray               *returned_typed_values);
typedef gpointer (*GskXmlrpcStructMaker)(GskXmlrpcParam       *params,
                                         GskXmlrpcValue       *values,
                                         gpointer              marshal_data);

typedef enum _GskXmlrpcType
{
  GSK_XMLRPC_NONE,
  GSK_XMLRPC_INT,
  GSK_XMLRPC_DOUBLE,
  GSK_XMLRPC_STRING,

  GSK_XMLRPC_TYPE_IS_4_BYTES = 0x100000
} GskXmlrpcType;

union _GskXmlrpcValue
{
  int i;
  gdouble d;
  gpointer p;
};

struct _GskXmlrpmTypedValue
{
  GskXmlrpcType type;
  GskXmlrpcValue value;
};

/* --- parameters --- */
/* These parameters come in several types:
       - int
       - string
       - double
       - struct [user-defined]
       - fault [user-defined]
 */
struct _GskXmlrpcParam
{
  char *param_name;
  gboolean has_default;
  GskXmlrpcType type;
  union
  {
    struct
    {
      char               *str;
    } string_data;
    struct
    {
      int                 i;
    } int_data;
    struct
    {
      GskXmlrpcNewFunc    new_func;
      gpointer            new_data;
      GDestroyNotify      destroy_new_data;
    } struct_data
  } defaults;
};

GskXmlrpcParam     *gsk_xmlrpc_param_new_int_default      (const char          *name,
                                                           int                  v);
GskXmlrpcParam     *gsk_xmlrpc_param_new_int              (const char          *name);
GskXmlrpcParam     *gsk_xmlrpc_param_new_string_default   (const char          *name,
                                                           const char          *v);
GskXmlrpcParam     *gsk_xmlrpc_param_new_string           (const char          *name);
GskXmlrpcParam     *gsk_xmlrpc_param_new_struct           (const char          *name,
                                                           GskXmlrpcType        type,
                                                           gboolean             called_func_free);
GskXmlrpcParam     *gsk_xmlrpc_param_new_struct_default   (const char          *name,
                                                           GskXmlrpcType        type,
                                                           GskXmlrpcNewFunc     new_func,
                                                           gpointer             new_data,
                                                           GDestroyNotify       destroy_new_data,
                                                           gboolean             called_func_free);
void                gsk_xmlrpc_param_destroy              (GskXmlrpcParam      *param);
                                                          
GskXmlrpcSpec      *gsk_xmlrpc_param_new_spec             (guint                num_params,
                                                           GskXmlrpcParam      *params);
                                                        
/* --- method and type spaces --- */
GskXmlrpcNamespace *gsk_xmlrpc_namespace_new              ();
void                gsk_xmlrpc_namespace_unref            (GskXmlrpcNamespace  *name_space);
void                gsk_xmlrpc_namespace_ref              (GskXmlrpcNamespace  *name_space);

/* register new substructure types */
GskXmlrpcType       gsk_xmlrpc_namespace_register_type    (GskXmlrpcNamespace  *name_space,
						           const char          *struct_name,
                                                           gboolean             is_fault,
                                                           guint                num_members,
                                                           GskXmlrpcParamSpec  *members,
                                                           GskXmlrpcStructMaker struct_maker,
                                                           gpointer             marshal_data,
                                                           guint                num_params,
                                                           ...);                    
/* register new functions */
void                gsk_xmlrpc_namespace_register_method  (GskXmlrpcNamespace  *name_space,
                                                           const char          *method,
                                                           GskXmlrpcFunc        func,
                                                           gpointer             user_data,
                                                           GDestroyNotify       destroy,
                                                           guint                num_in_params,
                                                           guint                num_out_params,
							   guint                num_allowed_fault_types,
							   /* num_in_params GskXmlrpcParam* */
							   /* num_out_params GskXmlrpcParam* */
							   /* num_allowed_fault_types GskXmlrpcType */
							   ...);
void                gsk_xmlrpc_namespace_register_method_v(GskXmlrpcNamespace  *name_space,
                                                           const char          *method,
                                                           GskXmlrpcMarshaller  marshaller,
                                                           gpointer             marshal_data,
                                                           GskXmlrpcFunc        func,
                                                           gpointer             user_data,
                                                           GDestroyNotify       destroy,
                                                           guint                num_in_params,
							   GskXmlrpcParam      *in_types,
                                                           guint                num_out_params,
                                                           GskXmlrpcParam      *out_types,
							   guint                num_allowed_fault_types,
							   GskXmlrpcType        fault_type);

/* --- GtkType/Arg <=> GskXmlrpcType helper functions --- */

/* Register a substructure type named STRUCT-NAME with the arguments and types
 * of the args of OBJECT-CLASS.  IS-FAULT determines whether STRUCT-NAME is a `fault'
 * or a `struct' according to the xmlrpc protocol.
 */
GskXmlrpcType       gsk_xmlrpc_namespace_register_gtk_type(GskXmlrpcNamespace  *name_space,
							   const char          *struct_name,
							   gboolean             is_fault,
							   GtkObjectClass      *object_class);

/* Register a gtk-argument as a function; it takes one argument named OBJECT-PARAM-NAME
 * with the type structure TYPE forcing substructure names.  The resultant function is
 * accessible through METHOD.
 */
void                gsk_xmlrpc_namespace_register_arg     (GskXmlrpcNamespace  *name_space,
							   const char          *method,
							   GtkType              type,
							   const char          *object_param_name,
							   const char          *arg_name);




                                                                              
/* --- processors --- */
GskXmlrpcProcessor *gsk_xmlrpc_processor_new              (GskXmlrpcNamespace  *name_space);
gboolean            gsk_xmlrpc_processor_input            (GskXmlrpcProcessor  *processor,
                                                           const char          *input,
                                                           int                  num_read);
gboolean            gsk_xmlrpc_processor_output           (GskXmlrpcProcessor  *processor,
                                                           const char         **buffer_out,
                                                           int                 *length_out);
gboolean            gsk_xmlrpc_processor_wrote            (GskXmlrpcProcessor  *processor,
                                                           int                  num_written);

/* If this returns TRUE, we should call gsk_xml_rpc_processor_input next.
 * If this returns FALSE, we should call gsk_xml_rpc_processor_output next.
 */
gboolean            gsk_xmlrpc_processor_reading          (GskXmlrpcProcessor  *processor);
void                gsk_xmlrpc_processor_destroy          (GskXmlrpcProcessor  *processor);

/* --- actors --- */
GskActor           *gsk_xmlrpc_server_new                 (GskXmlrpcNamespace  *name_space,
							   GskStreamSocket     *stream_socket);
GskActor           *gsk_xmlrpc_listener_new               (GskXmlrpcNamespace  *name_space,
							   GskSocketListener   *listener);


/* --- registering marshallers --- */

/* This is the system for mapping GskXmlrpcValue's to C calling conventions. */

/* XXX: do we really need this? */

/* fundamental types, in terms of having different passing policies */
typedef enum _GskXmlrpmFundType
{
  GSK_XMLRPC_FUNC_INT,
  GSK_XMLRPC_FUNC_DOUBLE,
  GSK_XMLRPC_FUNC_POINTER
} GskXmlrpmFundType;

GskXmlrpcMarshaller gsk_xmlrpc_find_marshaller_v          (guint                num_in_params,
						           guint                num_out_params,
						           gboolean             can_fault,
						           GskXmlrpmFundType   *in_types,
						           GskXmlrpmFundType   *out_types);
void                gsk_xmlrpc_register_marshaller        (guint                num_in_params,
						           guint                num_out_params,
						           gboolean             can_fault,
						           GskXmlrpmFundType   *in_types,
							   GskXmlrpmFundType   *out_types,
							   GskXmlrpcMarshaller  marshaller);



#endif
