#ifndef _GLOBUS_RENDEZVOUS_H_
#define _GLOBUS_RENDEZVOUS_H_

#include "globus_common.h"

EXTERN_C_BEGIN

#include "globus_soap_message_attrs.h"
#include "xsd_QName.h"

/**
 * error types
 */
typedef enum
{
    GLOBUS_RZ_ERROR_TYPE_OUT_OF_MEMORY,
    GLOBUS_RZ_ERROR_TYPE_FAILED_ATTR_INIT,
    GLOBUS_RZ_ERROR_TYPE_INIT_FAILED,
    GLOBUS_RZ_ERROR_TYPE_REGISTER_FAILED,
    GLOBUS_RZ_ERROR_TYPE_REQUEST_ALREADY_BEGUN,
    GLOBUS_RZ_ERROR_TYPE_DATA_REQUEST_FAILED,
    GLOBUS_RZ_ERROR_TYPE_SUBSCRIBE_FAILED,
    GLOBUS_RZ_ERROR_TYPE_POLL_FAILED,
    GLOBUS_RZ_ERROR_TYPE_INVALID_TOPIC,
    GLOBUS_RZ_ERROR_TYPE_INVALID_MESSAGE_TYPE,
    GLOBUS_RZ_ERROR_TYPE_INVALID_POLL_RESPONSE,
    GLOBUS_RZ_ERROR_TYPE_SHUTDOWN_FAILED
} globus_rendezvous_error_type_t;

extern xsd_QName                        wsgram_ResourceID_qname;

/**
 * result is GLOBUS_SUCCESS if the RendezvousCompleted state
 * was received (and true), either via notifications or by
 * polling.  If result != GLOBUS_SUCCESS, an error occurred
 * and the values of buffer and length are undefined
 */
typedef void (* globus_rz_callback_func_t) (
    globus_result_t                     result,
    const char *                        buffer,
    size_t                              length,
    void *                              args);

typedef globus_result_t (* globus_rz_handle_attr_copy_func_t) (
    void **                             new_attr,
    void *                              attr);

typedef void (* globus_rz_handle_attr_destroy_func_t) (
    void *                              attr);

typedef struct globus_rz_handle_attr_s * globus_rz_handle_attr_t;
typedef struct globus_rz_handle_s *      globus_rz_handle_t;

extern globus_module_descriptor_t       globus_i_rz_module;
#define GLOBUS_RENDEZVOUS_MODULE        (&globus_i_rz_module)

/**
 * The varargs are multiples of key/copy/destroy/value:
 *
 * const char *                          key,
 * globus_rz_handle_attr_copy_func_t     copy,
 * globus_rz_handle_attr_destroy_func_t  destroy,
 * void *                                value
 *
 * Example attrs you might want to set would be security, i.e.
 *
 * GLOBUS_SOAP_MESSAGE_AUTHENTICATION_METHOD_KEY,
 * NULL,
 * NULL,
 * GLOBUS_SOAP_MESSAGE_AUTH_SECURE
 *
 * or a timeout value for the rendezvous register operation:
 *
 * GLOBUS_SOAP_MESSAGE_TIEMOUT_KEY,
 * NULL,
 * NULL,
 * timeout  ** a (globus_reltime_t *) **
 *
 * count parameter defines the number of 
 * key/copy/destroy/value multiples are being passed in
 * via the varargs
 *
 * attr created must be freed with _attr_destroy
 */
globus_result_t
globus_rz_handle_attr_init(
    globus_rz_handle_attr_t *           attr,
    int                                 count,
    ...);

void
globus_rz_handle_attr_destroy(
    globus_rz_handle_attr_t             attr);

/**
 * attr can be NULL
 * endpoint is EPR from getenv or wherever 
 *
 * handle created must be freed with _handle_destroy
 */
globus_result_t
globus_rz_handle_init(
    globus_rz_handle_t *                handle,
    globus_rz_handle_attr_t             attr,
    const char *                        endpoint);

void
globus_rz_handle_destroy(
    globus_rz_handle_t                  handle);

/**
 * does the register to the subjob endpoint.  Pass
 * this subjob's business card to the Rendezvous
 * endpoint.
 *
 * returns the rank.
 *
 * returns GLOBUS_SUCCESS unless an error occurred
 */
globus_result_t
globus_rz_sub_register(
    globus_rz_handle_t                  handle,
    const char *                        buffer,
    size_t                              length,
    int *                               rank);

/**
 * does the register to the multijob endpoint.  Pass
 * this multijob's business card to the Rendezvous
 * endpoint.
 *
 * returns the rank.
 *
 * returns GLOBUS_SUCCESS unless an error occurred
 */
globus_result_t
globus_rz_multi_register(
    globus_rz_handle_t                  handle,
    const char *                        buffer,
    size_t                              length,
    int *                               rank);

/**
 * performs the subscribe and poll.  If the poll
 * shows the completed state, then the callback is
 * called with the registrant data.  If not, then
 * we wait for the notification of completion and call the
 * callback with the registrant data at that point.
 *
 * poll_freq allows the user to poll occasionally in the event
 * that the notification of RendezvousCompleted is not being
 * sent.  This has nothing to do with the initial poll that happens
 * immediately after the subscribe.  If you don't want to do this
 * polling, set to globus_i_reltime_infinity.
 * 
 * This is a non-blocking function
 *
 * If return-value is non-zero (!= GLOBUS_SUCCESS), then
 * an error occurred.
 */
globus_result_t
globus_rz_multi_data_request_begin(
    globus_rz_handle_t                  handle,
    globus_reltime_t *                  poll_freq,
    globus_rz_callback_func_t           callback,
    void *                              args);


/**
 * performs the subscribe and poll.  If the poll
 * shows the completed state, then the callback is
 * called with the registrant data.  If not, then
 * we wait for the notification of completion and call the
 * callback with the registrant data at that point.
 *
 * poll_freq allows the user to poll occasionally in the event
 * that the notification of RendezvousCompleted is not being
 * sent.  This has nothing to do with the initial poll that happens
 * immediately after the subscribe.  If you don't want to do this
 * polling, set to globus_i_reltime_infinity.
 * 
 * This is a non-blocking function
 *
 * If return-value is non-zero (!= GLOBUS_SUCCESS), then
 * an error occurred.
 */
globus_result_t
globus_rz_sub_data_request_begin(
    globus_rz_handle_t                  handle,
    globus_reltime_t *                  poll_freq,
    globus_rz_callback_func_t           callback,
    void *                              args);

/* 
 * for each data_request_begin, you must call
 * data_request_finished once the callback has been
 * called (and completed).  Does teardown of the
 * subscriptions and internal state.
 *
 * If return value is non-zero (!= GLOBUS_SUCCESS)
 * than an error occurred.
 */
globus_result_t
globus_rz_data_request_finished(
    globus_rz_handle_t                  handle);

EXTERN_C_END

#endif    
