/*
** Convert objects from Python to CoreFoundation and vice-versa.
*/

#ifdef WITHOUT_FRAMEWORKS
#include <CFBase.h>
#include <CFNumber.h>
#include <CFArray.h>
#include <CFData.h>
#include <CFDictionary.h>
#include <CFString.h>
#include <CFURL.h>
#else
#include <CoreServices/CoreServices.h>
#endif

#include "Python.h"
#include "macglue.h"
#include "pycfbridge.h"


/* ---------------------------------------- */
/* CoreFoundation objects to Python objects */
/* ---------------------------------------- */

PyObject *
PyCF_CF2Python(CFTypeRef src) {
	CFTypeID typeid;
	
	if( src == NULL ) {
		Py_INCREF(Py_None);
		return Py_None;
	}
	typeid = CFGetTypeID(src);
	if (typeid == CFArrayGetTypeID())
		return PyCF_CF2Python_sequence((CFArrayRef)src);
	if (typeid == CFDictionaryGetTypeID())
		return PyCF_CF2Python_mapping((CFDictionaryRef)src);
	return PyCF_CF2Python_simple(src);
}

PyObject *
PyCF_CF2Python_sequence(CFArrayRef src) {
	int size = CFArrayGetCount(src);
	PyObject *rv;
	CFTypeRef item_cf;
	PyObject *item_py = NULL;
	int i;
	
	if ( (rv=PyList_New(size)) == NULL )
		return NULL;
	for(i=0; i<size; i++) {
		item_cf = CFArrayGetValueAtIndex(src, i);
		if (item_cf == NULL ) goto err;
		item_py = PyCF_CF2Python(item_cf);
		if (item_py == NULL ) goto err;
		if (PyList_SetItem(rv, i, item_py) < 0) goto err;
		item_py = NULL;
	}
	return rv;
err:
	Py_XDECREF(item_py);
	Py_DECREF(rv);
	return NULL;
}

PyObject *
PyCF_CF2Python_mapping(CFTypeRef src) {
	int size = CFDictionaryGetCount(src);
	PyObject *rv = NULL;
	CFTypeRef *allkeys = NULL, *allvalues = NULL;
	CFTypeRef key_cf, value_cf;
	PyObject *key_py = NULL, *value_py = NULL;
	int i;
	
	allkeys = malloc(size*sizeof(CFTypeRef *));
	if (allkeys == NULL) {
		PyErr_NoMemory();
		goto err;
	}
	allvalues = malloc(size*sizeof(CFTypeRef *));
	if (allvalues == NULL) {
		PyErr_NoMemory();
		goto err;
	}
	if ( (rv=PyDict_New()) == NULL ) goto err;
	CFDictionaryGetKeysAndValues(src, allkeys, allvalues);
	for(i=0; i<size; i++) {
		key_cf = allkeys[i];
		value_cf = allvalues[i];
		key_py = PyCF_CF2Python(key_cf);
		if (key_py == NULL ) goto err;
		value_py = PyCF_CF2Python(value_cf);
		if (value_py == NULL ) goto err;
		if (PyDict_SetItem(rv, key_py, value_py) < 0) goto err;
		key_py = NULL;
		value_py = NULL;
	}
	return rv;
err:
	Py_XDECREF(key_py);
	Py_XDECREF(value_py);
	Py_XDECREF(rv);
	free(allkeys);
	free(allvalues);
	return NULL;
}

PyObject *
PyCF_CF2Python_simple(CFTypeRef src) {
	CFTypeID typeid;
	
	typeid = CFGetTypeID(src);
	if (typeid == CFStringGetTypeID())
		return PyCF_CF2Python_string((CFStringRef)src);
	if (typeid == CFBooleanGetTypeID())
		return PyBool_FromLong((long)CFBooleanGetValue(src));
	if (typeid == CFNumberGetTypeID()) {
		if (CFNumberIsFloatType(src)) {
			double d;
			CFNumberGetValue(src, kCFNumberDoubleType, &d);
			return PyFloat_FromDouble(d);
		} else {
			long l;
			if (!CFNumberGetValue(src, kCFNumberLongType, &l))
				/* XXXX Out of range! */;
			return PyInt_FromLong(l);
		}
	}
	/* XXXX Should return as CFTypeRef, really... */
	PyMac_Error(resNotFound);
	return NULL;
}

/* Unsure - Return unicode or 8 bit strings? */
PyObject *
PyCF_CF2Python_string(CFStringRef src) {
	int size = CFStringGetLength(src)+1;
	Py_UNICODE *data = malloc(size*sizeof(Py_UNICODE));
	CFRange range;
	PyObject *rv;

	range.location = 0;
	range.length = size;
	if( data == NULL ) return PyErr_NoMemory();
	CFStringGetCharacters(src, range, data);
	rv = (PyObject *)PyUnicode_FromUnicode(data, size-1);
	free(data);
	return rv;
}

/* ---------------------------------------- */
/* Python objects to CoreFoundation objects */
/* ---------------------------------------- */

int
PyCF_Python2CF(PyObject *src, CFTypeRef *dst) {

	if (PyString_Check(src) || PyUnicode_Check(src))
		return PyCF_Python2CF_simple(src, dst);
	if (PySequence_Check(src))
		return PyCF_Python2CF_sequence(src, (CFArrayRef *)dst);
	if (PyMapping_Check(src))
		return PyCF_Python2CF_mapping(src, (CFDictionaryRef *)dst);
	return PyCF_Python2CF_simple(src, dst);
}

int
PyCF_Python2CF_sequence(PyObject *src, CFArrayRef *dst) {
	CFMutableArrayRef rv = NULL;
	CFTypeRef item_cf = NULL;
	PyObject *item_py = NULL;
	int size, i;
	
	if( !PySequence_Check(src) ) {
		PyErr_Format(PyExc_TypeError,
			"Cannot convert %.500s objects to CFArray",
			src->ob_type->tp_name);
		return 0;
	}
	size = PySequence_Size(src);
	rv = CFArrayCreateMutable((CFAllocatorRef)NULL, size, &kCFTypeArrayCallBacks);
	if (rv == NULL) {
		PyMac_Error(resNotFound); 
		goto err;
	}

	for( i=0; i<size; i++) {
		item_py = PySequence_GetItem(src, i);
		if (item_py == NULL) goto err;
		if ( !PyCF_Python2CF(item_py, &item_cf)) goto err;
		Py_DECREF(item_py);
		CFArraySetValueAtIndex(rv, i, item_cf);
		CFRelease(item_cf);
		item_cf = NULL;
	}
	*dst = rv;
	return 1;
err:
	Py_XDECREF(item_py);
	if (rv) CFRelease(rv);
	if (item_cf) CFRelease(item_cf);
	return 0;		
}

int
PyCF_Python2CF_mapping(PyObject *src, CFDictionaryRef *dst) {
	CFMutableDictionaryRef rv = NULL;
	PyObject *aslist = NULL;
	CFTypeRef key_cf = NULL, value_cf = NULL;
	PyObject *item_py = NULL, *key_py = NULL, *value_py = NULL;
	int size, i;
	
	if( !PyMapping_Check(src) ) {
		PyErr_Format(PyExc_TypeError,
			"Cannot convert %.500s objects to CFDictionary",
			src->ob_type->tp_name);
		return 0;
	}
	size = PyMapping_Size(src);
	rv = CFDictionaryCreateMutable((CFAllocatorRef)NULL, size,
					&kCFTypeDictionaryKeyCallBacks,
	                                &kCFTypeDictionaryValueCallBacks);
	if (rv == NULL) {
		PyMac_Error(resNotFound); 
		goto err;
	}
	if ( (aslist = PyMapping_Items(src)) == NULL ) goto err;

	for( i=0; i<size; i++) {
		item_py = PySequence_GetItem(aslist, i);
		if (item_py == NULL) goto err;
		if (!PyArg_ParseTuple(item_py, "OO", &key_py, &value_py)) goto err;
		if ( !PyCF_Python2CF(key_py, &key_cf) ) goto err;
		if ( !PyCF_Python2CF(value_py, &value_cf) ) goto err;
		CFDictionaryAddValue(rv, key_cf, value_cf);
		CFRelease(key_cf);
		key_cf = NULL;
		CFRelease(value_cf);
		value_cf = NULL;
	}
	*dst = rv;
	return 1;
err:
	Py_XDECREF(item_py);
	Py_XDECREF(aslist);
	if (rv) CFRelease(rv);
	if (key_cf) CFRelease(key_cf);
	if (value_cf) CFRelease(value_cf);
	return 0;		
}

int
PyCF_Python2CF_simple(PyObject *src, CFTypeRef *dst) {
	
#if 0
	if (PyObject_HasAttrString(src, "CFType")) {
		*dst = PyObject_CallMethod(src, "CFType", "");
		return (*dst != NULL);
	}
#endif
	if (PyString_Check(src) || PyUnicode_Check(src)) 
		return PyCF_Python2CF_string(src, (CFStringRef *)dst);
	if (PyBool_Check(src)) {
		if (src == Py_True)
			*dst = kCFBooleanTrue;
		else
			*dst = kCFBooleanFalse;
		return 1;
	}
	if (PyInt_Check(src)) {
		long v = PyInt_AsLong(src);
		*dst = CFNumberCreate(NULL, kCFNumberLongType, &v);
		return 1;
	}
	if (PyFloat_Check(src)) {
		double d = PyFloat_AsDouble(src);
		*dst = CFNumberCreate(NULL, kCFNumberDoubleType, &d);
		return 1;
	}
			
	PyErr_Format(PyExc_TypeError,
		  "Cannot convert %.500s objects to CFType",
				     src->ob_type->tp_name);
	return 0;
}

int
PyCF_Python2CF_string(PyObject *src, CFStringRef *dst) {
	char *chars;
	CFIndex size;
	UniChar *unichars;
	
	if (PyString_Check(src)) {
		if ((chars = PyString_AsString(src)) == NULL ) goto err;
		*dst = CFStringCreateWithCString((CFAllocatorRef)NULL, chars, 0);
		return 1;
	}
	if (PyUnicode_Check(src)) {
		/* We use the CF types here, if Python was configured differently that will give an error */
		size = PyUnicode_GetSize(src);
		if ((unichars = PyUnicode_AsUnicode(src)) == NULL ) goto err;
		*dst = CFStringCreateWithCharacters((CFAllocatorRef)NULL, unichars, size);
		return 1;
	}
err:
	PyErr_Format(PyExc_TypeError,
		  "Cannot convert %.500s objects to CFString",
				     src->ob_type->tp_name);
	return 0;
}
