# include "GObject.h"
# include "GObject.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 <string.h>
#include <stdlib.h>
#include <vgagl.h>
#include <stdio.h>
#include "../include/io.h"

static struct GObject * GObject_setdata (void * _self, void * data) {
	struct GObject * self = cast(GObject, _self);

	size_t nbytes = (self->width)*
			(self->height)*
			(self->bytesperpixel);

	memcpy(self->buffer, data, nbytes);
	return (void *) self;
}

static struct GObject * GObject_godisplay (void * _self, int x, int y) {
	struct GObject * self = cast(GObject, _self);

	D_ENTRY("GObject.godisplay");
	debug_printf("displaying at: %d,%d\n", x, y);
	if(self->bytesperpixel == BYTESPERPIXEL)
		gl_putbox(x,y, self->width, self->height, self->buffer);
	else
	{	size_t 	nbytes	= (self->width)*(self->height)*BYTESPERPIXEL;
		size_t	depth	= self->bytesperpixel;
		char *	buffer2 = malloc(nbytes);
		char *	buffer1	= self->buffer;
		size_t	count, count2;
		assert(buffer2);

		for(count=0;count < nbytes;count+= depth)
			for(count2 = 0; count2 < depth; count2++)
			buffer2[count+count2] = buffer1[count+count2];

		gl_putbox(x,y, self->width, self->height, self->buffer);
		free(buffer2);

	}
	D_LEAVE
	return (void *) self;
}

static struct GObject * GObject_goundisplay (void * _self, int x, int y) {
	struct GObject * self = cast(GObject, _self);

	gl_fillbox(x, y, self->width, self->height, 0);
	return self;
}

static struct GObject * GObject_gomove (void * _self, int x1, int y1, int x2, int y2) {
	struct GObject * self = cast(GObject, _self);

	D_ENTRY("GObject.gomove");
	debug_printf("from %d,%d to %d, %d\n", x1, y1, x2, y2);
	gl_fillbox(x1, y1, self->width, self->height, 0);
	godisplay(self, x2, y2);
	D_LEAVE
	return (void *) self;
}

static struct GObject * GObject_save (void * _self, FILE * fp) {
	struct GObject * self = cast(GObject, _self);

	size_t	nbytes = self->width * self->height * self->bytesperpixel;
	assert(fp);

	fwrite(&(self->width),sizeof(self->width),1,fp);
	fwrite(&(self->height),sizeof(self->height),1,fp);
	fwrite(&(self->bytesperpixel),sizeof(self->bytesperpixel),1,fp);
	fwrite(self->buffer,1,nbytes,fp);

	return (void *) self;
}

static struct GObject * GObject_load (void * _self, FILE * fp) {
	struct GObject * self = cast(GObject, _self);

	size_t	nbytes;

	fread(&(self->width),sizeof(self->width),1,fp);
	fread(&(self->height),sizeof(self->height),1,fp);
	fread(&(self->bytesperpixel),sizeof(self->bytesperpixel),1,fp);

	free(self->buffer);
	nbytes = self->width * self->height * self->bytesperpixel;
	self->buffer = malloc(nbytes);
	assert(self->buffer);

	fread(self->buffer,nbytes,1,fp);
	return (void *) self;
}

static void * GObject_ctor (void * _self, va_list * app) {
	struct GObject *self = super_ctor(GObject, _self, *app);

	size_t	nbytes;

	self->width		= va_arg(*app, int);
	self->height		= va_arg(*app, int);
	self->bytesperpixel	= va_arg(*app, int);

	nbytes			= (self->width)*
				  (self->height)*
				  (self->bytesperpixel);
	self->buffer		= calloc(nbytes,1);

	assert(self->buffer);
	return (void *) self;
}

static void * GObject_dtor (void * _self) {
	struct GObject * self = cast(GObject, _self);

	free(self->buffer);
	super_dtor(GObject, self);

	return (void *) self;
}

static int GObject_differ (const void * _self, const void * b) {
	return (int) 0;
}

static int GObject_puto (const void * _self, FILE * fp) {
	return (int) 0;
}

static void * GObject_geto (void * _self, FILE * fp) {
	return (void *) 0;
}

static void * GObject_clone (const void * _self) {
	const struct GObject * self = cast(GObject, _self);

	void * newO = new(GObject, self->width,
				self->height, self->bytesperpixel);

	assert(newO);
	setdata(newO, self->buffer);
	return newO;
}

struct GObject * setdata (void * _self, void * data) {
	const struct GClass * class = cast(GClass, classOf(_self));

	assert(class -> setdata.method);
	return ((struct GObject * (*) ()) class -> setdata.method)(_self, data);
}

struct GObject * super_setdata (const void * _class, void * _self, void * data) {
	const struct GClass * superclass = cast(GClass, super(_class));

	assert(superclass -> setdata.method);
	return ((struct GObject * (*) ()) superclass -> setdata.method)(_self, data);
}

struct GObject * godisplay (void * _self, int x, int y) {
	const struct GClass * class = cast(GClass, classOf(_self));

	assert(class -> godisplay.method);
	return ((struct GObject * (*) ()) class -> godisplay.method)(_self, x, y);
}

struct GObject * super_godisplay (const void * _class, void * _self, int x, int y) {
	const struct GClass * superclass = cast(GClass, super(_class));

	assert(superclass -> godisplay.method);
	return ((struct GObject * (*) ()) superclass -> godisplay.method)(_self, x, y);
}

struct GObject * goundisplay (void * _self, int x, int y) {
	const struct GClass * class = cast(GClass, classOf(_self));

	assert(class -> goundisplay.method);
	return ((struct GObject * (*) ()) class -> goundisplay.method)(_self, x, y);
}

struct GObject * super_goundisplay (const void * _class, void * _self, int x, int y) {
	const struct GClass * superclass = cast(GClass, super(_class));

	assert(superclass -> goundisplay.method);
	return ((struct GObject * (*) ()) superclass -> goundisplay.method)(_self, x, y);
}

struct GObject * gomove (void * _self, int x1, int y1, int x2, int y2) {
	const struct GClass * class = cast(GClass, classOf(_self));

	assert(class -> gomove.method);
	return ((struct GObject * (*) ()) class -> gomove.method)(_self, x1, y1, x2, y2);
}

struct GObject * super_gomove (const void * _class, void * _self, int x1, int y1, int x2, int y2) {
	const struct GClass * superclass = cast(GClass, super(_class));

	assert(superclass -> gomove.method);
	return ((struct GObject * (*) ()) superclass -> gomove.method)(_self, x1, y1, x2, y2);
}

struct GObject * save (void * _self, FILE * fp) {
	const struct GClass * class = cast(GClass, classOf(_self));

	assert(class -> save.method);
	return ((struct GObject * (*) ()) class -> save.method)(_self, fp);
}

struct GObject * super_save (const void * _class, void * _self, FILE * fp) {
	const struct GClass * superclass = cast(GClass, super(_class));

	assert(superclass -> save.method);
	return ((struct GObject * (*) ()) superclass -> save.method)(_self, fp);
}

struct GObject * load (void * _self, FILE * fp) {
	const struct GClass * class = cast(GClass, classOf(_self));

	assert(class -> load.method);
	return ((struct GObject * (*) ()) class -> load.method)(_self, fp);
}

struct GObject * super_load (const void * _class, void * _self, FILE * fp) {
	const struct GClass * superclass = cast(GClass, super(_class));

	assert(superclass -> load.method);
	return ((struct GObject * (*) ()) superclass -> load.method)(_self, fp);
}

static void * GClass_ctor (void * _self, va_list * app) {
	struct GClass * self = super_ctor(GClass, _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) setdata)
		{	if (tag)
				self -> setdata.tag = tag,
				self -> setdata.selector = selector;
			self -> setdata.method = method;
			continue;
		}
		if (selector == (Method) godisplay)
		{	if (tag)
				self -> godisplay.tag = tag,
				self -> godisplay.selector = selector;
			self -> godisplay.method = method;
			continue;
		}
		if (selector == (Method) goundisplay)
		{	if (tag)
				self -> goundisplay.tag = tag,
				self -> goundisplay.selector = selector;
			self -> goundisplay.method = method;
			continue;
		}
		if (selector == (Method) gomove)
		{	if (tag)
				self -> gomove.tag = tag,
				self -> gomove.selector = selector;
			self -> gomove.method = method;
			continue;
		}
		if (selector == (Method) save)
		{	if (tag)
				self -> save.tag = tag,
				self -> save.selector = selector;
			self -> save.method = method;
			continue;
		}
		if (selector == (Method) load)
		{	if (tag)
				self -> load.tag = tag,
				self -> load.selector = selector;
			self -> load.method = method;
			continue;
		}
	}
	return self;
}

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

static const struct ClassInit _GClass = { { MAGIC }, initGClass };
const void * GClass = & _GClass;

static const void * initGObject (void)
{
	return ((struct Object *) GObject) -> class ? GObject :
		(GObject = new(GClass,
			"GObject", Object, sizeof(struct GObject),
			setdata, "setdata", GObject_setdata,
			godisplay, "godisplay", GObject_godisplay,
			goundisplay, "goundisplay", GObject_goundisplay,
			gomove, "gomove", GObject_gomove,
			save, "save", GObject_save,
			load, "load", GObject_load,
			ctor, "ctor", GObject_ctor,
			dtor, "dtor", GObject_dtor,
			differ, "differ", GObject_differ,
			puto, "puto", GObject_puto,
			geto, "geto", GObject_geto,
			clone, "clone", GObject_clone,
			(void *) 0));
}

static const struct ClassInit _GObject = { { MAGIC }, initGObject };
const void * GObject = & _GObject;
