
	/* embodies the ATIS method of selecting the current, best object
	   to observe next.  See the discussion in chapter 12 of "Robotic
	   Observatories" for an explanation. */

#include <stdio.h>
#include "listgen.h"

#undef DEBUG
#define MAX_RAND     32767	/* maximum value returned by 'rand()' routine */

static top_priority;		/* priority of "best" object so far */
static min_lst_left;		/* minimum lst window for "best" object so far */
static int best_id;			/* ID of best target to look */
static double jd, ut, lst;

static mark_as_best();

	/* return a pointed to the "best" object to observe next, or NULL
	   if there are no target was selected at the current time. */

struct target *
atis_select(num_list)
int num_list;
{
	unsigned int seed;
	int iteration, max_iter, i;
	struct target *t;

	seed = (unsigned int) time((long *) 0);
	srand(seed);

	now(&jd, &ut, &lst);
	top_priority = LOWEST_PRIORITY;
	min_lst_left = 1e6;
	iteration = 0;
	max_iter = 10;

	while (iteration < max_iter) {
		best_id = -1;
		for (i = 0; i < num_list; i++) {
			t = &(list[i]);
#ifdef DEBUG
			printf("considering target with ID %5d ... ", t->target_id);
#endif

			if (t->tonight_status != ACTIVE) {
#ifdef DEBUG
				printf("rejected because not ACTIVE \n");
#endif
				continue;
			}

			/* this is really not necessary, but do it just in case ... */
			if ((t->start_jd > jd) || (t->end_jd < jd)) {
#ifdef DEBUG
				printf("rejected by JD \n");
#endif
				t->tonight_status = INACTIVE;	
				continue;
			}
			if (t->lst_min < t->lst_max) {
				if ((t->lst_min > lst) || (t->lst_max < lst)) {
#ifdef DEBUG
					printf("rejected due to LST \n");
#endif
					continue;
				}
			}
			else {
				if ((t->lst_min > lst) && (t->lst_max < lst)) {
#ifdef DEBUG
					printf("rejected due to LST \n");
#endif
					continue;
			}

			if (t->priority > top_priority) {
#ifdef DEBUG
				printf("rejected due to priority \n");
#endif
				continue;
			}

			if (t->priority < top_priority) {
#ifdef DEBUG
				printf("marking as best, due to priority\n");
#endif
				mark_as_best(t);
				continue;
			}
			if (t->lst_max - lst < min_lst_left) {
#ifdef DEBUG
				printf("marking as best, due to LST left\n");
#endif
				mark_as_best(t);
				continue;
			}
		}
		/* for this candidate object, roll the die; if the 'probability'
		   field is lower than the die roll, mark the object as DISCARDED.
		   Otherwise, return it as the next object to be observed. */
		if (best_id != -1) {
			if (rand()/MAX_RAND <= list[best_id].probability) {
#ifdef DEBUG
				printf(" returning target with ID %5d\n", best_id);
#endif
				return(&(list[best_id]));
			}
			else {
#ifdef DEBUG
				printf(" rejecting target with ID %5d due to probability\n");
#endif
				list[best_id].tonight_status = DISCARDED;
			}
		}
		iteration++;
	}
#ifdef DEBUG
	printf(" returning NULL \n");
#endif
	return((struct target *) NULL);
}

	/* set the current "best" target to the given one */

static
mark_as_best(t)
struct target *t;
{
	best_id = t->target_id;
	top_priority = t->priority;
	min_lst_left = t->lst_max - lst;
}
