# include "Collection.h"
# include "Collection.r"

/******************************************************************************
*									      *
*	(C) 1993 by K. Ballueder					      *
*									      *
*	See README and COPYING for details.				      *
*									      *
*		kballued@charon.physik.uni-osnabrueck.de		      *
*		kballued@jupiter.rz.uni-osnabrueck.de			      *
*									      *
**** Changelog: ***************************************************************
*/

#include <stdlib.h>

static void make (struct Collection * self, unsigned nel)
{
	if (! (self -> dim = nel))
		self -> dim = MINDIM;
	self -> buf = calloc(dim(self), sizeof(void *));
	assert(self -> buf);
}

static void * Collection_ctor (void * _self, va_list * app) {
	struct Collection * self = super_ctor(Collection, _self, app);

	make(self, va_arg(* app, unsigned));
	return self;
}

static void * Collection_dtor (void * _self) {
	struct Collection * self = cast(Collection, _self);

	free(self -> buf), self -> buf = 0;
	return super_dtor(Collection, self);
}

static int Collection_puto (const void * _self, FILE * fp) {
	int result;
	const struct Collection * self = cast(Collection, _self);

	result = super_puto(Collection, self, fp);
	return result + fprintf(fp, "dim %u\n", dim(self));
}

static void * Collection_geto (void * _self, FILE * fp) {
	unsigned n;
	struct Collection * self = cast(Collection, _self);

	if (! super_geto(Collection, self, fp))
		assert(0);
	if (fscanf(fp, "dim %u\n", & n) != 1)
		assert(0);
	make(self, n);
	return self;
}

int isEmpty (const void * _self) {
	return count(_self) == 0;
}

struct Object * add (void * _self, const void * element, ...) {
	struct Object * result;
	va_list ap;
	const struct CollectionClass * class = cast(CollectionClass, classOf(_self));

	element = cast(Object, element);

	assert(class -> add.method);
	va_start(ap, element);
	result = ((struct Object * (*) ()) class -> add.method)(_self, element, & ap);
	va_end(ap);
	return result;
}

struct Object * super_add (const void * _class, void * _self, const void * element, va_list * app) {
	const struct CollectionClass * superclass = cast(CollectionClass, super(_class));

	element = cast(Object, element);

	assert(superclass -> add.method);
	return ((struct Object * (*) ()) superclass -> add.method)(_self, element, app);
}

struct Object * find (const void * _self, const void * element) {
	const struct CollectionClass * class = cast(CollectionClass, classOf(_self));

	element = cast(Object, element);

	assert(class -> find.method);
	return ((struct Object * (*) ()) class -> find.method)(_self, element);
}

struct Object * super_find (const void * _class, const void * _self, const void * element) {
	const struct CollectionClass * superclass = cast(CollectionClass, super(_class));

	element = cast(Object, element);

	assert(superclass -> find.method);
	return ((struct Object * (*) ()) superclass -> find.method)(_self, element);
}

unsigned count (const void * _self) {
	const struct CollectionClass * class = cast(CollectionClass, classOf(_self));

	assert(class -> count.method);
	return ((unsigned (*) ()) class -> count.method)(_self);
}

unsigned super_count (const void * _class, const void * _self) {
	const struct CollectionClass * superclass = cast(CollectionClass, super(_class));

	assert(superclass -> count.method);
	return ((unsigned (*) ()) superclass -> count.method)(_self);
}

int apply (const void * _self, Action action, ...) {
	int result;
	va_list ap;
	const struct CollectionClass * class = cast(CollectionClass, classOf(_self));

	assert(class -> apply.method);
	va_start(ap, action);
	result = ((int (*) ()) class -> apply.method)(_self, action, & ap);
	va_end(ap);
	return result;
}

int super_apply (const void * _class, const void * _self, Action action, va_list * app) {
	const struct CollectionClass * superclass = cast(CollectionClass, super(_class));

	assert(superclass -> apply.method);
	return ((int (*) ()) superclass -> apply.method)(_self, action, app);
}

static void * CollectionClass_ctor (void * _self, va_list * app) {
	struct CollectionClass * self = super_ctor(CollectionClass, _self, app);
	Method selector;
	va_list ap = * app;

	while ((selector = va_arg(ap, Method)))
	{	const char * tag = va_arg(ap, const char *);
		Method method = va_arg(ap, Method);

		if (selector == (Method) add)
		{	if (tag)
				self -> add.tag = tag,
				self -> add.selector = selector;
			self -> add.method = method;
			continue;
		}
		if (selector == (Method) find)
		{	if (tag)
				self -> find.tag = tag,
				self -> find.selector = selector;
			self -> find.method = method;
			continue;
		}
		if (selector == (Method) count)
		{	if (tag)
				self -> count.tag = tag,
				self -> count.selector = selector;
			self -> count.method = method;
			continue;
		}
		if (selector == (Method) apply)
		{	if (tag)
				self -> apply.tag = tag,
				self -> apply.selector = selector;
			self -> apply.method = method;
			continue;
		}
	}
	return self;
}

static const void * initCollectionClass (void)
{
	return ((struct Object *) CollectionClass) -> class ? CollectionClass :
		(CollectionClass = new(Class,
			"CollectionClass", Class, sizeof(struct CollectionClass),
			ctor, "", CollectionClass_ctor,
			(void *) 0));
}

static const struct ClassInit _CollectionClass = { { MAGIC }, initCollectionClass };
const void * CollectionClass = & _CollectionClass;

static const void * initCollection (void)
{
	return ((struct Object *) Collection) -> class ? Collection :
		(Collection = new(CollectionClass,
			"Collection", Object, sizeof(struct Collection),
			ctor, "ctor", Collection_ctor,
			dtor, "dtor", Collection_dtor,
			puto, "puto", Collection_puto,
			geto, "geto", Collection_geto,
			(void *) 0));
}

static const struct ClassInit _Collection = { { MAGIC }, initCollection };
const void * Collection = & _Collection;
