# include "pcontrol.h"
# define DEBUG 0

int CheckBusyJob (Job *job, Host *host) {

  int      status;
  int      outstate;
  char    *p;
  char     string[64];
  IOBuffer buffer;

  /* we are checking a job which is currently busy.  it has been pulled from the
     JOB_BUSY stack, and is linked to a host in the HOST_BUSY stack.  
     XXX need to check on state of HOST on return */

  ASSERT (job, "job not set");
  ASSERT (host, "host not set");

  ASSERT (host == (Host *) job[0].host, "invalid host");
  ASSERT (job  == (Job *) host[0].job, "invalid job");

  InitIOBuffer (&buffer, 0x100);

  status = PclientCommand (host, "status", PCLIENT_PROMPT, &buffer);

  /* check on success of pclient command */
  switch (status) {
    case PCLIENT_DOWN:
      HarvestHost (host[0].pid);
      // unlink host & job
      job[0].host = NULL;
      host[0].job = NULL;
      if (job[0].realhost) free (job[0].realhost);
      job[0].realhost = NULL;
      PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
      PutJob (job, PCONTROL_JOB_PENDING, STACK_BOTTOM);
      FreeIOBuffer (&buffer);
      return (FALSE);

    case PCLIENT_HUNG:
      // don't do anything drastic, just keep trying
      if (DEBUG || VerboseMode()) gprint (GP_ERR, "client is busy, not responding");
      PutHost (host, PCONTROL_HOST_BUSY, STACK_BOTTOM);
      PutJob (job, PCONTROL_JOB_BUSY, STACK_BOTTOM);
      FreeIOBuffer (&buffer);
      return (TRUE);

    case PCLIENT_GOOD:
      if (DEBUG || VerboseMode()) gprint (GP_ERR, "message received (CheckBusyJob)");
      break;

    default:
      ABORT ("unknown status for pclient command");  
  }

  /** host is up, need to parse message **/
  p = memstr (buffer.buffer, "STATUS", buffer.Nbuffer);
  // this condition means the message is garbage.  toss it and try again
  if (p == NULL) {
    PutHost (host, PCONTROL_HOST_BUSY, STACK_BOTTOM);
    PutJob (job, PCONTROL_JOB_BUSY, STACK_BOTTOM);
    FreeIOBuffer (&buffer);
    return (FALSE);
  }

  sscanf (p, "%*s %s", string);
  ASSERT (strcmp(string, "NONE"), "no current job\n");

  /** no status change, return to BUSY stack **/
  if (!strcmp(string, "BUSY")) {
    PutHost (host, PCONTROL_HOST_BUSY, STACK_BOTTOM);
    PutJob (job, PCONTROL_JOB_BUSY, STACK_BOTTOM);
    FreeIOBuffer (&buffer);
    return (TRUE);
  }

  /* exit status better be either EXIT or CRASH */
  outstate = PCONTROL_JOB_BUSY;
  if (!strcmp(string, "EXIT")) outstate = PCONTROL_JOB_EXIT;
  if (!strcmp(string, "CRASH")) outstate = PCONTROL_JOB_CRASH;
  ASSERT (outstate != PCONTROL_JOB_BUSY, "should not reach here (CheckJob)");

  /* parse the exit status and sizes of output buffers */
  p = memstr (buffer.buffer, "EXITST", buffer.Nbuffer);
  sscanf (p, "%*s %d", &job[0].exit_status);
  p = memstr (buffer.buffer, "STDOUT", buffer.Nbuffer);
  sscanf (p, "%*s %d", &job[0].stdout_size);
  p = memstr (buffer.buffer, "STDERR", buffer.Nbuffer);
  sscanf (p, "%*s %d", &job[0].stderr_size);

  // XXX runaway job if output too large?
  if (job[0].stdout_size > 0x100000) abort();
  if (job[0].stderr_size > 0x100000) abort();

  // job has exited : move to DONE stack 
  // the host is still BUSY until job output is gathered (int CheckDoneJob)
  // don't unlink job and host yet
  PutHost (host, PCONTROL_HOST_BUSY, STACK_BOTTOM);
  PutJobSetState (job, PCONTROL_JOB_DONE, STACK_BOTTOM, outstate);
  gettimeofday (&job[0].stop, (void *) NULL);
  job[0].dtime = DTIME(job[0].stop, job[0].start);
  FreeIOBuffer (&buffer);
  return (TRUE);
}
