/* run a command at certain time-of-day */

#include <time.h>
#include "global.h"
#include "timer.h"
#include "cmdparse.h"

#if (defined(MSDOS) && !(defined(MSC)) && !(defined(__TURBOC__)))
# define TIMEZONE	0L		/* Aztec doesn't define timezone */
#endif

#ifdef UNIX
# define TIMEZONE	(daylight? altzone : timezone) /* XENIX has "altzone" */
#endif

#ifdef MWC
# define TIMEZONE	timezone	/* MWC does not know "daylight" */
#endif

#ifndef TIMEZONE
# define TIMEZONE	(daylight? timezone - 3600L : timezone)
#endif

struct at
{
    struct at *next,*prev;		/* doubly-linked list */
    time_t when;			/* time-of-day */
    int argc;				/* description of command */
    char *argv[NARG];			/* pointers to copied args */
};
#define NULLAT	((struct at *) 0)

struct at *at_head = NULLAT;		/* list of scheduled commands */
time_t lasttime = 0;			/* last time we executed one */

struct timer at_timer;			/* 1-minute timer to execute cmds */

static void at_tick();

extern struct cmds cmds[];		/* commands */
extern char nospace[];

int
doat (argc,argv)
    int argc;
    char *argv[];

{
    register struct at *at,*new;
    char *p;
    time_t when;
    int i;

    if (argc < 2) {
	printf("Time   Command\n");
	for (at = at_head; at != NULLAT; at = at->next){
	    i = (int) (at->when / 60L);
	    printf("%2d:%02d ",i / 60,i % 60);
	    for (i = 0; i < at->argc; i++)
		printf(" %s",at->argv[i]);
	    printf("\n");
	}
	return 0;
    }
    if ((p = index(argv[1],':')) == NULLCHAR){
	printf("Usage: at hh:mm [command]\n");
	return 1;
    }
    if ((when = 3600L * atoi(argv[1]) + 60 * atoi(p + 1)) >= 86400L){
	printf("at: illegal time\n");
	return 1;
    }
    for (at = at_head; at != NULLAT; at = at->next)
	if (at->when == when){
	    for (i = 0; i < at->argc; i++)
		free(at->argv[i]);

	    if (at->next != NULLAT)
		at->next->prev = at->prev;

	    if (at->prev != NULLAT)
		at->prev->next = at->next;
	    else
		at_head = at->next;

	    free(at);
	    break;
	}
    if (argc > 2){
	/* create new "at" control block */
	if ((new = (struct at *) calloc(1,sizeof(struct at))) == NULLAT){
	    printf(nospace);
	    return 1;
	}
	new->when = when;
	new->argc = argc - 2;
	/* copy command and args to allocated space and link to "at" block */
	for (i = 0; i < new->argc; i++){
	    if ((new->argv[i] = malloc(strlen(argv[i + 2]) + 1)) == NULLCHAR){
		while (--i >= 0)
		    free(new->argv[i]);
		free(new);
		printf(nospace);
		return 1;
	    }
	    strcpy(new->argv[i],argv[i + 2]);
	}
	/* find proper position in the list (sorted on time-of-day) */
	for (at = at_head; at != NULLAT; at = at->next)
	    if (at->when > when)
		break;
	if (at == NULLAT){
	    if (at_head == NULLAT)
		at_head = new;
	    else {
		for (at = at_head; at->next != NULLAT; at = at->next)
		    ;				/* find end of list */
		at->next = new;
		new->prev = at;
	    }
	} else {				/* insert before this one */
	    if ((new->prev = at->prev) != NULLAT)
		new->prev->next = new;
	    else
		at_head = new;
	    at->prev = new;
	    new->next = at;
	}
    }

    stop_timer(&at_timer);
    if (at_head != NULLAT){			/* anything to run? */
	if (at_timer.start == 0){		/* first time? */
	    at_timer.start = SEC2TICK(60);	/* tick each minute */
	    at_timer.func = at_tick;
	    lasttime = (time(NULL) - TIMEZONE) % 86400L; /* init last-time-done */
	}
	start_timer(&at_timer);
	at_timer.count = SEC2TICK(60 - (time(NULL) % 60)); /* sync with minute */
    }
    return 0;
}

/* called once a minute to check for commands to run */

static void
at_tick ()

{
    register struct at *at;
    time_t now;
    char *argv[NARG];

    at = at_head;
    now = (time(NULL) - TIMEZONE) % 86400L;	/* get time of day */

    /* skip all commands that already have been processed */
    if (now > lasttime)
	while (at != NULLAT && at->when <= lasttime)
	    at = at->next;

    while (at != NULLAT){
	if (at->when <= now){			/* time to run it? */
	    memcpy(argv,at->argv,NARG * sizeof(char *)); /* copy arg vector */
	    docmd(cmds,at->argc,argv);		/* and go! */
	}

	at = at->next;
    }

    lasttime = now;				/* remember last time */
    start_timer(&at_timer);			/* look again in a minute */
}
