git @ Cat's Eye Technologies beta-Juliet / master src / event.c
master

Tree @master (Download .tar.gz)

event.c @masterraw · history · blame

/*
 * Copyright (c)2004 Cat's Eye Technologies.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 *   Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 *   Neither the name of Cat's Eye Technologies nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
/*
 * event.c
 * Event housekeeping and manipulation for 2Iota.
 * $Id: event.c 518 2010-04-28 17:48:38Z cpressey $
 */

#include <stdio.h>
#include <stdlib.h>

#include "event.h"
#include "symbol.h"
#include "symstr.h"
#include "ehist.h"
#include "etime.h"
#include "debug.h"
#include "2iota.h"

struct event_table *
event_table_new(void)
{
	struct event_table *etab;

	MALLOC(etab, event_table, "event table");

	etab->head = NULL;
	return(etab);
}

struct event *
event_new(struct event_table *etab)
{
	struct event *e;

	MALLOC(e, event, "event");
	
	e->next = etab->head;
	e->name = symstr_new();
	e->head = NULL;
	e->params = symbol_table_new();
	e->duration = etime_zero;
	etab->head = e;
	return(e);
}

struct consequence *
event_consequence_append(struct event *cause,
			 struct symstr *effect,
			 struct etime *delay)
{
	struct consequence *c;

	MALLOC(c, consequence, "consequence");

	c->next = cause->head;
	c->effect = effect;
	if (delay == NULL)
		c->delay = cause->duration;
	else
		c->delay = *delay;

	cause->head = c;

	return(c);
}

struct condition *
consequence_condition_append(struct consequence *c,
			     struct symstr *earlier, struct symstr *later)
{
	struct condition *cond;

	MALLOC(cond, condition, "condition");

	cond->next = c->head;
	cond->earlier = earlier;
	cond->later = later;

	c->head = cond;

	return(cond);
}

/*
 * Given a name of an event, find the matching event with the most
 * specific name in the given event table.
 * Returns NULL if no matching event was found.
 */
struct event *
event_find(struct event_table *etab, struct symstr *ss)
{
	int result;
	struct event *e;
		
	struct event *cand = NULL;
	int rank, order;
	int best_rank = 3;
	int best_order = 65535;		/* XXX well, infinite really */

	for (e = etab->head; e != NULL; e = e->next) {
		symbol_table_unbind(e->params);
		result = symstr_bind(ss, e->name, e->params);
		if (result == SYMSTR_BIND_OK) {
			symstr_specificity(e->name, &rank, &order);
			debug_trace(TRACE_EVENTS, "Found %S, rank=%d, order=%d",
			    e->name, rank, order);
			if (rank < best_rank ||
			    (rank == best_rank && order < best_order)) {
				best_rank = rank;
				best_order = order;
				cand = e;
			}
		}
	}

	if (cand != NULL)
		debug_trace(TRACE_EVENTS, "Best Match %S, rank=%d, order=%d",
			    cand->name, best_rank, best_order);

	return(cand);
}

int
event_happen(struct event *e, struct equeue *eq, struct ehist *eh)
{
	struct consequence *c;
	struct condition *cond;
	struct symstr *ss;
	int result = 0;
	int condok;

	debug_trace(TRACE_EVENTS, "Triggering %S:", e->name);
	for (c = e->head; c != NULL; c = c->next) {
		ss = symstr_substitute(c->effect, e->params);
		debug_trace(TRACE_EVENTS, "Consequence %S:", ss);
		condok = 1;
		for (cond = c->head; cond != NULL; cond = cond->next) {
			/* TODO: subst these too */
			condok = ehist_was_later(eh, cond->later, cond->earlier);
			debug_trace(TRACE_EVENTS,
			    "Condition: %S > %S = %B",
			    cond->later, cond->earlier, condok);
			if (!condok)
				break;
		}
		if (condok) {
			equeue_insert(eq, ss, &c->delay);
			result++;
		} else {
			symstr_free(ss);
		}
	}
	
	return(result);
}

void
event_dump(struct event *e)
{
	struct consequence *c;
	struct condition *cond;

	fprintf(stderr, "event ");
	if (e == NULL) {
		fprintf(stderr, "*NULL*\n");
		return;
	}
	symstr_dump(e->name);
	fprintf(stderr, "\n");

	symbol_table_dump(1, e->params);
	for (c = e->head; c != NULL; c = c->next) {
		fprintf(stderr, "\tcauses ");
		symstr_dump(c->effect);
		fprintf(stderr, " after ");
		etime_dump(&c->delay);
		fprintf(stderr, "\n");
		for (cond = c->head; cond != NULL; cond = cond->next) {
			fprintf(stderr, "\t\twhen ");
			symstr_dump(cond->later);
			fprintf(stderr, " > ");
			symstr_dump(cond->earlier);
			fprintf(stderr, "\n");
		}
	}
}

void
event_table_dump(struct event_table *etab)
{
	struct event *e;

	for (e = etab->head; e != NULL; e = e->next)
		event_dump(e);
}

struct caused_by_table *
caused_by_table_new(void)
{
	struct caused_by_table *ctab;

	MALLOC(ctab, caused_by_table, "caused by table");

	ctab->head = NULL;
	return(ctab);
}

struct caused_by *
caused_by_add(struct caused_by_table *ctab,
	      struct symstr *ss, struct event *e)
{
	struct caused_by *c;

	MALLOC(c, caused_by, "caused by");

	c->next = ctab->head;
	ctab->head = c;
	c->cause = ss;
	c->effect = e;

	return(c);
}

void
caused_by_reconcile(struct event_table *etab,
		    struct caused_by_table *ctab)
{
	struct caused_by *c;
	struct event *e;

	for (c = ctab->head; c != NULL; c = c->next) {
		int match = 0;

		for (e = etab->head; e != NULL; e = e->next) {
			if (symstr_is_literal(e->name) &&
			    symstr_eq(c->cause, e->name)) {
				event_consequence_append(e,
				    c->effect->name, &etime_zero);
				match = 1;
				break;
			}
		}

		if (!match) {
			/* add an event */
			/* TODO: probably leaky */
			/* TODO: only store effect as a name? */
			e = event_new(etab);
			e->name = c->cause;
			event_consequence_append(e, c->effect->name, &etime_zero);
		}
	}
}