/* This file is part of the PyObjC package. */
/*
 * Support code for the Apple runtime
 */
#include "pyobjc.h"

#if defined(APPLE_RUNTIME)
#include "objc-runtime-apple.h"

int PyObjCRT_SetupClass(
	Class cls, 
	Class metaCls, 
	const char*name, 
	Class superCls,
	Class rootCls,
	ssize_t ivarSize,
	struct objc_ivar_list* ivarList,
	struct objc_protocol_list* protocolList
)

{
	/* Initialize the structure */
	memset(cls, 0, sizeof(*cls));
	memset(metaCls, 0, sizeof(*cls));

	cls->methodLists = NULL;
	metaCls->methodLists = NULL;
	cls->isa = metaCls;

	cls->info = CLS_CLASS; // |CLS_METHOD_ARRAY;
	metaCls->info = CLS_META; // |CLS_METHOD_ARRAY;

	cls->name = strdup(name);
	if (cls->name == NULL) {
		return -1;
	}
	metaCls->name = strdup(name);
	if (metaCls->name == NULL) {
		free((char*)(cls->name));
		cls->name = NULL;
		return -1;
	}

	cls->methodLists = malloc(sizeof(struct objc_method_list*));
	if (cls->methodLists == NULL) {
		PyErr_NoMemory();
		free((char*)(cls->name)); 
		cls->name = NULL;
		free((char*)(metaCls->name)); 
		metaCls->name = NULL;
		return -1;
	}
	memset(cls->methodLists, 0, sizeof(*(cls->methodLists)));

	metaCls->methodLists = malloc(sizeof(struct objc_method_list*));
	if (cls->methodLists == NULL) {
		PyErr_NoMemory();
		free((char*)(cls->name)); 
		cls->name = NULL;
		free((char*)(metaCls->name)); 
		metaCls->name = NULL;
		free(cls->methodLists);
		cls->methodLists = NULL;
		return -1;
	}
	memset(metaCls->methodLists, 0, sizeof(*(metaCls->methodLists)));

	/*
	 * This is MacOS X specific, and an undocumented feature (long live
	 * Open Source!).
	 *
	 * The code in the objc runtime assumes that the method lists are
	 * terminated by '-1', and will happily overwite existing data if
	 * they aren't.
	 *
	 * Ronald filed a bugreport for this: Radar #3317376
	 */
	cls->methodLists[0] = (struct objc_method_list*)-1;
	metaCls->methodLists[0] = (struct objc_method_list*)-1;

	cls->super_class = superCls;
	metaCls->super_class = superCls->isa;
	metaCls->isa = rootCls->isa;

	cls->instance_size = ivarSize;
	cls->ivars = ivarList;

	metaCls->instance_size = metaCls->super_class->instance_size;
	metaCls->ivars = NULL;

	metaCls->protocols = cls->protocols = protocolList;

	return 0;
}

void PyObjCRT_ClearClass(Class cls)
{
	if (cls->methodLists) {
		if (cls->methodLists) {
			struct objc_method_list** cur;

			cur = cls->methodLists;
			while (*cur != (struct objc_method_list*)-1) {
				if (*cur != NULL) {
					free(*cur);
					*cur = NULL;
				}
				cur++;
			}
			free(cls->methodLists);
			cls->methodLists = NULL;
		}
		cls->methodLists = NULL;
	}

	if (cls->name) {
		free((char*)(cls->name));
	}
}

struct objc_method_list *PyObjCRT_AllocMethodList(ssize_t numMethods)
{
	struct objc_method_list *mlist;

	mlist = malloc(sizeof(struct objc_method_list)
			 + ((numMethods+1) * sizeof(struct objc_method)));

	if (mlist == NULL) {
			return NULL;
	}

	mlist->method_count = 0;
	mlist->obsolete = NULL;

	return mlist;
}

struct objc_protocol_list* PyObjCRT_AllocProtocolList(ssize_t numProtocols)
{
	struct objc_protocol_list *plist;

	plist = malloc(sizeof(struct objc_protocol_list)
			 + ((numProtocols+1) * sizeof(Protocol *)));

	if (plist == NULL) {
			return NULL;
	}

	plist->count = 0;
	plist->next = NULL;

	return plist;
}

#else /* !APPLE_RUNTIME */

static int dummy __attribute__((__unused__));

#endif /* !APPLE_RUNTIME */
