# include "basic.h"
# include "scheduler.h"

int schedule (int argc, char **argv) {

  Job *job;
  Task *task;
  Macro *macro;
  struct timeval now;
  double dtime;
  int i, found, status;
  int Ntest;

  if (argc != 1) {
    fprintf (stderr, "USAGE: schedule\n");
    return (FALSE);
  }

  /*
  task = NextTask ();
  CreateJob (task);
  CreateJob (task);
  job = NextJob ();
  DeleteJob (job);
  CreateJob (task);
  return (FALSE);
  */

  /* start the clock for all tasks */
  while ((task = NextTask ()) != NULL) {
    gettimeofday (&task[0].last, (void *) NULL);
  }

  Ntest = 0;

  while (1) {
    if (Ntest > 5) { 
      ListJobs ();
      Ntest = 0;
    }
    usleep (10000);
    Ntest ++;

    /** test all tasks **/
    while ((task = NextTask ()) != NULL) {

      /* check exec period (ready to run again?) */
      gettimeofday (&now, (void *) NULL);
      dtime = DTIME (now, task[0].last);
      if (dtime < task[0].exec_period) continue;

      SetCurrentTask (task[0].name);
      fprintf (stderr, "trying task %s\n", task[0].name);

      /* run task.exec macro */
      if (task[0].exec != NULL) {
	status = exec_loop (task[0].exec);
	if (!status) continue;
      }

      /* is task valid ?(argc, argv) */

      /* construct job from task */
      job = CreateJob (task);

      /* execute job */
      SubmitJob (job);

      /* reset timer on task (don't do this if Create/Submit fails)*/
      gettimeofday (&task[0].last, (void *) NULL);

    }

    /** test all jobs **/
    while ((job = NextJob ()) != NULL) {

      /* check poll period (ready to run again?) */
      gettimeofday (&now, (void *) NULL);

      dtime = DTIME (now, job[0].last);
      if (dtime >= job[0].task.poll_period) {
	/* check current status */
	status = CheckJob (job);
	switch (status) {
	case JOB_BUSY:
	  fprintf (stderr, "job %s (%d) busy\n", job[0].task.name, job[0].JobID);
	  break;

	case JOB_CRASH:
	  fprintf (stderr, "job %s (%d) crash\n", job[0].task.name, job[0].JobID);
	  if (job[0].task.crash != NULL) {
	    exec_loop (job[0].task.crash);
	  }
	  DeleteJob (job);
	  continue;
	  break;

	case JOB_EXIT:
	  fprintf (stderr, "job %s (%d) exit\n", job[0].task.name, job[0].JobID);
	  /* look for corresponding exit macro */
	  macro = job[0].task.def;
	  for (i = 0; i < job[0].task.Nexit; i++) {
	    if (job[0].exit_status == atoi(job[0].task.exit[i][0].name)) {
	      macro = job[0].task.exit[i];
	      break;
	    }
	  }
	  if (macro != NULL) exec_loop (macro);
	  DeleteJob (job);
	  continue;
	  break;

	default:
	  fprintf (stderr, "unknown exit status\n");
	  break;
	}
	job[0].last = now;
      }

      dtime = DTIME (now, job[0].start);
      if (dtime >= job[0].task.timeout_period) {
	fprintf (stderr, "timeout on %s\n", job[0].task.name);
	if (job[0].task.timeout != NULL) {
	  exec_loop (job[0].task.timeout);
	}
	DeleteJob (job);
	continue;
      }
    }
  }

  return (TRUE);

}
