# include "data.h"
# include "basic.h"
# include "astro.h"

# include <sys/time.h>
# include <time.h>
# include <zlib.h>

typedef enum {
  JOB_NONE,
  JOB_BUSY, 
  JOB_EXIT, 
  JOB_HUNG,
  JOB_CRASH,
  JOB_PENDING,
} JobStat;

typedef enum {
  JOB_LOCAL, 
  JOB_CONTROLLER, 
} JobMode;

typedef enum {
  CONTROLLER_HUNG = -1,
  CONTROLLER_DOWN = 0,
  CONTROLLER_GOOD = 1,
} ControllerStat;

enum {RANGE_ABS, RANGE_DAY, RANGE_WEEK};
enum {TIMER_ALLJOBS, TIMER_SUCCESS, TIMER_FAILURE};

enum {TASK_NONE, 
      TASK_EMPTY, 
      TASK_COMMENT, 
      TASK_NMAX, 
      TASK_ACTIVE, 
      TASK_TRANGE, 
      TASK_END, 
      TASK_HOST, 
      TASK_STDOUT, 
      TASK_STDERR, 
      TASK_COMMAND, 
      TASK_OPTIONS, 
      TASK_PERIODS, 
      TASK_NPENDING, 
      TASK_EXIT, 
      TASK_EXEC
} TaskHashResults;

typedef struct {
  time_t start;
  time_t stop;
  char type;
  char include;
  int Nmax;
  int Nrun;
} TimeRange;

/* a task is a description of the wrapping of a job */
typedef struct {
  Macro  *exec;				/* name is 'exec' */
  Macro  *crash;			/* name is 'crash' */
  Macro  *timeout;
  Macro  *defexit;

  int     NEXIT;
  int     Nexit;
  Macro **exit;				/* name is exit status */

  int     argc;
  char  **argv;

  int     optc;
  char  **optv;

  char   *host;
  int     host_required;

  char   *name;

  char   *stdout_dump;
  char   *stderr_dump;

  int       Nranges;
  TimeRange *ranges;

  int     Nmax;  // only construct Ntotal jobs for this task
  int     Njobs;

  int     Npending;  // number of currently pending jobs
  int     NpendingMax;  // max number of pending jobs allowed

  float   poll_period;
  float   exec_period;
  float   timeout_period;

  struct timeval last;

  int Nsuccess;
  int Nfailure;
  int Ntimeout;

  double dtimeAve_alljobs, dtimeMin_alljobs, dtimeMax_alljobs;
  double dtimeAve_success, dtimeMin_success, dtimeMax_success;
  double dtimeAve_failure, dtimeMin_failure, dtimeMax_failure;

  int active;

} Task;

// time period include/exclude periods: 
// date ranges (e_time - e_time) 
// time ranges (e_time - e_time) (use e_time % 86400)
// time-of-week ranges  (e_time - e_time
// -trange Mon Fri (inclusive on days -- end defaults to Fri@23:59:59)
// -trange 08:00 - 17:00
// -trange 2005/12/24 2005/12/31
// be careful of HST!
// type: day, week, date
// keep: TRUE: perform action within this time period
// keep: FALSE: do not perform action within this time period
  
typedef struct {
  int JobID;				/* internal ID for job */
  int pid;				/* external ID for job */

  struct timeval last;
  struct timeval start;
  int state;
  int exit_status;

  int     argc;
  char  **argv;

  int     optc;
  char  **optv;

  Task   *task;

  IOBuffer    stdout;			/* stdout storage buffer */
  IOBuffer    stderr;			/* stderr storage buffer */
  JobMode     mode;			/* local or controller? */

  char   *stdout_dump;
  char   *stderr_dump;
  char   *realhost;

  int         stdout_size;		/* size of pending stdout buffer (controller) */
  int         stderr_size;		/* size of pending stderr buffer (controller) */
  int         stdout_fd;		/* stdout pipe (local only) */
  int         stderr_fd;		/* stderr pipe (local only) */

  double dtime;
} Job;

# define CONTROLLER_PROMPT "pcontrol:"

/* scheduler prototypes */

void InitPantasks ();
void InitPantasksServer ();
void InitPantasksClient ();
void InitTasks ();
Task *NextTask ();
Task *FindTask (char *name);
void ListTasks (int verbose);
int ShowTask (char *name);
int FreeTask (Task *task);
Task *CreateTask (char *name);
int ValidateTask (Task *task, int RequireStatic);
int RegisterNewTask ();
int DeleteNewTask ();
Task *GetNewTask ();
Task *GetActiveTask ();
void SetTaskTimer (struct timeval *timer);
double GetTaskTimer (struct timeval start);
void InitTaskTimers ();
int TaskHash (char *input);
int RemoveTask (Task *task);
Task *SetNewTask (Task *task);
void ListTaskStats (char *regex);
void UpdateTaskTimerStats (Task *task, int mode, double dtime);

int NextJobID ();
int InitJobIDs ();
int FreeJobID (int ID);

void InitJobs ();
Job *NextJob ();
Job *FindJob (int JobID);
void ListJobs ();
Job *CreateJob (Task *task);
int SubmitJob (Job *job);
int CheckJob (Job *job);
int DeleteJob (Job *job);
void FreeJob (Job *job);

int CheckJobs ();
int CheckTasks ();
int CheckSystem ();
int CheckController ();
int CheckTimeRanges (TimeRange *ranges, int Nranges);
int BumpTimeRanges (TimeRange *ranges, int Nranges);

int GetJobOutput (char *channel, int pid, IOBuffer *buffer, int Nbytes);
int CheckControllerJob (Job *job);
int CheckControllerJobStatus (Job *job);
int SubmitControllerJob (Job *job);
int DeleteControllerJob (Job *job);
Job *FindControllerJob (int JobID);
int StartController ();
int ControllerCommand (char *command, char *response, IOBuffer *buffer);
int SubmitLocalJob (Job *job);
int CheckLocalJob (Job *job);
int CheckLocalJobStatus (Job *job);
void InitTaskTimers ();
CommandF *FindControllerCommand (char *cmd);
int QuitController ();
int StopController ();
int VerboseMode ();
int KillLocalJob (Job *job);
int CheckControllerOutput ();
int PrintControllerOutput ();

int KillControllerJob (Job *job);
int CheckControllerStatus ();
int TestElapsedCheck ();
void gotsignal (int signum);
int client_shell (int argc, char **argv);

void InitClients ();
void AddNewClient (int client);
int  DeleteClient (int client);
void *ListenClients (void *data);

// functions related to the server threads
void CheckTasksSetState (int state);
int CheckTasksGetState ();
void *CheckTasksThread (void *data);

void CheckJobsSetState (int state);
int CheckJobsGetState ();
void *CheckJobsThread (void *data);

void CheckControllerSetState (int state);
int CheckControllerGetState ();
void *CheckControllerThread (void *data);

void CheckInputsSetState (int state);
int CheckInputsGetState ();
void *CheckInputsThread (void *data);

// functions related to the queue of input files
void InitInputs ();
void AddNewInput (char *input);
int DeleteInput (char *input);
void CheckInputs ();

void SerialThreadLock ();
void SerialThreadUnlock ();

int InitPassword ();
int CheckPassword (int BindSocket);
