/* timer.c -- Subroutines for (system-) timed events */

#include "autoconf.h"
#include "copyright.h"
#ifndef	lint
static char *RCSid = "$Id: timer.c,v 1.7 1995/03/21 00:01:16 ambar Exp $";
USE(RCSid);
#endif

#include <signal.h>

#include "interface.h"
#include "match.h"
#include "command.h"
#include "rwho_clilib.h"

extern void NDECL(pool_reset);
extern void NDECL(do_second);
extern void FDECL(fork_and_dump, (int key));
extern unsigned int FDECL(alarm, (unsigned int seconds));
extern void NDECL(pcache_trim);

int 
NDECL(next_timer)
{
#ifdef NEVER

    /* 
     * This code is hosed. Due to an ancient bug, this never returned anything
     * other than 1. When this bug was fixed, certain operating systems 
     * decided to return pretty wild values, more or less thoroughly
     * breaking the wait queue stuff.
     * As far as I can tell, this _needs_ to return 1 in order for do_second()
     * to function properly.
     */

    int result;

    result = mudstate.dump_counter;
    if (mudstate.check_counter < result)
	result = mudstate.check_counter;
    if (mudstate.idle_counter < result)
	result = mudstate.idle_counter;
    if (mudstate.rwho_counter < result)
	result = mudstate.rwho_counter;
    result -= mudstate.now;
    if (result <= 0)
	result = 1;
    return result;
#else
    return 1;
#endif				/* NEVER */
}

void 
NDECL(init_timer)
{
    mudstate.now = time(NULL);
    mudstate.dump_counter = ((mudconf.dump_offset == 0) ?
		mudconf.dump_interval : mudconf.dump_offset) + mudstate.now;
    mudstate.check_counter = ((mudconf.check_offset == 0) ?
	      mudconf.check_interval : mudconf.check_offset) + mudstate.now;
    mudstate.idle_counter = mudconf.idle_interval + mudstate.now;
    mudstate.rwho_counter = mudconf.rwho_interval + mudstate.now;
    alarm(next_timer());
}

void 
NDECL(dispatch)
{
    char *cmdsave;

    cmdsave = mudstate.debug_cmd;
    mudstate.debug_cmd = (char *) "< dispatch >";

    /* this routine can be used to poll from interface.c */

    if (!mudstate.alarm_triggered)
	return;
    mudstate.alarm_triggered = 0;
    mudstate.now = time(NULL);

    do_second();

    /* Free list reconstruction */

    if ((mudconf.control_flags & CF_DBCHECK) &&
	(mudstate.check_counter <= mudstate.now)) {
	mudstate.check_counter = mudconf.check_interval + mudstate.now;
	mudstate.debug_cmd = (char *) "< dbck >";
	cache_reset(0);
	do_dbck(NOTHING, NOTHING, 0);
	cache_reset(0);
	pcache_trim();
    }
    /* Database dump routines */

    if ((mudconf.control_flags & CF_CHECKPOINT) &&
	(mudstate.dump_counter <= mudstate.now)) {
	pool_reset();		/* Clear extra buffer pools */
	mudstate.dump_counter = mudconf.dump_interval + mudstate.now;
	mudstate.debug_cmd = (char *) "< dump >";
	fork_and_dump(0);
    }
    /* Idle user check */

    if ((mudconf.control_flags & CF_IDLECHECK) &&
	(mudstate.idle_counter <= mudstate.now)) {
	mudstate.idle_counter = mudconf.idle_interval + mudstate.now;
	mudstate.debug_cmd = (char *) "< idlecheck >";
	cache_reset(0);
	check_idle();

    }

#ifdef RWHO_IN_USE
    if ((mudconf.control_flags & CF_RWHO_XMIT) &&
	(mudstate.rwho_counter <= mudstate.now)) {
	mudstate.rwho_counter = mudconf.rwho_interval + mudstate.now;
	mudstate.debug_cmd = (char *) "< rwho update >";
	rwho_update();
    }
#endif

    /* reset alarm */

    alarm(1);
    mudstate.debug_cmd = cmdsave;
}

/* ---------------------------------------------------------------------------
 * do_timewarp: Adjust various internal timers.
 */

void 
do_timewarp(player, cause, key, arg)
    dbref player, cause;
    int key;
    char *arg;
{
    int secs;

    secs = atoi(arg);

    if ((key == 0) || (key & TWARP_QUEUE))	/* Sem/Wait queues */
	do_queue(player, cause, QUEUE_WARP, arg);
    if (key & TWARP_DUMP)
	mudstate.dump_counter -= secs;
    if (key & TWARP_CLEAN)
	mudstate.check_counter -= secs;
    if (key & TWARP_IDLE)
	mudstate.idle_counter -= secs;
    if (key & TWARP_RWHO)
	mudstate.rwho_counter -= secs;
}
