# include "List.h"
# include "List.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 * add1 (struct List * self, const void * element)
{
	self -> end = self -> nelts = 1;
	return (void *) (buf(self)[self -> begin = 0] = element);
}

static void extend (struct List * self)
{
	if (self -> nelts >= dim(self))
	{	* (const void ***) & self -> _.buf = realloc(buf(self),
				2 * dim(self) * sizeof(void *));
		assert(buf(self));
		if (self -> begin && self -> begin != dim(self))
		{	memcpy(self -> _.buf + dim(self) + self -> begin,
				buf(self) + self -> begin,
				(dim(self) - self -> begin)
						* sizeof (void *));
			self -> begin += dim(self);
		}
		else
			self -> begin = 0;
		* (unsigned *) & self -> _.dim *= 2;
	}
	++ self -> nelts;
}

struct Object * addFirst (void * _self, const void * element) {
	struct List * self = cast(List, _self);

	element = cast(Object, element);

	if (! self -> nelts)
		return add1(self, element);
	extend(self);
	if (self -> begin == 0)
		self -> begin = dim(self);
	buf(self)[-- self -> begin] = element;
	return (void *) element;
}

struct Object * addLast (void * _self, const void * element) {
	struct List * self = cast(List, _self);

	element = cast(Object, element);

	if (! self -> nelts)
		return add1(self, element);
	extend(self);
	if (self -> end >= dim(self))
		self -> end = 0;
	buf(self)[self -> end ++] = element;
	return (void *) element;
}

static unsigned List_count (const void * _self) {
	const struct List * self = cast(List, _self);

	return self -> nelts;
}

struct Object * lookAt (const void * _self, unsigned n) {
	const struct List * self = cast(List, _self);

	return (void *) (n >= self -> nelts ? 0 :
		buf(self)[(self -> begin + n) % dim(self)]);
}

struct Object * takeFirst (void * _self) {
	struct List * self = cast(List, _self);

	if (! self -> nelts)
		return 0;
	-- self -> nelts;
	if (self -> begin >= dim(self))
		self -> begin = 0;
	return (void *) buf(self)[self -> begin ++];
}

struct Object * takeLast (void * _self) {
	struct List * self = cast(List, _self);

	if (! self -> nelts)
		return 0;
	-- self -> nelts;
	if (self -> end == 0)
		self -> end = dim(self);
	return (void *) buf(self)[-- self -> end];
}

static int List_puto (const void * _self, FILE * fp) {
	int result;
	unsigned i;
	const struct List * self = cast(List, _self);

	result = super_puto(List, self, fp);
	result += fprintf(fp, "nelts %u {\n", self -> nelts);
	for (i = 0; i < self -> nelts; ++ i)
		result += puto(lookAt(self, i), fp);
	return result + fprintf(fp, "}\n");
}

static void * List_geto (void * _self, FILE * fp) {
	unsigned i, n;
	void * p;
	struct List * self = cast(List, _self);

	if (!super_geto(List, self, fp))
		assert(0);
	if (fscanf(fp, "nelts %u {\n", & n) != 1)
		assert(0);
#ifdef RETRIEVE
	for (i = 0; i < n && (p = retrieve(fp)); ++ i)
		addLast(self, p);
	if (i != n || getc(fp) != '}' || getc(fp) != '\n')
		assert(0);
#endif
	return self;
}

static void * List_clone (const void * _self) {
	struct List * result;
	unsigned i;
	const struct List * self = cast(List, _self);

	result = cast(List, new(classOf(self), dim(self)));
	for (i = 0; i < self -> nelts; ++ i)
		addLast(result, clone(lookAt(self, i)));
	return result;
}

static struct Object * List_find (const void * _self, const void * element) {
	const void * p;
	unsigned i;
	const struct List * self = cast(List, _self);

	for (i = 0; i < self -> nelts; ++ i)
		if (! differ(p = lookAt(self, i), element))
			return (void *) p;
	return 0;
}

static int List_apply (const void * _self, Action action, va_list * app) {
	unsigned i;
	int result;
	const struct List * self = cast(List, _self);

	for (i = 0; i < self -> nelts; ++ i)
		if (! (result = action(lookAt(self, i), * app)))
			return 0;
	return result;
}

struct Object * take (void * _self) {
	const struct ListClass * class = cast(ListClass, classOf(_self));

	assert(class -> take.method);
	return ((struct Object * (*) ()) class -> take.method)(_self);
}

struct Object * super_take (const void * _class, void * _self) {
	const struct ListClass * superclass = cast(ListClass, super(_class));

	assert(superclass -> take.method);
	return ((struct Object * (*) ()) superclass -> take.method)(_self);
}

static void * ListClass_ctor (void * _self, va_list * app) {
	struct ListClass * self = super_ctor(ListClass, _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) take)
		{	if (tag)
				self -> take.tag = tag,
				self -> take.selector = selector;
			self -> take.method = method;
			continue;
		}
	}
	return self;
}

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

static const struct ClassInit _ListClass = { { MAGIC }, initListClass };
const void * ListClass = & _ListClass;

static const void * initList (void)
{
	return ((struct Object *) List) -> class ? List :
		(List = new(ListClass,
			"List", Collection, sizeof(struct List),
			count, "count", List_count,
			puto, "puto", List_puto,
			geto, "geto", List_geto,
			clone, "clone", List_clone,
			find, "find", List_find,
			apply, "apply", List_apply,
			(void *) 0));
}

static const struct ClassInit _List = { { MAGIC }, initList };
const void * List = & _List;
