#ifndef __SGE_JOB_H 
#define __SGE_JOB_H 
/*___INFO__MARK_BEGIN__*/
/*************************************************************************
 *
 *  The Contents of this file are made available subject to the terms of
 *  the Sun Industry Standards Source License Version 1.2
 *
 *  Sun Microsystems Inc., March, 2001
 *
 *
 *  Sun Industry Standards Source License Version 1.2
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.2 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *   Copyright: 2001 by Sun Microsystems, Inc.
 *
 *   All Rights Reserved.
 *
 ************************************************************************/
/*___INFO__MARK_END__*/       

#include "sge_htable.h"
#include "sge_dstring.h"
#include "sge_job_JB_L.h"
#include "sge_job_JG_L.h"
#include "sge_job_PN_L.h"
#include "sge_job_AT_L.h"
#include "sge_job_ref_JRE_L.h"

/* Job states moved in from def.h */
#define JIDLE                                0x00000000
/* #define JENABLED                          0x00000008 */
#define JHELD                                0x00000010
#define JMIGRATING                           0x00000020
#define JQUEUED                              0x00000040
#define JRUNNING                             0x00000080
#define JSUSPENDED                           0x00000100
#define JTRANSFERING                         0x00000200
#define JDELETED                             0x00000400
#define JWAITING                             0x00000800
#define JEXITING                             0x00001000
#define JWRITTEN                             0x00002000
/* used in execd - job waits for getting its ASH/JOBID */
#define JWAITING4OSJID                       0x00004000
/* used in execd - shepherd reports job exit but there are still processes */
#define JERROR                               0x00008000

/*
 * JSUSPEND_ON_THRESHOLD and JFINISHED have the same value, but
 * JSUSPEND_ON_THRESHOLD is only set in the JAT_state filed,
 * where JFINISHED is set in the JAT_status and PET_status fields.
 */
#define JSUSPENDED_ON_THRESHOLD              0x00010000
/*
 * SGEEE: qmaster delays job removal till schedd 
 * does no longer need this finished job 
 */
#define JFINISHED                            0x00010000
/* used in execd to prevent slave jobs from getting started */
#define JSLAVE                               0x00020000
#define JDEFERRED_REQ                        0x00100000

/* 
   GDI request syntax for JB_hold 

   Example:
 
   qalter -h {u|s|o|n}

  POSIX (overwriting):
  u: SET|USER 
  o: SET|OPERATOR
  s: SET|SYSTEM 
  n: SUB|USER|SYSTEM|OPERATOR
 
  SGE (adding):
  +u: ADD|USER
  +o: ADD|OPERATOR
  +s: ADD|SYSTEM
 
  SGE (removing):
  -u: SUB|USER
  -o: SUB|OPERATOR
  -s: SUB|SYSTEM
   
*/
enum {
   /* need place for tree bits */
   MINUS_H_CMD_ADD = (0<<4), /* adds targetted flags */
   MINUS_H_CMD_SUB = (1<<4), /* remove targetted flags */
   MINUS_H_CMD_SET = (2<<4)  /* overwrites using targetted flags */
}; 

enum {
   MINUS_H_TGT_USER     = 1, /* remove needs at least job owner */
   MINUS_H_TGT_OPERATOR = 2, /* remove needs at least operator  */
   MINUS_H_TGT_SYSTEM   = 4, /* remove needs at least manager   */
   MINUS_H_TGT_JA_AD    = 8, /* removed automatically */
   MINUS_H_TGT_ALL      = 15,
   MINUS_H_TGT_NONE     = 31
};

/* values for JB_verify_suitable_queues */
#define OPTION_VERIFY_STR "nwevp"
enum {
   SKIP_VERIFY = 0,     /* -w n no expendable verifications will be done */
   WARNING_VERIFY,      /* -w w qmaster will warn about these jobs - but submit will succeed */
   ERROR_VERIFY,        /* -w e qmaster will make expendable verifications to reject 
                            jobs that are not schedulable (default) */
   JUST_VERIFY,         /* -w v just verify at qmaster but do not submit */
   POKE_VERIFY          /* -w p do verification with all resource utilizations in place (poke) */
};

/************    scheduling constants   *****************************************/
/* priorities are in the range from -1023 to 1024 */
/* to put them in into u_long we need to add 1024 */
#define BASE_PRIORITY  1024

/* int -> u_long */
#define PRI_ITOU(x) ((x)+BASE_PRIORITY)
/* u_long -> int */
#define PRI_UTOI(x) ((x)-BASE_PRIORITY)

#define PRIORITY_OFFSET 8
#define NEWCOMER_FLAG     0x1000000

/* forced negative sign bit  */
#define MAX_JOBS_EXCEEDED 0x8000000
#define ALREADY_SCANNED   0x4000000
#define PRIORITY_MASK     0xffff00
#define SUBPRIORITY_MASK  0x0000ff
#define JOBS_SCANNED_PER_PASS 10

/* 
   used in qstat:

   JSUSPENDED_ON_SUBORDINATE means that the job is
   suspended because its queue is suspended

*/
#define JSUSPENDED_ON_SUBORDINATE            0x00002000
#define JSUSPENDED_ON_SLOTWISE_SUBORDINATE   0x00004000

/* reserved names for JB_context */
#define CONTEXT_IOR "IOR"
#define CONTEXT_PARENT "PARENT"

/****** sgeobj/job/jb_now *****************************************************
*  NAME
*     jb_now -- macros to handle flag JB_type 
*
*  SYNOPSIS
*
*     JOB_TYPE_IMMEDIATE
*     JOB_TYPE_QSH
*     JOB_TYPE_QLOGIN
*     JOB_TYPE_QRSH
*     JOB_TYPE_QRLOGIN
*        
*     JOB_TYPE_NO_ERROR
*        When a job of this type fails and the error condition usually
*        would result in the job error state the job is finished. Thus
*        no qmod -c "*" is supported.
*******************************************************************************/

#define JOB_TYPE_IMMEDIATE  0x01UL
#define JOB_TYPE_QSH        0x02UL
#define JOB_TYPE_QLOGIN     0x04UL
#define JOB_TYPE_QRSH       0x08UL
#define JOB_TYPE_QRLOGIN    0x10UL
#define JOB_TYPE_NO_ERROR   0x20UL

/* submitted via "qsub -b y" or "qrsh [-b y]" */ 
#define JOB_TYPE_BINARY     0x40UL

/* array job (qsub -t ...) */
#define JOB_TYPE_ARRAY      0x80UL
/* Do a raw exec (qsub -noshell) */
#define JOB_TYPE_NO_SHELL   0x100UL

#define JOB_TYPE_QXXX_MASK \
   (JOB_TYPE_QSH | JOB_TYPE_QLOGIN | JOB_TYPE_QRSH | JOB_TYPE_QRLOGIN | JOB_TYPE_NO_ERROR)

#define JOB_TYPE_STR_IMMEDIATE  "IMMEDIATE"
#define JOB_TYPE_STR_QSH        "INTERACTIVE"
#define JOB_TYPE_STR_QLOGIN     "QLOGIN"
#define JOB_TYPE_STR_QRSH       "QRSH"
#define JOB_TYPE_STR_QRLOGIN    "QRLOGIN"
#define JOB_TYPE_STR_NO_ERROR   "NO_ERROR"

#define JOB_TYPE_CLEAR_IMMEDIATE(jb_now) \
   jb_now = jb_now & ~JOB_TYPE_IMMEDIATE 

#define JOB_TYPE_SET_IMMEDIATE(jb_now) \
   jb_now =  jb_now | JOB_TYPE_IMMEDIATE

#define JOB_TYPE_SET_QSH(jb_now) \
   jb_now = (jb_now & (~JOB_TYPE_QXXX_MASK)) | JOB_TYPE_QSH

#define JOB_TYPE_SET_QLOGIN(jb_now) \
   jb_now = (jb_now & (~JOB_TYPE_QXXX_MASK)) | JOB_TYPE_QLOGIN

#define JOB_TYPE_SET_QRSH(jb_now) \
   jb_now = (jb_now & ~JOB_TYPE_QXXX_MASK) | JOB_TYPE_QRSH

#define JOB_TYPE_SET_QRLOGIN(jb_now) \
   jb_now = (jb_now & ~JOB_TYPE_QXXX_MASK) | JOB_TYPE_QRLOGIN

#define JOB_TYPE_SET_BINARY(jb_now) \
   jb_now = jb_now | JOB_TYPE_BINARY

#define JOB_TYPE_CLEAR_BINARY(jb_now) \
   jb_now = jb_now & ~JOB_TYPE_BINARY

#define JOB_TYPE_SET_ARRAY(jb_now) \
   jb_now = jb_now | JOB_TYPE_ARRAY

#define JOB_TYPE_CLEAR_NO_ERROR(jb_now) \
   jb_now = jb_now & ~JOB_TYPE_NO_ERROR

#define JOB_TYPE_SET_NO_ERROR(jb_now) \
   jb_now =  jb_now | JOB_TYPE_NO_ERROR

#define JOB_TYPE_SET_NO_SHELL(jb_now) \
   jb_now =  jb_now | JOB_TYPE_NO_SHELL

#define JOB_TYPE_CLEAR_NO_SHELL(jb_now) \
   jb_now =  jb_now & ~JOB_TYPE_NO_SHELL

#define JOB_TYPE_UNSET_BINARY(jb_now) \
   jb_now = jb_now & ~JOB_TYPE_BINARY

#define JOB_TYPE_UNSET_NO_SHELL(jb_now) \
   jb_now =  jb_now & ~JOB_TYPE_NO_SHELL

#define JOB_TYPE_IS_IMMEDIATE(jb_now)      (jb_now & JOB_TYPE_IMMEDIATE)
#define JOB_TYPE_IS_QSH(jb_now)            (jb_now & JOB_TYPE_QSH)
#define JOB_TYPE_IS_QLOGIN(jb_now)         (jb_now & JOB_TYPE_QLOGIN)
#define JOB_TYPE_IS_QRSH(jb_now)           (jb_now & JOB_TYPE_QRSH)
#define JOB_TYPE_IS_QRLOGIN(jb_now)        (jb_now & JOB_TYPE_QRLOGIN)
#define JOB_TYPE_IS_BINARY(jb_now)         (jb_now & JOB_TYPE_BINARY)
#define JOB_TYPE_IS_ARRAY(jb_now)          (jb_now & JOB_TYPE_ARRAY)
#define JOB_TYPE_IS_NO_ERROR(jb_now)       (jb_now & JOB_TYPE_NO_ERROR)
#define JOB_TYPE_IS_NO_SHELL(jb_now)       (jb_now & JOB_TYPE_NO_SHELL)


bool job_is_enrolled(const lListElem *job, 
                     u_long32 ja_task_number);

u_long32 job_get_ja_tasks(const lListElem *job);

u_long32 job_get_not_enrolled_ja_tasks(const lListElem *job);

u_long32 job_get_enrolled_ja_tasks(const lListElem *job);

u_long32 job_get_submit_ja_tasks(const lListElem *job);
 
lListElem *job_enroll(lListElem *job, lList **answer_list, 
                      u_long32 task_number);  

void job_delete_not_enrolled_ja_task(lListElem *job, lList **answer_list,
                                     u_long32 ja_task_number);

int job_count_pending_tasks(lListElem *job, bool count_all);

bool job_has_soft_requests(lListElem *job);

bool job_is_ja_task_defined(const lListElem *job, u_long32 ja_task_number);

void job_set_hold_state(lListElem *job, 
                        lList **answer_list, u_long32 ja_task_id,
                        u_long32 new_hold_state);

u_long32 job_get_hold_state(lListElem *job, u_long32 ja_task_id);

/* int job_add_job(lList **job_list, char *name, lListElem *job, int check,
                 int hash, htable* Job_Hash_Table); */

void job_list_print(lList *job_list);

lListElem *job_get_ja_task_template(const lListElem *job, u_long32 ja_task_id); 

lListElem *job_get_ja_task_template_hold(const lListElem *job,
                                         u_long32 ja_task_id, 
                                         u_long32 hold_state);

lListElem *job_get_ja_task_template_pending(const lListElem *job,
                                            u_long32 ja_task_id);

lListElem *job_search_task(const lListElem *job, lList **answer_list, u_long32 ja_task_id);
lListElem *job_create_task(lListElem *job, lList **answer_list, u_long32 ja_task_id);

void job_add_as_zombie(lListElem *zombie, lList **answer_list, 
                       u_long32 ja_task_id);

int job_list_add_job(lList **job_list, const char *name, lListElem *job, 
                     int check); 

u_long32 job_get_ja_task_hold_state(const lListElem *job, u_long32 ja_task_id);

void job_destroy_hold_id_lists(const lListElem *job, lList *id_list[16]);

void job_create_hold_id_lists(const lListElem *job, lList *id_list[16],
                              u_long32 hold_state[16]);

bool job_is_zombie_job(const lListElem *job); 

const char *job_get_shell_start_mode(const lListElem *job,
                                     const lListElem *queue,
                                     const char *conf_shell_start_mode);

bool job_is_array(const lListElem *job); 

bool job_is_parallel(const lListElem *job);

bool job_is_tight_parallel(const lListElem *job, const lList *pe_list);

bool job_might_be_tight_parallel(const lListElem *job, const lList *pe_list);

void job_get_submit_task_ids(const lListElem *job, u_long32 *start, 
                             u_long32 *end, u_long32 *step); 

int job_set_submit_task_ids(lListElem *job, u_long32 start, u_long32 end,
                            u_long32 step);

u_long32 job_get_smallest_unenrolled_task_id(const lListElem *job);

u_long32 job_get_smallest_enrolled_task_id(const lListElem *job);

u_long32 job_get_biggest_unenrolled_task_id(const lListElem *job);

u_long32 job_get_biggest_enrolled_task_id(const lListElem *job);

int job_list_register_new_job(const lList *job_list, u_long32 max_jobs);

void jatask_list_print_to_string(const lList *task_list, dstring *range_string);

lList* ja_task_list_split_group(lList **task_list);

int job_initialize_id_lists(lListElem *job, lList **answer_list);

void job_initialize_env(lListElem *job, 
                        lList **answer_list,
                        const lList* path_alias_list,
                        const char *unqualified_hostname,
                        const char *qualified_hostname);

const char* job_get_env_string(const lListElem *job, const char *variable);

void job_set_env_string(lListElem *job, const char *variable, 
                        const char *value);

void job_check_correct_id_sublists(lListElem *job, lList **answer_list);

const char *job_get_id_string(u_long32 job_id, u_long32 ja_task_id, 
                              const char *pe_task_id, dstring *buffer);

const char *job_get_job_key(u_long32 job_id, dstring *buffer);

const char *job_get_key(u_long32 job_id, u_long32 ja_task_id, 
                        const char *pe_task_id, dstring *buffer);

const char *jobscript_get_key(lListElem *jep, dstring *buffer);

char *jobscript_parse_key(char *key,const char **exec_file);

bool job_parse_key(char *key, u_long32 *job_id, u_long32 *ja_task_id,
                   char **pe_task_id, bool *only_job);

bool job_is_pe_referenced(const lListElem *job, const lListElem *pe);

bool job_is_ckpt_referenced(const lListElem *job, const lListElem *ckpt);

void job_get_state_string(char *str, u_long32 op);

lListElem *job_list_locate(lList *job_list, u_long32 job_id);

void job_add_parent_id_to_context(lListElem *job);

int job_check_qsh_display(const lListElem *job, 
                          lList **answer_list, 
                          bool output_warning);

int job_check_owner(const char *user_name, u_long32 job_id, lList *master_job_list);

int job_resolve_host_for_path_list(const lListElem *job, lList **answer_list, int name);

lListElem *
job_get_request(const lListElem *this_elem, const char *centry_name);

bool
job_get_contribution(const lListElem *this_elem, lList **answer_list,
                     const char *name, double *value,
                     const lListElem *implicit_centry);

/* unparse functions */
bool sge_unparse_string_option_dstring(dstring *category_str, const lListElem *job_elem, 
                               int nm, char *option);

bool sge_unparse_ulong_option_dstring(dstring *category_str, const lListElem *job_elem, 
                               int nm, char *option);
                               
bool sge_unparse_pe_dstring(dstring *category_str, const lListElem *job_elem, int pe_pos, int range_pos,
                            const char *option); 

bool sge_unparse_resource_list_dstring(dstring *category_str, lListElem *job_elem, 
                                       int nm, const char *option);

bool sge_unparse_queue_list_dstring(dstring *category_str, lListElem *job_elem, 
                                    int nm, const char *option);   

bool sge_unparse_acl_dstring(dstring *category_str, const char *owner, const char *group, 
                             const lList *acl_list, const char *option);

bool job_verify(const lListElem *job, lList **answer_list, bool do_cull_verify);
bool job_verify_submitted_job(const lListElem *job, lList **answer_list);

bool job_get_wallclock_limit(u_long32 *limit, const lListElem *jep);

bool
job_is_binary(const lListElem *job);

bool
job_set_binary(lListElem *job, bool is_binary);

bool
job_is_no_shell(const lListElem *job);

bool
job_set_no_shell(lListElem *job, bool is_no_shell);

bool
job_set_owner_and_group(lListElem *job, u_long32 uid, u_long32 gid,
                        const char *user, const char *group);

bool  
job_get_ckpt_attr(int op, dstring *string);

bool
job_get_verify_attr(u_long32 op, dstring *string);

void 
set_context(lList *jbctx, lListElem *job);

bool 
job_parse_validation_level(int *level, const char *input, int prog_number, lList **answer_list);

bool
job_is_requesting_consumable(lListElem *jep, const char *resource_name);

bool
job_init_binding_elem(lListElem *jep);

#endif /* __SGE_JOB_H */    
