/*
	Little Smalltalk
		Internal class dictionary

		timothy a. budd, 10/84

	In order to facilitate lookup, classes are kept in an internal data
	dictionary.  Classes are inserted into this dictionary using a
	primtitive, and are removed by either being overridden, or being
	flushed at the end of execution.
*/
/*
	The source code for the Little Smalltalk System may be freely
	copied provided that the source of all files is acknowledged
	and that this condition is copied with each file.

	The Little Smalltalk System is distributed without responsibility
	for the performance of the program and without any guarantee of
	maintenance.

	All questions concerning Little Smalltalk should be addressed to:

		Professor Tim Budd
		Department of Computer Science
		The University of Arizona
		Tucson, Arizona
		85721
		USA
*/
# include <stdio.h>
# include "object.h"
# include "number.h"
# include "symbol.h"
# include "primitive.h"

struct class_entry {		/* structure for internal dictionary */
	char *cl_name;
	object *cl_description;
	struct class_entry *cl_link;
	};

static struct class_entry *class_dictionary = 0;
int ca_cdict = 0;
static mstruct *fr_cdict = 0;		/* class dictionary free list */

# define CDICTINIT 30
static struct class_entry cdsinit[CDICTINIT];

/* cdic_init - initialize the internal class dictionary */
cdic_init() {
	struct class_entry *p;
	mstruct *new;
	int i;

	for (p = cdsinit, i = 0; i < CDICTINIT; i++, p++) {
		new = (mstruct *) p;
		new->mlink = fr_cdict;
		fr_cdict = new;
		}
}

/* enter_class - enter a class into the internal class dictionary */
enter_class(name, description)
char *name;
object *description;
{	struct class_entry *p;

	for (p = class_dictionary; p; p = p->cl_link)
		if (strcmp(name, p->cl_name) == 0) {
			assign(p->cl_description, description);
			return;
			}
	/* not found, make a new entry */
	if (fr_cdict) {
		p = (struct class_entry *) fr_cdict;
		fr_cdict = fr_cdict->mlink;
		}
	else {
		p = structalloc(struct class_entry);
		ca_cdict++;
		}
	p->cl_name = name;
	sassign(p->cl_description, description);
	p->cl_link = class_dictionary;
	class_dictionary = p;
}

/* lookup - take a name and find the associated class object */
object *lookup_class(name)
char *name;
{	struct class_entry *p;

	for (p = class_dictionary; p; p = p->cl_link)
		if (strcmp(name, p->cl_name) == 0)
			return(p->cl_description);
	return(NULL);
}

/* free_all_classes - flush all references for the class dictionary */
free_all_classes()
{	struct class_entry *p;

	for (p = class_dictionary; p; p = p->cl_link) {
		obj_dec(p->cl_description);
		}
}

/* class_list - list all the subclasses of a class (recursively),
	indenting by a specified number of tab stops */
class_list(c, n)
class *c;
int n;
{	struct class_entry *p;
	object *prs[2];
	class *q;
	char *name;

	/* first print out this class name */
	if (! is_symbol(c->class_name))
		return;
	sassign(prs[0], c->class_name);
	name = symbol_value(c->class_name);
	sassign(prs[1], new_int(n));
	primitive(SYMPRINT, 2, prs);
	obj_dec(prs[0]);
	obj_dec(prs[1]);

	/* now find all subclasses and print them out */
	for (p = class_dictionary; p; p = p->cl_link) {
		q = (class *) p->cl_description;
		if ((is_symbol(q->super_class)) && 
		   (strcmp(name, symbol_value(q->super_class)) == 0) )
			class_list(q, n+1);
		}
}
