/* Copyright 1989, 1990 by James Aspnes, David Applegate, and Bennet Yee */
/* See the file COPYING for distribution information */
#include "db.h"
#include "config.h"    
#include "bytecode.h"
#include "globals.h"
#include "interface.h"

static datum sys_examine(void)
{
    struct object *o;
    char buf[MAX_STRLEN + MAX_STRLEN + 16];
    datum key;
    datum value;
    char *p;

    /* you examine me */
    if((o = object(me)) == 0) return 0;

    FOREACH(o->vars, key, value) {
	strcpy(buf, string(key));
	strcat(buf, ": ");
	p = buf + strlen(buf);

	switch(*buf) {
	  case STRING_MARKER:
	    if(value != NOTHING) {
		strcpy(p, string(value));
	    }
	    break;
	  case BOOL_MARKER:
	    strcpy(p, value ? "TRUE" : "FALSE");
	    break;
	  case TIME_MARKER:
	    strcpy(p, time_string(value));
	    break;
	  case NUM_MARKER:
	  default:
	    sprintf(p, "%d", value);
	    break;
	}

	notify(you, buf);
    } END_FOREACH;

    /* just dump the names of the sets */
    FOREACH(o->sets, key, value) {
	notify(you, string(key));
    } END_FOREACH;

    if(!isempty(o->actions)) {
	FOREACH(o->actions, key, value) {
	    sprintf(buf, "%c%s", ACTION_MARKER, string(key));
	    notify(you, buf);
	} END_FOREACH;
    }

    return 1;
}

static datum do_request(int *flag)
{
    if(flag_set(you, F_ADMIN)) {
	*flag = 1;
	return 1;
    } else {
	return 0;
    }
}

static datum sys_gc(void)
{
    return do_request(&please_gc);
}

static datum sys_checkpoint(void)
{
    return do_request(&please_checkpoint);
}

static datum sys_shutdown(void)
{
    return do_request(&shutdown_flag);
}
    
/* encrypt password on me */
static datum sys_encrypt_password(void)
{
    extern const char *encrypt_password(const char *);

    datum password;

    if((password = lookup(me, PASSWORD_NAME)) == NOTHING) {
	return 0;
    }
    /* else */
    return set_variable(me, PASSWORD_NAME,
			intern(encrypt_password(string(password))));
}
    
/* checks all the code on me and reports errors to you */
static datum sys_verify(void)
{
    datum key;
    datum value;
    char buf[MAX_STRLEN];
    const char *s;
    datum *code;
    struct object *o;

    if((o = object(me)) == 0) return 0;

    if(!isempty(o->actions)) {
	FOREACH(o->actions, key, value) {
	    if((s = string(value)) == 0) {
		sprintf(buf, "&%s: no code!", string(key));
		notify(you, buf);
	    } else if((code = compile(s)) == 0) {
		sprintf(buf, "&%s: %s", string(key), compile_error);
		notify(you, buf);
	    } else {
		/* everything ok, free the compiled block */
		/* (it's not safe to call set_compiled_string down here) */
		free((void *) code);
	    }
	} END_FOREACH;
    }

    return 1;
}

static datum sys_remove_delays(void)
{
    remove_delays(me);
    return 1;
}

#define SYSFUNC_COUNT (7)

static datum (*sysfuncs[SYSFUNC_COUNT])(void) = {
    sys_examine,
    sys_gc,
    sys_checkpoint,
    sys_shutdown,
    sys_encrypt_password,
    sys_verify,
    sys_remove_delays,
};

datum do_syscall(datum number)
{
    if(number <= 0 || number > SYSFUNC_COUNT) {
	return 0;
    } else {
	return (*sysfuncs[number - 1])();
    }
}