/***************************************************************************
                          kdesupport.cpp  -  description
                             -------------------
    copyright            : (C) 2001 by Richard Dale
    email                : Lost_Highway@tipitina.demon.co.uk
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as published by*
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>

#include <kdejava/KDESupport.h>
#include <qtjava/QtSupport.h>


DOM::DOMString *
KDESupport::toDOMString(JNIEnv * env, jstring str, DOM::DOMString ** domstring)
{
	const jchar *	_jchar_str;

	if (str == 0L) {
		return 0;
	}

	if (*domstring != 0L) {
		delete *domstring;
	}

	_jchar_str = env->GetStringChars(str, 0);

	if (QtSupport::bigEndianUnicode()) {
		*domstring = new DOM::DOMString((QChar *) _jchar_str, env->GetStringLength(str));
	} else {
static QString *	temp = 0L;

		if (temp == 0L) {
			temp = new QString();
		}

		// Hack to change the big endian unicode in 'str' to little endian in 'temp'.
		temp->setUnicodeCodes((const ushort *) _jchar_str, (long) env->GetStringLength(str));
		*domstring = new DOM::DOMString(*temp);
	}

	env->ReleaseStringChars(str, _jchar_str);
	return *domstring;
}

jstring
KDESupport::fromDOMString(JNIEnv * env, DOM::DOMString * domstring)
{
	if (QtSupport::bigEndianUnicode()) {
		return env->NewString((const jchar *) domstring->unicode(), (long) domstring->length());
	} else {
static QString *	temp = 0L;

		if (temp == 0L) {
			temp = new QString();
		}

		// Hack to change the big endian unicode in 'qstring' to little endian in 'temp'.
		temp->setUnicodeCodes((const ushort *) domstring->unicode(), (long) domstring->length());
		return env->NewString((const jchar *) temp->unicode(), (long) temp->length());
	}
}

KURL::List *
KDESupport::toKURLList(JNIEnv * env, jobjectArray urlList, KURL::List ** kurlList)
{
	int				length;
	int				index;
	jobject			url;

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

	if (*kurlList == NULL) {
		*kurlList = new KURL::List();
	}

	length = env->GetArrayLength(urlList);
	(*kurlList)->clear();

	for (index = 0; index < length; index++) {
		url = (jobject) env->GetObjectArrayElement(urlList, index);
		(*kurlList)->append((KURL &) * (KURL *) QtSupport::getQt(env, url));
	}

	return *kurlList;
}

KFileItemList *
KDESupport::toKFileItemList(JNIEnv * env, jobjectArray itemList, KFileItemList ** kitemList)
{
	int				length;
	int				index;
	jobject			fileItem;

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

	if (*kitemList == NULL) {
		*kitemList = new KFileItemList();
	}

	length = env->GetArrayLength(itemList);
	(*kitemList)->clear();

	for (index = 0; index < length; index++) {
		fileItem = (jobject) env->GetObjectArrayElement(itemList, index);
		(*kitemList)->append((const KFileItem *) QtSupport::getQt(env, fileItem));
	}

	return *kitemList;
}

KCmdLineOptions *
KDESupport::toKCmdLineOptions(JNIEnv * env, jobjectArray optionsArray)
{
	jstring				jstr;
	const char *		str;
	int					length;
	int					index;
	jobjectArray 		optionEntry;
	KCmdLineOptions * 	cmdLineOptions;
	
	length = env->GetArrayLength(optionsArray);
	// Allocate 'length + 1' entries, to include an all NULLs last entry
	cmdLineOptions = (KCmdLineOptions *) calloc(length + 1, sizeof(struct KCmdLineOptions));
	
	for (index = 0; index < length; index++) {
		optionEntry = (jobjectArray) env->GetObjectArrayElement(optionsArray, index);
		
		jstr = (jstring) env->GetObjectArrayElement(optionEntry, 0);
		if (jstr == 0) {
			cmdLineOptions[index].name = 0;
		} else {
			str = env->GetStringUTFChars(jstr, NULL);
			cmdLineOptions[index].name = strdup(str);
			env->ReleaseStringUTFChars(jstr, str);
		}
		
		jstr = (jstring) env->GetObjectArrayElement(optionEntry, 1);
		if (jstr == 0) {
			cmdLineOptions[index].description = 0;
		} else {
			str = env->GetStringUTFChars(jstr, NULL);
			cmdLineOptions[index].description = strdup(str);
			env->ReleaseStringUTFChars(jstr, str);
		}
		
		jstr = (jstring) env->GetObjectArrayElement(optionEntry, 2);
		if (jstr == 0) {
			cmdLineOptions[index].def = 0;
		} else {
			str = env->GetStringUTFChars(jstr, NULL);
			cmdLineOptions[index].def = strdup(str);
			env->ReleaseStringUTFChars(jstr, str);
		}
	}
	
	// An entry with three null values terminates the array
	cmdLineOptions[length].name = 0;
	cmdLineOptions[length].description = 0;
	cmdLineOptions[length].def = 0;
	
	return cmdLineOptions;
}

QByteArray *
KDESupport::toQByteArrayFromStream(JNIEnv * env, QByteArray * qbyteArray, jobject byteStream)
{
	jclass			cls;
	jmethodID		toByteArrayMid;
	jbyteArray		byteArray;
	
	if (byteStream == 0) {
		return 0;
	}
	
	cls = env->GetObjectClass(byteStream);
	toByteArrayMid = env->GetMethodID(cls, "toByteArray", "()[B");
	if (toByteArrayMid == NULL) {
		return NULL;
	}

	byteArray = (jbyteArray) env->CallObjectMethod(byteStream, toByteArrayMid);
	return QtSupport::toQByteArray(env, byteArray, &qbyteArray);
}
	
jobject
KDESupport::arrayWithQCStringList(JNIEnv * env, QCStringList * qcstringList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, qcstringList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	QCStringList::Iterator it;
	
	for (it = qcstringList->begin(); it != qcstringList->end(); ++it) {
		QCString currentQCString = (QCString) *it;
		
		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										env->NewStringUTF(currentQCString.data()) ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;
}

jobject
KDESupport::arrayWithOfferList(JNIEnv * env, KTrader::OfferList * offerList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, offerList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	KTrader::OfferList::Iterator it;
	
	for (it = offerList->begin(); it != offerList->end(); ++it) {
		KService::Ptr ptr = *it;
		// Increment the reference count to prevent C++ garbage collection.
		// The contents of the offerList should be deref'd when it's finalized,
		// so ArrayList should really be sub-classed, and finalize() overriden.
		ptr->_KShared_ref();
		KService * currentOffer = ptr;
		
		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										QtSupport::objectForQtKey(env, currentOffer, "org.kde.koala.KService") ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;
}

jobject
KDESupport::arrayWithKMainWindowList(JNIEnv * env, QPtrList<KMainWindow>* memberList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, memberList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	for (unsigned int index = 0; index < memberList->count(); index++) {
		KMainWindow * currentWindow = (KMainWindow *) (memberList->at(index));

		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										QtSupport::objectForQtKey(env, currentWindow, "org.kde.koala.KMainWindow") ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;
}

jobject
KDESupport::arrayWithKFileItemList(JNIEnv * env, KFileItemList* itemList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, itemList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	for (unsigned int index = 0; index < itemList->count(); index++) {
		KFileItem * currentItem = (KFileItem *) (itemList->at(index));

		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										QtSupport::objectForQtKey(env, currentItem, "org.kde.koala.KFileItem") ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;
}

jobject
KDESupport::arrayWithKURLList(JNIEnv * env, KURL::List * kurlList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, kurlList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	KURL::List::Iterator it;
	
	for (it = kurlList->begin(); it != kurlList->end(); ++it) {
		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										QtSupport::objectForQtKey(env, (void *) &it, "org.kde.koala.KURL") ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;
}

jobject
KDESupport::arrayWithNodeList(JNIEnv * env, DOM::NodeList * nodeList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, nodeList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	for (unsigned int index = 0; index < nodeList->length(); index++) {
		DOM::Node currentItem = (DOM::Node) (nodeList->item(index));

		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										QtSupport::objectForQtKey(env, new DOM::Node(currentItem), "org.kde.koala.DOMNode") ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;
}

jobject
KDESupport::arrayWithStyleSheetList(JNIEnv * env, DOM::StyleSheetList * styleSheetList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, styleSheetList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	for (unsigned int index = 0; index < styleSheetList->length(); index++) {
		DOM::StyleSheet currentItem = (DOM::StyleSheet) (styleSheetList->item(index));

		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										QtSupport::objectForQtKey(env, new DOM::StyleSheet(currentItem), "org.kde.koala.DOMNode") ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;}


jobject
KDESupport::arrayWithMediaList(JNIEnv * env, DOM::MediaList * mediaList)
{
	jobject			objectArray;
	jclass			cls;
	jmethodID		clearMid;
	jmethodID		addMid;

	objectArray = (jobject) QtSupport::objectForQtKey(env, mediaList, "java.util.ArrayList");

	cls = env->GetObjectClass(objectArray);
	clearMid = env->GetMethodID(cls, "clear", "()V");
	if (clearMid == NULL) {
		return NULL;
	}

	env->CallVoidMethod(objectArray, clearMid);

	addMid = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z");
	if (addMid == NULL) {
		return NULL;
	}

	for (unsigned int index = 0; index < mediaList->length(); index++) {
		DOM::DOMString currentItem = (DOM::DOMString) (mediaList->item(index));

		if (! env->CallBooleanMethod(	objectArray,
										addMid,
										env->NewString((const jchar *) currentItem.unicode(), (long) currentItem.length()) ) )
		{
			return NULL;
		}
	}

	return (jobject) objectArray;
}

QCStringList *
KDESupport::toQCStringList(JNIEnv * env, jobjectArray stringList, QCStringList ** qstringList)
{
	int				length;
	int				index;
	jstring			jstr;
	static QCString * _qstring_temp = 0;

	if (*qstringList == 0) {
		*qstringList = new QCStringList();
	}

	(*qstringList)->clear();

	if (stringList == 0) {
		return *qstringList;
	}

	length = env->GetArrayLength(stringList);
	for (index = 0; index < length; index++) {
		jstr = (jstring) env->GetObjectArrayElement(stringList, index);
		(*qstringList)->append((QCString &) * (QCString *) QtSupport::toQCString(env, jstr, &_qstring_temp));
		env->DeleteLocalRef(jstr);
	}

	return *qstringList;
}
