
#ifndef GLOBUS_DUROC_CONTROL_H
#define GLOBUS_DUROC_CONTROL_H


#include "nexus.h"
#include "globus_common.h"
#include "globus_duct_control.h"
#include "globus_duroc_common.h"


#ifndef EXTERN_C_BEGIN
#ifdef __cplusplus
#define EXTERN_C_BEGIN extern "C" {
#define EXTERN_C_END }
#else
#define EXTERN_C_BEGIN
#define EXTERN_C_END
#endif
#endif
 
EXTERN_C_BEGIN

#define GLOBUS_DUROC_SUBJOB_STATE_PENDING      1
#define GLOBUS_DUROC_SUBJOB_STATE_ACTIVE       2
#define GLOBUS_DUROC_SUBJOB_STATE_CHECKED_IN   4
#define GLOBUS_DUROC_SUBJOB_STATE_RELEASED     8
#define GLOBUS_DUROC_SUBJOB_STATE_DONE         16
#define GLOBUS_DUROC_SUBJOB_STATE_FAILED       32

#define GLOBUS_DUROC_SUBJOB_STATE_ALL     (GLOBUS_DUROC_SUBJOB_STATE_PENDING \
                                    | GLOBUS_DUROC_SUBJOB_STATE_ACTIVE \
                                    | GLOBUS_DUROC_SUBJOB_STATE_CHECKED_IN \
                                    | GLOBUS_DUROC_SUBJOB_STATE_RELEASED \
                                    | GLOBUS_DUROC_SUBJOB_STATE_DONE \
                                    | GLOBUS_DUROC_SUBJOB_STATE_FAILED)


#define GLOBUS_DUROC_JOB_STATE_PENDING   GLOBUS_DUROC_SUBJOB_STATE_PENDING
#define GLOBUS_DUROC_JOB_STATE_ACTIVE    GLOBUS_DUROC_SUBJOB_STATE_ACTIVE
#define GLOBUS_DUROC_JOB_STATE_FAILED    GLOBUS_DUROC_SUBJOB_STATE_FAILED
#define GLOBUS_DUROC_JOB_STATE_DONE      GLOBUS_DUROC_SUBJOB_STATE_DONE

#define GLOBUS_DUROC_JOB_STATE_ALL  (GLOBUS_DUROC_SUBJOB_STATE_PENDING \
                              | GLOBUS_DUROC_JOB_STATE_ACTIVE \
                              | GLOBUS_DUROC_JOB_STATE_DONE \
                              | GLOBUS_DUROC_JOB_STATE_FAILED)


extern int 
globus_duroc_control_activate (void);

extern int
globus_duroc_control_deactivate (void);

extern globus_module_descriptor_t globus_duroc_control_module;
#define GLOBUS_DUROC_CONTROL_MODULE (&globus_duroc_control_module)


typedef struct globus_duroc_control_checkin_port_s {
  nexus_startpoint_t   sp;
  nexus_endpointattr_t epattr;
  nexus_endpoint_t     ep;
} globus_duroc_control_checkin_port_t;


typedef struct globus_duroc_control_s {
  globus_duroc_control_checkin_port_t   subjob_checkin_port;

  char        * volatile subjob_callback_contact;

  nexus_mutex_t          mutex;
  volatile int           next_free_serialno;  /* allocate and increment */
  volatile int           open_globus_gram_jobs;      /* possible deferrals */

  globus_hashtable_t     globus_gram_hasht;
  globus_hashtable_t     serialno_hasht;

  globus_list_t        * volatile job_monitors; /* all managed jobs */
  globus_list_t        * volatile deferrals;    /* deferred subjob states */
} globus_duroc_control_t;


/* initialize a globus_duroc_control_t agent 
 */
extern int 
globus_duroc_control_init (globus_duroc_control_t * controlp);

/* submit a job through an initialized globus_duroc_control_t agent
 * submission results for each requested subjob are returned in subjob_results
 */
extern int 
globus_duroc_control_job_request (globus_duroc_control_t  * controlp,
			   const char       * description,
			   int                job_state_mask,
			   const char       * callback_contact,
			   char            ** job_contactp,
			   int              * subreq_countp,
			   volatile int    ** subreq_resultsp);

/* add a new subjob to an already-submitted job 
 * currently only allowed before calling barrier_release 
 */
extern int 
globus_duroc_control_subjob_add (globus_duroc_control_t  * controlp,
			  const char       * job_contact,
			  char             * subjob_request_string);

/* remove (and cancel) a subjob from an already-submitted job
 * currently only allowed before calling barrier_release
 */
extern int 
globus_duroc_control_subjob_delete (globus_duroc_control_t  * controlp,
			     const char       * job_contact,
			     const char       * subjob_label);

/* conditionally allow job components to run forward:
 */
extern int 
globus_duroc_control_barrier_release (globus_duroc_control_t        * controlp,
			       const char             * job_contact,
			       globus_bool_t     wait_for_checkins);

/* cancel a submitted duroc job
 * returns failure if called more than once on the same job
 */
extern int
globus_duroc_control_job_cancel (globus_duroc_control_t * controlp,
			  const char      * job_contact);

/* obtain state snapshot for a submitted duroc job
 * returns the number of subjobs in (*subjob_countp)
 *      for i=0 to (*subjob_countp)-1:
 *         the state of subjob i in (*subjob_statesp)[i]
 *         the label for subjob i in (*subjob_labelsp)[i]
 * 
 * the arrays in (*subjob_statesp) and (*subjob_labelsp), and
 * the strings stored in the label array are
 * allocated by globus_malloc and should be freed with globus_free.
 */
extern int
globus_duroc_control_subjob_states (
			    globus_duroc_control_t   * controlp,
			    const char        * job_contact,
			    int               * subjob_countp,
			    int              ** subjob_statesp,
			    char            *** subjob_labelsp);


/* obtain job snapshot for a submitted duroc job
 * returns the number of subjobs in (*subjob_countp)
 *      for i=0 to (*subjob_countp)-1:
 *         the GRAM contact of subjob i in (*subjob_contactsp)[i]
 *         the label for subjob i in (*subjob_labelsp)[i]
 * 
 * the arrays in (*subjob_contactsp) and (*subjob_labelsp), and
 * the strings stored in the contact and label arrays are
 * allocated by globus_malloc and should be freed with globus_free.
 */
extern int
globus_duroc_control_subjob_contacts (
			      globus_duroc_control_t   * controlp,
			      const char               * job_contact,
			      int                      * subjob_countp,
			      char                   *** subjob_contactsp,
			      char                   *** subjob_labelsp);

EXTERN_C_END

#endif /* GLOBUS_DUROC_CONTROL_H */

