/* 
 * JGimp - A Java extension for the GIMP
 * Copyright (C) 2002  Georgia Tech Research Corp.
 * Written by Michael Terry, mterry@cc.gatech.edu
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <string.h>

#include "jgimp_data_conversions.h"
#include "jgimp_constants.h"

#include <libgimp/gimp.h>

#include <jni.h>

/* Constructor types */
#define CONSTRUCTOR_NAME                      "<init>"

jobject get_plugin_proxy(JNIEnv *env);

jobject GimpParam_to_JGimpData(JNIEnv* env, GimpParam *param, int array_len)
{
	jobject   constructor_data;
	jclass    return_class_ID;
	jmethodID constructor_ID;
	jobject   plugin_proxy;
	int       i;

	if (param == NULL)
	{
		fprintf(stderr, "JGimp: NULL GimpParam passed in to GimpParam_to_JGimpData. Returning NULL\n");
		return NULL;
	}
	switch (param->type)
	{
		case GIMP_PDB_INT32:
			return_class_ID = (*env)->FindClass(env, JGIMP_INT32_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpInt32 class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpInt32 constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_int32);
			break;

		case GIMP_PDB_INT16:
			return_class_ID = (*env)->FindClass(env, JGIMP_INT16_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpInt16 class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(S)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpInt16 constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_int16);
			break;

		case GIMP_PDB_INT8:
			return_class_ID = (*env)->FindClass(env, JGIMP_INT8_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpInt8 class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(B)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpInt8 constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_int8);
			break;

		case GIMP_PDB_FLOAT:
			return_class_ID = (*env)->FindClass(env, JGIMP_FLOAT_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpFloat class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(D)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpFloat constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_float);
			break;

		case GIMP_PDB_STRING:
			return_class_ID = (*env)->FindClass(env, JGIMP_STRING_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpString class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(Ljava/lang/String;)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpString constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_data =(*env)->NewStringUTF(env, param->data.d_string);
			if (constructor_data == NULL)
			{
				fprintf(stderr, "JGimp internal error: Couldn't allocate new String to pass to JGimpString constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, constructor_data);
			break;

		case GIMP_PDB_INT32ARRAY:
			return_class_ID = (*env)->FindClass(env, JGIMP_INT32_ARRAY_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpInt32Array class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "([I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpInt32Array constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_data =(*env)->NewIntArray(env, array_len);
			if (constructor_data == NULL)
			{
				fprintf(stderr, "JGimp internal error: Couldn't allocate new jintarray to pass to JGimpInt32Array constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			else
			{
				jint *theArray = (*env)->GetIntArrayElements(env, constructor_data, NULL);
				g_memmove(theArray, param->data.d_int32array, sizeof(jint) * array_len);
				(*env)->ReleaseIntArrayElements(env, constructor_data, theArray, 0);
				return (*env)->NewObject(env, return_class_ID, constructor_ID, constructor_data);
			}
			break;

		case GIMP_PDB_INT16ARRAY:
			return_class_ID = (*env)->FindClass(env, JGIMP_INT16_ARRAY_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpInt16Array class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "([S)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpInt16Array constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_data =(*env)->NewShortArray(env, array_len);
			if (constructor_data == NULL)
			{
				fprintf(stderr, "JGimp internal error: Couldn't allocate new jshortarray to pass to JGimpInt16Array constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			else
			{
				jshort *theArray = (*env)->GetShortArrayElements(env, constructor_data, NULL);
				g_memmove(theArray, param->data.d_int16array, sizeof(jshort) * array_len);
				(*env)->ReleaseShortArrayElements(env, constructor_data, theArray, 0);
				return (*env)->NewObject(env, return_class_ID, constructor_ID, constructor_data);
			}
			break;

		case GIMP_PDB_INT8ARRAY:
			return_class_ID = (*env)->FindClass(env, JGIMP_INT8_ARRAY_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpInt8Array class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "([B)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpInt8Array constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_data =(*env)->NewByteArray(env, array_len);
			if (constructor_data == NULL)
			{
				fprintf(stderr, "JGimp internal error: Couldn't allocate new jbytearray to pass to JGimpInt8Array constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			else
			{
				jbyte *theArray = (*env)->GetByteArrayElements(env, constructor_data, NULL);
				g_memmove(theArray, param->data.d_int8array, sizeof(jbyte) * array_len);
				(*env)->ReleaseByteArrayElements(env, constructor_data, theArray, 0);
				return (*env)->NewObject(env, return_class_ID, constructor_ID, constructor_data);
			}
			break;

		case GIMP_PDB_FLOATARRAY:
			return_class_ID = (*env)->FindClass(env, JGIMP_FLOAT_ARRAY_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpFloatArray class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "([D)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpFloatArray constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_data =(*env)->NewDoubleArray(env, array_len);
			if (constructor_data == NULL)
			{
				fprintf(stderr, "JGimp internal error: Couldn't allocate new jdoublearray to pass to JGimpFloatArray constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			else
			{
				jdouble *theArray = (*env)->GetDoubleArrayElements(env, constructor_data, NULL);
				g_memmove(theArray, param->data.d_floatarray, sizeof(jdouble) * array_len);
				(*env)->ReleaseDoubleArrayElements(env, constructor_data, theArray, 0);
				return (*env)->NewObject(env, return_class_ID, constructor_ID, constructor_data);
			}
			break;

		case GIMP_PDB_STRINGARRAY:
			return_class_ID = (*env)->FindClass(env, JGIMP_STRING_ARRAY_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpStringArray class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "([Ljava/lang/String;)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpStringArray constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_data =(*env)->NewObjectArray(env, array_len, (*env)->FindClass(env, JAVA_STRING_CLASS), (*env)->NewStringUTF(env, ""));
			if (constructor_data == NULL)
			{
				fprintf(stderr, "JGimp internal error: Couldn't allocate new jobjectarray to pass to JGimpStringArray constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			else
			{
				for (i = 0; i < array_len; i++)
				{
					(*env)->SetObjectArrayElement(env, constructor_data, i, (*env)->NewStringUTF(env, param->data.d_stringarray[i]));
				}
				return (*env)->NewObject(env, return_class_ID, constructor_ID, constructor_data);
			}
			break;

		case GIMP_PDB_COLOR:
			return_class_ID = (*env)->FindClass(env, JGIMP_COLOR_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpColor class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(III)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpColor constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_color.red, param->data.d_color.green, param->data.d_color.blue);
			break;

		case GIMP_PDB_REGION:
			return_class_ID = (*env)->FindClass(env, JGIMP_REGION_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpRegion class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(IIII)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpRegion constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_region.x, param->data.d_region.y, param->data.d_region.width, param->data.d_region.height);
			break;

		case GIMP_PDB_DISPLAY:
			plugin_proxy = get_plugin_proxy(env);
			if (plugin_proxy == NULL)
			{
				fprintf(stderr, "JGimp error: Couldn't get reference to JGimpPlugInProxy in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}

			return_class_ID = (*env)->FindClass(env, JGIMP_DISPLAY_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpDisplay class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(Lorg/gimp/jgimp/proxy/JGimpProxy;I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpDisplay constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, plugin_proxy, param->data.d_display);
			break;

		case GIMP_PDB_IMAGE:
			plugin_proxy = get_plugin_proxy(env);
			if (plugin_proxy == NULL)
			{
				fprintf(stderr, "JGimp error: Couldn't get reference to JGimpPlugInProxy in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}

			return_class_ID = (*env)->FindClass(env, JGIMP_IMAGE_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpImage class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(Lorg/gimp/jgimp/proxy/JGimpProxy;I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpImage constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, plugin_proxy, param->data.d_image);
			break;

		case GIMP_PDB_LAYER:
			plugin_proxy = get_plugin_proxy(env);
			if (plugin_proxy == NULL)
			{
				fprintf(stderr, "JGimp error: Couldn't get reference to JGimpPlugInProxy in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}

			return_class_ID = (*env)->FindClass(env, JGIMP_LAYER_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpLayer class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(Lorg/gimp/jgimp/proxy/JGimpProxy;I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpLayer constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, plugin_proxy, param->data.d_layer);
			break;

		case GIMP_PDB_CHANNEL:
			plugin_proxy = get_plugin_proxy(env);
			if (plugin_proxy == NULL)
			{
				fprintf(stderr, "JGimp error: Couldn't get reference to JGimpPlugInProxy in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}

			return_class_ID = (*env)->FindClass(env, JGIMP_CHANNEL_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpChannel class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(Lorg/gimp/jgimp/proxy/JGimpProxy;I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpChannel constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, plugin_proxy, param->data.d_channel);
			break;

		case GIMP_PDB_DRAWABLE:
			plugin_proxy = get_plugin_proxy(env);
			if (plugin_proxy == NULL)
			{
				fprintf(stderr, "JGimp error: Couldn't get reference to JGimpPlugInProxy in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}

			return_class_ID = (*env)->FindClass(env, JGIMP_DRAWABLE_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpDrawable class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(Lorg/gimp/jgimp/proxy/JGimpProxy;I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpDrawable constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, plugin_proxy, param->data.d_drawable);
			break;

		case GIMP_PDB_SELECTION:
			return_class_ID = (*env)->FindClass(env, JGIMP_SELECTION_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpSelection class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpSelection constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_selection);
			break;

		case GIMP_PDB_BOUNDARY:
			return_class_ID = (*env)->FindClass(env, JGIMP_BOUNDARY_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpBoundary class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpBoundary constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_boundary);
			break;

		case GIMP_PDB_PATH:
			return_class_ID = (*env)->FindClass(env, JGIMP_PATH_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpPath class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpPath constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_path);
			break;

#ifndef JGIMP_COMPILE_FOR_FILMGIMP
		case GIMP_PDB_PARASITE:
			return_class_ID = (*env)->FindClass(env, JGIMP_PARASITE_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpParasite class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "()V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpParasite constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_image);
			break;
#endif /* JGIMP_COMPILE_FOR_FILMGIMP */

		case GIMP_PDB_STATUS:
			return_class_ID  = (*env)->FindClass(env, JGIMP_PDB_STATUS_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpPDBStatus class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "(I)V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpPDBStatus constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID, param->data.d_status);
			break;

		case GIMP_PDB_END:
			return_class_ID  = (*env)->FindClass(env, JGIMP_END_CLASS);
			if (return_class_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Couldn't find JGimpEnd class in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			constructor_ID = (*env)->GetMethodID(env, return_class_ID, CONSTRUCTOR_NAME, "()V");
			if (constructor_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Can't get method ID for JGimpEnd constructor in jgimp.GimpParam_to_JGimpData\n");
				return NULL;
			}
			return (*env)->NewObject(env, return_class_ID, constructor_ID);
			break;

		default:
			fprintf(stderr, "JGimp error: Unknown GimpParam passed in. Type: %d. in jgimp.GimpParam_to_JGimpData\n", param->type);
			return NULL;
	}
	return NULL;
}

struct ConvertedGimpParam* JGimpData_to_GimpParam(JNIEnv* env, jobject jgimp_data)
{
	struct ConvertedGimpParam *return_data;
	jmethodID pdbArgType_method_ID;
	jmethodID getData_method_ID;
	jobject data_object;
	
	return_data = g_new0(struct ConvertedGimpParam, 1);
	if (!return_data)
	{
		fprintf(stderr, "JGimp: Could not allocate GimpParam in jgimp.JGimpData_to_GimpParam\n");
		return NULL;
	}

	pdbArgType_method_ID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, jgimp_data), "getGimpPDBArgType", "()I");
	if (pdbArgType_method_ID == 0)
	{
		fprintf(stderr, "JGimp internal error: Could not get getGimpPDBArgType methodID in jgimp.JGimpData_to_GimpParam\n");
		return NULL;
	}
	return_data->param.type = (*env)->CallIntMethod(env, jgimp_data, pdbArgType_method_ID);

	switch (return_data->param.type)
	{
		case GIMP_PDB_INT32:
		case GIMP_PDB_DISPLAY:
		case GIMP_PDB_IMAGE:
		case GIMP_PDB_LAYER:
		case GIMP_PDB_CHANNEL:
		case GIMP_PDB_DRAWABLE:
		case GIMP_PDB_SELECTION:
		case GIMP_PDB_BOUNDARY:
		case GIMP_PDB_PATH:
		case GIMP_PDB_STATUS:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, jgimp_data), "convertToInt", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToInt method in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_int32 = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);
			break;

		case GIMP_PDB_INT16:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_INT16_CLASS), "convertToShort", "()S");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToShort method for JGimpInt16 in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_int16 = (*env)->CallShortMethod(env, jgimp_data, getData_method_ID);
			break;

		case GIMP_PDB_INT8:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_INT8_CLASS), "convertToByte", "()B");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToByte method for JGimpInt8 in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_int8 = (*env)->CallByteMethod(env, jgimp_data, getData_method_ID);
			break;

		case GIMP_PDB_FLOAT:
			/* Note: it says float, but GIMP defines it as a double, hence the double data types */
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_FLOAT_CLASS), "convertToDouble", "()D");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToDouble method for JGimpFloat in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_float = (*env)->CallDoubleMethod(env, jgimp_data, getData_method_ID);
			break;

		case GIMP_PDB_STRING:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_STRING_CLASS), "convertToString", "()Ljava/lang/String;");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToString method for JGimpString in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			data_object = (*env)->CallObjectMethod(env, jgimp_data, getData_method_ID);
			if (data_object == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not get String from JGimpString object in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			else
			{
				return_data->param.data.d_string = jstring_to_c_string(env, data_object);
				if (return_data->param.data.d_string == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not copy string from JGimpString object in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					return NULL;
				}
			}
			break;

		case GIMP_PDB_INT32ARRAY:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_INT32_ARRAY_CLASS), "convertToIntArray", "()[I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToIntArray method for JGimpInt32Array in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			data_object = (*env)->CallObjectMethod(env, jgimp_data, getData_method_ID);
			if (data_object == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not get object array from JGimpInt32Array object in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			else
			{
				jint *temp_array = (*env)->GetIntArrayElements(env, data_object, NULL);
				return_data->array_len = (*env)->GetArrayLength(env, data_object);
				if (temp_array == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not _copy_ array from JGimpInt32Array object in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					return NULL;
				}
				return_data->param.data.d_int32array = g_new(jint, return_data->array_len);
				if (return_data->param.data.d_int32array == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not allocate new native gint32 array in JGimpInt32Array in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					(*env)->ReleaseIntArrayElements(env, data_object, temp_array, JNI_ABORT);
					return NULL;
				}
				g_memmove(return_data->param.data.d_int32array, temp_array, sizeof(jint) * return_data->array_len);
				(*env)->ReleaseIntArrayElements(env, data_object, temp_array, JNI_ABORT);
			}
			break;

		case GIMP_PDB_INT16ARRAY:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_INT16_ARRAY_CLASS), "convertToShortArray", "()[S");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToShortArray method for JGimpInt16Array in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			data_object = (*env)->CallObjectMethod(env, jgimp_data, getData_method_ID);
			if (data_object == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not get array object from JGimpInt16Array object in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			else
			{
				jshort *temp_array = (*env)->GetShortArrayElements(env, data_object, NULL);
				return_data->array_len = (*env)->GetArrayLength(env, data_object);
				if (temp_array == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not _copy_ array from JGimpInt16Array object in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					return NULL;
				}
				return_data->param.data.d_int16array = g_new(jshort, return_data->array_len);
				if (return_data->param.data.d_int16array == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not allocate new native gint16 array in JGimpInt16Array in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					(*env)->ReleaseShortArrayElements(env, data_object, temp_array, JNI_ABORT);
					return NULL;
				}
				g_memmove(return_data->param.data.d_int16array, temp_array, sizeof(jshort) * return_data->array_len);
				(*env)->ReleaseShortArrayElements(env, data_object, temp_array, JNI_ABORT);
			}
			break;

		case GIMP_PDB_INT8ARRAY:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_INT8_ARRAY_CLASS), "convertToByteArray", "()[B");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToByteArray method for JGimpInt8Array in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			data_object = (*env)->CallObjectMethod(env, jgimp_data, getData_method_ID);
			if (data_object == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not get array object from JGimpInt8Array object in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			else
			{
				jbyte *temp_array = (*env)->GetByteArrayElements(env, data_object, NULL);
				return_data->array_len = (*env)->GetArrayLength(env, data_object);
				if (temp_array == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not _copy_ array from JGimpInt8Array object in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					return NULL;
				}
				return_data->param.data.d_int8array = g_new(jbyte, return_data->array_len);
				if (return_data->param.data.d_int8array == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not allocate new native gint8 array in JGimpInt8Array in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					(*env)->ReleaseByteArrayElements(env, data_object, temp_array, JNI_ABORT);
					return NULL;
				}
				g_memmove(return_data->param.data.d_int8array, temp_array, sizeof(jbyte) * return_data->array_len);
				(*env)->ReleaseByteArrayElements(env, data_object, temp_array, JNI_ABORT);
			}
			break;

		case GIMP_PDB_FLOATARRAY:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_FLOAT_ARRAY_CLASS), "convertToDoubleArray", "()[D");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToDoubleArray method for JGimpFloatArray in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			data_object = (*env)->CallObjectMethod(env, jgimp_data, getData_method_ID);
			if (data_object == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not get array object from JGimpFloatArray object in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			else
			{
				jdouble *temp_array = (*env)->GetDoubleArrayElements(env, data_object, NULL);
				return_data->array_len = (*env)->GetArrayLength(env, data_object);
				if (temp_array == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not _copy_ array from JGimpFloatArray object in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					return NULL;
				}
				return_data->param.data.d_floatarray = g_new(jdouble, return_data->array_len);
				if (return_data->param.data.d_floatarray == NULL)
				{
					fprintf(stderr, "JGimp internal error: Could not allocate new native gfloat array in JGimpFloatArray in jgimp.JGimpData_to_GimpParam\n");
					g_free(return_data);
					return_data = NULL;
					(*env)->ReleaseDoubleArrayElements(env, data_object, temp_array, JNI_ABORT);
					return NULL;
				}
				g_memmove(return_data->param.data.d_floatarray, temp_array, sizeof(jdouble) * return_data->array_len);
				(*env)->ReleaseDoubleArrayElements(env, data_object, temp_array, JNI_ABORT);
			}
			break;

		case GIMP_PDB_STRINGARRAY:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_STRING_ARRAY_CLASS), "convertToStringArray", "()[Ljava/lang/String;");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load convertToStringArray method for JGimpStringArray in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			data_object = (*env)->CallObjectMethod(env, jgimp_data, getData_method_ID);
			if (data_object == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not get array object from JGimpStringArray object in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			else
			{
				int i = 0;

				return_data->array_len = (*env)->GetArrayLength(env, data_object);
				return_data->param.data.d_stringarray = g_new(char*, return_data->array_len);

				for (i = 0; i < return_data->array_len; i++)
				{
					jobject this_string = (*env)->GetObjectArrayElement(env, data_object, i);
					if (this_string == 0)
					{
						int j = i - 1;

						fprintf(stderr, "JGimp internal error: Could not get string ref (index: %d) from array in JGimpStringArray in jgimp.JGimpData_to_GimpParam\n", i);
						
						while (j >= 0)
						{
							g_free(return_data->param.data.d_stringarray[j]);
							return_data->param.data.d_stringarray[j] = NULL;
							j--;
						}
						g_free(return_data->param.data.d_stringarray);
						return_data->param.data.d_stringarray = NULL;
						g_free(return_data);
						return_data = NULL;
						return NULL;
					}
					return_data->param.data.d_stringarray[i] = jstring_to_c_string(env, this_string);
					/* Frees this local ref (an optimization, but not necessary) */
					(*env)->DeleteLocalRef(env, this_string);
				}
			}
			break;

		case GIMP_PDB_COLOR:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_COLOR_CLASS), "getRed", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load getRed method for JGimpColor in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_color.red = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);

			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_COLOR_CLASS), "getGreen", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load getRed method for JGimpColor in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_color.green = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);

			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_COLOR_CLASS), "getBlue", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load getBlue method for JGimpColor in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_color.blue = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);
			break;

		case GIMP_PDB_REGION:
			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_REGION_CLASS), "getX", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load getX method for JGimpRegion in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_region.x = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);

			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_REGION_CLASS), "getY", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load getY method for JGimpRegion in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_region.y = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);

			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_REGION_CLASS), "getWidth", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load getWidth method for JGimpRegion in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_region.width = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);

			getData_method_ID = (*env)->GetMethodID(env, (*env)->FindClass(env, JGIMP_REGION_CLASS), "getHeight", "()I");
			if (getData_method_ID == 0)
			{
				fprintf(stderr, "JGimp internal error: Could not load getHeight method for JGimpRegion in jgimp.JGimpData_to_GimpParam\n");
				g_free(return_data);
				return_data = NULL;
				return NULL;
			}
			return_data->param.data.d_region.height = (*env)->CallIntMethod(env, jgimp_data, getData_method_ID);
			break;

#ifndef JGIMP_COMPILE_FOR_FILMGIMP
		case GIMP_PDB_PARASITE:
			fprintf(stderr, "Stub for GIMP PDB parasite translation from Java to C\n");
			break;
#endif /* JGIMP_COMPILE_FOR_FILMGIMP */

		case GIMP_PDB_END:
			; /* no-op: no data is held in the end param (as far as I know) */
			break;

		default:
			fprintf(stderr, "Error: unknown JGimpData PDB arg type in jgimp.JGimpData_to_GimpParam: %d\n", return_data->param.type);
			g_free(return_data);
			return_data = NULL;
			return NULL;
	}

	return return_data;
}

void convert_jgimp_param_descriptor(JNIEnv* env, jobject param_descriptor_object, GimpParamDef* param_def)
{
	jclass    class_ID           = NULL;
	jmethodID method_ID          = NULL;
	jstring   name_object        = NULL;
	jstring   description_object = NULL;

	class_ID = (*env)->GetObjectClass(env, param_descriptor_object);
	if (class_ID == NULL)
	{
		fprintf(stderr, "JGimp internal error: couldn't get class ID for a JGimpParamDescriptor in jgimp-data-conversions.convert_jgimp_param_descriptor\n");
		return;
	}
	/* Get the name for this param */
	method_ID = (*env)->GetMethodID(env, class_ID, "getName", "()Ljava/lang/String;");
	if (method_ID == NULL)
	{
		fprintf(stderr, "JGimp internal error: couldn't get method ID for JGimpParamDescriptor's getName in jgimp-data-conversions.convert_jgimp_param_descriptor\n");
		return;
	}
	name_object = (*env)->CallObjectMethod(env, param_descriptor_object, method_ID);
	if (name_object == NULL)
	{
		fprintf(stderr, "JGimp internal error: couldn't get name for JGimpParamDescriptor in jgimp-data-conversions.convert_jgimp_param_descriptor\n");
		return;
	}
	param_def->name = jstring_to_c_string(env, name_object);

	/* Get its description */
	method_ID = (*env)->GetMethodID(env, class_ID, "getDescription", "()Ljava/lang/String;");
	if (method_ID == NULL)
	{
		fprintf(stderr, "JGimp internal error: couldn't get method ID for JGimpParamDescriptor's getDescription in jgimp-data-conversions.convert_jgimp_param_descriptor\n");
		return;
	}
	description_object = (*env)->CallObjectMethod(env, param_descriptor_object, method_ID);
	if (description_object == NULL)
	{
		fprintf(stderr, "JGimp internal error: couldn't get description for JGimpParamDescriptor in jgimp-data-conversions.convert_jgimp_param_descriptor\n");
		return;
	}
	param_def->description = jstring_to_c_string(env, description_object);

	/* Get arg type object */
	method_ID = (*env)->GetMethodID(env, class_ID, "getGimpPDBArgType", "()I");
	if (method_ID == NULL)
	{
		fprintf(stderr, "JGimp internal error: couldn't get method ID for getGimpPDBArgType in JGimpParamDescriptor in jgimp-data-conversions.convert_jgimp_param_descriptor\n");
		return;
	}
	param_def->type = (*env)->CallIntMethod(env, param_descriptor_object, method_ID);
}

char* jstring_to_c_string(JNIEnv* env, jstring in_string)
{
	const char *temp_string = (*env)->GetStringUTFChars(env, in_string, NULL);
	char* return_string = NULL;

	if (temp_string == NULL)
	{
		fprintf(stderr, "JGimp internal error: Could not get char* from GetStringUTFChars in jgimp.jstring_to_c_string\n");
		return NULL;
	}
	return_string = g_strdup(temp_string);
	(*env)->ReleaseStringUTFChars(env, in_string, temp_string);

	return return_string;
}

void free_ConvertedGimpParam(struct ConvertedGimpParam *param)
{
	int i = 0;
	switch (param->param.type)
	{
		case GIMP_PDB_STRING:
			g_free(param->param.data.d_string);
			param->param.data.d_string = NULL;
			break;

		case GIMP_PDB_INT32ARRAY:
			g_free(param->param.data.d_int32array);
			param->param.data.d_int32array = NULL;
			break;

		case GIMP_PDB_INT16ARRAY:
			g_free(param->param.data.d_int16array);
			param->param.data.d_int16array = NULL;
			break;

		case GIMP_PDB_INT8ARRAY:
			g_free(param->param.data.d_int8array);
			param->param.data.d_int8array = NULL;
			break;

		case GIMP_PDB_FLOATARRAY:
			g_free(param->param.data.d_floatarray);
			param->param.data.d_floatarray = NULL;;
			break;

		case GIMP_PDB_STRINGARRAY:
			for (i = 0; i < param->array_len; i++)
			{
				g_free(param->param.data.d_stringarray[i]);
				param->param.data.d_stringarray[i] = NULL;
			}
			g_free(param->param.data.d_stringarray);
			param->param.data.d_stringarray = NULL;
			break;
		default:
			; /* no-op */
	}
	g_free(param);
}

jobject get_plugin_proxy(JNIEnv *env)
{
	jclass    proxy_class_ID;
	jmethodID method_ID;

	/* Get JavaPlugInProxy object */
	proxy_class_ID = (*env)->FindClass(env, JGIMP_PLUG_IN_PROXY_CLASS);
	if (proxy_class_ID == NULL)
	{
		fprintf(stderr, "JGimp error: Couldn't get JGimpPlugInProxy class ID in jgimp.GimpParam_to_JGimpData\n");
		return NULL;
	}
	method_ID = (*env)->GetStaticMethodID(env, proxy_class_ID, "_getInstance", "()Lorg/gimp/jgimp/proxy/JGimpPlugInProxy;");
	if (method_ID == NULL)
	{
		fprintf(stderr, "JGimp error: Couldn't get JGimpPlugInProxy _getInstance ID in jgimp.GimpParam_to_JGimpData\n");
		return NULL;
	}
	return (*env)->CallStaticObjectMethod(env, proxy_class_ID, method_ID);
}
