//#include <jni.h>    // The main and uttermost important file (next to this and usejava one)
//#include <jni_md.h> // This one contains all the neccessary type mapping
#include <string.h>
//#include <jvmdi.h>
#include "reflect.h"

#define JAVA_BOOLEAN      1
#define JAVA_CHAR         2
#define JAVA_BYTE         3
#define JAVA_SHORT        4
#define JAVA_INT          5
#define JAVA_LONG         6
#define JAVA_FLOAT        7
#define JAVA_DOUBLE       8
#define JAVA_VOID         9
#define JAVA_BIGINTEGER  11
#define JAVA_BIGDECIMAL  12
#define JAVA_STRING      13
#define JAVA_UNKNOWN     21
#define JAVA_OBJECT      22
#define JAVA_ARRAY      100

#define VALUE_BOOLEAN      1 // Bool
#define VALUE_BYTE         1 // Integer
#define VALUE_SHORT        2
#define VALUE_INT          3
#define VALUE_LONG         4
#define VALUE_BIGINTEGER   5
#define VALUE_FLOAT        1 // Floating point
#define VALUE_DOUBLE       2
#define VALUE_BIGDECIMAL   3
#define VALUE_CHAR         1 // Text
#define VALUE_STRING       2
#define VALUE_UNKNOWN      1 // Other
#define VALUE_OBJECT       1 // the NULL-object (so far the only one)
#define VALUE_ARRAY      100

#define NULL_CHECK0(e) if ((e) == NULL) return NULL

// Debug messages
// 2 = errors in reflect and usejava
// 1 = errors in usejava
// 0 = none
static int _debug = 0;                                                          // No debugging messages...
// To store the list
static jobject javaList = NULL;
static jobject x11Class = NULL;
static jint oH_counter = 0;
static jboolean isConstructor=JNI_FALSE;
//static jboolean exceptionNotCaught=JNI_TRUE;
static jclass jExceptionClass;
static jobject outClass;
static jmethodID jExceptionID;
static int isUTF16;
static jboolean showErrors = JNI_TRUE;

/** JClass : reflection support for classes
  *
  * JClass::getMethods
  * JClass::getConstructors
  * JClass::getFields
  * JClass::toString
  * JClass::getSignature
  */

/** getMethods
  * @param env     The ubiquitous pointer to JNI.
  * @param clazz   The class whose methods are wanted.
  * @param getAll  If true, all superclass methods are also returned.
  * @return        an array contatining Method objects.
  */
jobjectArray JClass::getMethods(JNIEnv* env, jclass clazz, jboolean getAll) {
  if (_debug>1) MFprintf("JClass::getMethods started\n");
  jclass objClazz = env->GetObjectClass(clazz);                                 // get the reference to the class
  jmethodID mid;                                                                // a methodID for the JVM
  if (_debug>1) MFprintf("JClass::getMethods POS2\n");
  if (getAll == JNI_TRUE)
  {
    mid = env->GetMethodID(objClazz,
                         "getMethods",                                        // use method getMethods from class classClz
                         "()[Ljava/lang/reflect/Method;");                    // return = java.lang.reflect.Method[], parameters = none
  } else {
  mid = env->GetMethodID(objClazz,
                         "getDeclaredMethods",                                // use method getDeclaredMethods from class classClz
                         "()[Ljava/lang/reflect/Method;");                    // return = java.lang.reflect.Method[], parameters = none
  }
  if (_debug>1) MFprintf("JClass::getMethods POS3\n");
  env->DeleteLocalRef(objClazz);
  return (jobjectArray) env->CallObjectMethod(clazz, mid, NULL);             // invoke "newClazz" with predefinitions and return result
}

/** getConstructors
  * @param env      The ubiquitous pointer.
  * @param newClazz The class whose constructors are wanted.
  * @param getAll   If true, all superclass methods are also returned.
  * @return         an array contatining Constructor objects.
  */
jobjectArray JClass::getConstructors(JNIEnv* env, jclass newClazz, jboolean getAll) {

  jclass clazz = env->FindClass("java/lang/Class");                             // use class Class for operations
  jclass classClz = env->GetObjectClass(clazz);                                 // get the reference to the class
  jmethodID mid;                                                                // a methodID for the JVM

  if (getAll == JNI_TRUE) {                                                     // If ALL (including superclasses) methods should be returned
    mid = env->GetMethodID(classClz,                                            // use classClz for invokation
                           "getConstructors",                                   // use method getConstructors from class classClz
                           "()[Ljava/lang/reflect/Constructor;");               // return = java.lang.reflect.Constructor[], parameters = none
  } else {                                                                      // only methods declared in this class:
    mid = env->GetMethodID(classClz,                                            // use classClz for invokation
                           "getDeclaredConstructors",                           // use method getDeclaredConstructors from class classClz
                           "()[Ljava/lang/reflect/Constructor;");               // return = java.lang.reflect.Construcor[], parameters = none
  }
  env->DeleteLocalRef(classClz);
  return (jobjectArray) env->CallObjectMethod(newClazz, mid, NULL);             // invoke "newClazz" with predefinitions and return result

}

/** getFields
  * @param env      The ubiquitous pointer.
  * @param newClazz The class whose variables (fields) are wanted.
  * @param getAll   If true, all superclass methods are also returned.
  * @return         an array contatining Field objects.
  */
jobjectArray JClass::getFields(JNIEnv* env, jclass newClazz, jboolean getAll) {
  jclass clazz = env->FindClass("java/lang/Class");                             // use class Class for operations
  jclass classClz = env->GetObjectClass(clazz);                                 // get the reference to the class
  jmethodID mid;                                                                // a methodID for the JVM

  if (getAll == JNI_TRUE) {                                                     // If ALL (including superclasses) methods should be returned
    mid = env->GetMethodID(classClz,                                            // use classClz for invokation
                           "getFields",                                         // use method getFields from class classClz
                           "()[Ljava/lang/reflect/Field;");                     // return = java.lang.reflect.Field[], parameters = none
  } else {                                                                      // only methods declared in this class:
    mid = env->GetMethodID(classClz,                                            // use classClz for invokation
                           "getDeclaredFields",                                 // use method getDeclaredFields from class classClz
                           "()[Ljava/lang/reflect/Field;");                     // return = java.lang.reflect.Field[], parameters = none
  }
  env->DeleteLocalRef(classClz);
  return (jobjectArray) env->CallObjectMethod(newClazz, mid, NULL);             // invoke "newClazz" with predefinitions and return result
}

/** toString (for classes)
  * @param env      The ubiquitous pointer to JNI.
  * @param clazz    The class whose name is wanted
  */
char* JClass::toString(JNIEnv* env, jclass clazz) {
//  jboolean isCopy; // needed, since GetStringUTFChars changes it acordingly

  if (_debug>1) MFprintf("JClass::toString: started...\n");
  jclass classClz = env->GetObjectClass(clazz);                                 // get the reference to the class according to this method
  if (_debug>1) MFprintf("JClass::toString: before creating mid...\n");
  jmethodID mid = env->GetMethodID(classClz,                                    // use classClz for invokation
                                   "toString",                                  // use method toString from class classClz
                                   "()Ljava/lang/String;");                     // return = String, parameters = none
  if (_debug>1) MFprintf("JClass::toString: Before calling object...\n");
  jstring str = (jstring) env->CallObjectMethod(clazz, mid, NULL);
  if (_debug>1) MFprintf("JClass::toString: Before returning object...\n");
  return JHelper::GetNativeChars(env, str); //env->GetStringUTFChars(str, &isCopy);
}

inline char* mystrdup(const char*s) {
  char* ret = (char *) MFcmalloc((strlen(s) * sizeof(char)) + 1);
  sprintf(ret, "%s", s);
  return ret;
}
/** getSignature
  * !!! Due to a BUG or wrongly written API in Java, getName does NOT return the binary code of a class.
  * For arrays it does what it says, but primitive types and classes or interfaces are returned as full qualified names.
  * The correct transformation is done with: <br/>
  * B            byte<br/>
  * C            char<br/>
  * D            double<br/>
  * F            float<br/>
  * I            int<br/>
  * J            long<br/>
  * Lclassname;  class or interface "classname"<br/>
  * S            short<br/>
  * Z            boolean<br/>
  * V	           void<br/>
  * @param env      The ubiquitous pointer to JNI.
  * @param newClazz The class whose methods are wanted.
  * @return         The signature of the class. Example : Ljava/lang/String
  */
char* JClass::getSignature(JNIEnv* env, jclass newClazz) {
  if (_debug>1) MFprintf("JClass::getSignature: started...\n");
  jclass classClz = env->GetObjectClass(newClazz);                              // get the reference to the class according to this method
  jmethodID mid = env->GetMethodID(classClz,                                    // use classClz for invokation
                                   "getName",                                   // use method getName from class classClz
                                   "()Ljava/lang/String;");                     // return = String, parameters = none

  jstring str = (jstring) env->CallObjectMethod(newClazz, mid, NULL);           // invoke "method" with predefinitions

  char *tName = JHelper::GetNativeChars(env, str);
  if (_debug>1) MFprintf("JClass::getSignature: tName = %s\n", tName);
  char *ret;

  /* List:
   B            byte
   C            char
   D            double
   F            float
   I            int
   J            long
   Lclassname;  class or interface "classname"
   S            short
   Z            boolean
   V	          void
  */

  if (strcmp(tName, "byte") == 0) {
    ret = mystrdup("B");
  }
  else if (strcmp(tName, "char") == 0) {
    ret = mystrdup("C");
  }
  else if (strcmp(tName, "double") == 0) {
    ret = mystrdup("D");
  }
  else if (strcmp(tName, "float") == 0) {
    ret = mystrdup("F");
  }
  else if (strcmp(tName, "int") == 0) {
    ret = mystrdup("I");
  }
  else if (strcmp(tName, "long") == 0) {
    ret = mystrdup("J");
  }
  else if (strcmp(tName, "short") == 0) {
    ret = mystrdup("S");
  }
  else if (strcmp(tName, "boolean") == 0) {
    ret = mystrdup("Z");
  }
  else if (strcmp(tName, "void") == 0) {
    ret = mystrdup("V");
  }
  else if (tName[0] != '[') {
    ret = (char *) MFcmalloc(strlen(tName) + 3);
    sprintf(ret, "L%s;", tName);
  } else {
    ret = mystrdup((const char*)tName);
  }

  // Now exchange all . to / ...
  //char *p = tName;
  int pLen = strlen(tName);
  for (int i=0;i<pLen;i++) {
    if (ret[i] == '.')
      ret[i] = '/';
  }
  MFcfree(tName);
  if (_debug>1) MFprintf("JClass::getSignature: ret = %s\n", ret);
  return ret;
}

// --------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------

/** JMethod : reflection support for methods
  *
  * JMethod::getParameterTypes
  * JMethod::getReturnType
  * JMethod::getSignature
  * JMethod::toString
  * JMethod::getName
  * JMethod::callMethod
  */

/** getParameterTypes
  * @param env    The ubiquitous pointer to JNI.
  * @param method The method whose parameters are wanted.
  * @return       Returns an array of Class objects that represent the formal parameter types,
                  in declaration order, of the method represented by this Method object.
  */
jobjectArray JMethod::getParameterTypes(JNIEnv* env, jobject method) {
  jclass clazz = env->GetObjectClass(method);                                   // get the reference to the class according to this method

  jmethodID mid = env->GetMethodID(clazz,                                       // get the reference to clazz
                                   "getParameterTypes",                         // use method getParameterTypes
                                   "()[Ljava/lang/Class;");                     // return = class[], parameters = none

  return (jobjectArray) env->CallObjectMethod(method, mid, NULL);               // invoke "method" with predefinitions and return result
}

/** getSpecialParameter
  * @param env    The ubiquitous pointer to JNI.
  * @param method The method whose parameters class at position position is wanted.
  * @return       Returns the class belonging to the method at position <code>position</code>.
  */
jclass JMethod::getSpecialParameter(JNIEnv* env, jobject method, jint position) {
  jobjectArray methodParams = JMethod::getParameterTypes(env, method);          // get the classes of all parameters.
  return (jclass) env->GetObjectArrayElement(methodParams, position);           // and return the parameters class on position position
}

/** getParameterNumber
  * @param env    The ubiquitous pointer to JNI.
  * @param method The method whose parameters are wanted.
  * @return       Returns the number of parameters for this method.
  */
jint JMethod::getParameterNumber(JNIEnv* env, jobject method) {
  jobjectArray joA = JMethod::getParameterTypes(env, method);
  return (jint) env->GetArrayLength(joA);
}


/** getReturnType
  * Returns the complete return type of the method.<br/>
  * Example : java/lang/String.
  * @param  env    The ubiquitous pointer to JNI.
  * @param  method The method/constructor/field whose complete description is wanted
  * @return        The class of the return type
  */
jclass JMethod::getReturnType(JNIEnv* env, jobject method) {
  jclass clazz = env->GetObjectClass(method);                                   // get the reference to the class according to this method
  jmethodID mid = env->GetMethodID(clazz,                                       // get the reference to clazz
                                   "getReturnType",                             // use method getReturnType
                                   "()Ljava/lang/Class;");                      // return = String, parameters = none
  return (jclass) env->CallObjectMethod(method, mid, NULL);                     // return the class object
}


/** getSignature
  * @param env       The ubiquitous pointer to JNI.
  * @param method    The method whose signature is wanted.
  * @param typeIndex The calculated number of all the parameters (kind of a checksum)
  * @return          The signature of the method. Example : ()V
  */

char* JMethod::getSignature(JNIEnv* env, jobject method, jint* typeIndex) {

  jclass classClz = env->GetObjectClass(method);                                // get the reference to the class according to this method
  int strCnt = 0;                                                               // for checking the available memory
  int reAllocCnt = 2;                                                           // if memory proves to be too small double it at first.
  jint index=0;                                                                 // for later use to easily decide which method to invoke

  jobjectArray parameterArray = JMethod::getParameterTypes(env, method);        // Store the array of available fields
  int nParameters = env->GetArrayLength(parameterArray);                        // Get the number of elements

  if (_debug>1) MFprintf("JMethod::getSignature: started...\n");
  if (_debug>1) MFprintf("JMethod::getSignature: nParameters = %d\n", nParameters);

  // Create the paramters for the signature. Example [Ljava/lang/String;ZI
  jclass singleClass;
  char *cName;
  char* typeSig = (char*) MFcmalloc(sizeof(char) * 128);
  char *dummyChar;

  if (typeSig == NULL) return NULL;                                             // already no memory ?
  strcpy(typeSig, "(");                                                         // first character of typesig

  for (int i = 0;i < nParameters; i++) {                                        // As long as classes exist in array
    singleClass = (jclass) env->GetObjectArrayElement(parameterArray, i);       // retrieve the i-th element from parameterArray
    cName = JClass::getSignature(env, singleClass);                             // get the signature of the class
    if (_debug>1) MFprintf("JMethod::getSignature: got from JClass::getSignature: '%s'\n", cName);
    strCnt += strlen(cName);                                                    // enough memory reserved?

    if (strCnt > (reAllocCnt-1) * 128) { // no, then double it...
      if (_debug>1) MFprintf("JMethod::getSignature: have to allocate more memory (1)...\n");
      dummyChar = (char*) MFcmalloc(reAllocCnt * 128 * sizeof(char));
      if (dummyChar == NULL) {                                                    // Not enough left, ERROR !!!
        return NULL;
      }
      strcpy(dummyChar, typeSig);
      MFcfree(typeSig);
      if (dummyChar == NULL) {                                                    // Not enough left, ERROR !!!
        return NULL;
      }
      typeSig = dummyChar;
      reAllocCnt++;
    }
    strcat(typeSig, cName);                                                     // add the signature to typeSig.
    MFcfree(cName);
  }

  env->DeleteLocalRef(parameterArray);
  strcat(typeSig, ")");                                                         // add a closing bracket to parameters
  strCnt ++;                                                                    // and increase strCnt by one.
  if (_debug>1) MFprintf("JMethod::getSignature: typeSig is now: '%s'\n", typeSig);
  // Now the parameters are all set up. The return parameter is still missing though.

  if (isConstructor == JNI_TRUE)
  {
    if (_debug>1) MFprintf("JMethod::getSignature: constructor\n");
    cName = mystrdup("V");
  }
  else {
    singleClass = JMethod::getReturnType(env, method);                            // get the Return type of the method
    cName = JClass::getSignature(env, singleClass);                               // get the signature of the class
    env->DeleteLocalRef(singleClass);
  }

  int lencName = strlen(cName);

  strCnt += strlen(cName);                                                      // enough memory reserved?

  if (strCnt > (reAllocCnt-1) * 128) {                                          // no, then double it...
    if (_debug>1) MFprintf("JMethod::getSignature: have to allocate more memory (2)...\n");
    dummyChar = (char*) MFcmalloc(reAllocCnt * 128 * sizeof(char));
    if (dummyChar == NULL) {                                                    // Not enough left, ERROR !!!
      return NULL;
    }
    strcpy(dummyChar, typeSig);
    MFcfree(typeSig);
    if (dummyChar == NULL) {                                                    // Not enough left, ERROR !!!
      return NULL;
    }
    typeSig = dummyChar;
    reAllocCnt++;
  }
  strcat(typeSig, cName);                                                       // add the signature to typeSig.

  if (_debug>1) MFprintf("JMethod::getSignature: typeSig is now: '%s'\n", typeSig);

  const char *p = cName;
  // This has to be given a second or third thought !
  // By now the array is just run through to check the parameters of the return value
  // Multidimensional arrays like in C/C++ are not allowed. They have to be of ONE Type !
  // They itself can contain again other types (kind of a nested structure)
  if (_debug>1) MFprintf("JMethod::getSignature: index = %d\n", index);
  if (typeIndex) {                                                              // only if typeIndex was set
    while (*cName != '\0') {
      switch (*cName++) {
        case '[' : index = index + JAVA_ARRAY; break;                           // If return type is an array, it will be greater than 10!
        case 'Z' : index+=JAVA_BOOLEAN; break;                                  // boolean
        case 'C' : index+=JAVA_CHAR; break;                                     // char
        case 'B' : index+=JAVA_BYTE; break;                                     // byte
        case 'S' : index+=JAVA_SHORT; break;                                    // short
        case 'I' : index = index + JAVA_INT; break;                             // int
        case 'J' : index+=JAVA_LONG; break;                                     // long
        case 'F' : index+=JAVA_FLOAT; break;                                    // float
        case 'D' : index+=JAVA_DOUBLE; break;                                   // double
        case 'V' : index+=JAVA_VOID; break;                                     // void
        case 'L' : if (strncmp(cName, "java/lang/String", 16) == 0) {
                     if (_debug>1) MFprintf("JMethod::getSignature : Jup, it's a String...\n");
                     index += JAVA_STRING;                                      // String
                   } else if (strncmp(cName, "java/math/BigInteger", 20) == 0) {
                     if (_debug>1) MFprintf("JMethod::getSignature : Jup, it's a BigInteger...\n");
                     index += JAVA_BIGINTEGER;                                  // BigInteger
                   } else if (strncmp(cName, "java/math/BigDecimal", 20) == 0) {
                     if (_debug>1) MFprintf("JMethod::getSignature : Jup, it's a BigDecimal...\n");
                     index += JAVA_BIGDECIMAL;                                  // BigDecimal
                   } else {
                     if (_debug>1) MFprintf("JMethod::getSignature : It's something unknown...\n");
                     index += JAVA_UNKNOWN;
                   }
                   while (*cName++ != ';') {}
                   break;                                                       // It is something like Ljava/...;
      }
    }
    if (typeIndex != NULL) {
      *typeIndex = index;                                                         // assign new value
      if (_debug>1) MFprintf("JMethod::getSignature: typeIndex = %d\n", *typeIndex);
    }
  }

  MFcfree(p);
  if (_debug>1) MFprintf("JMethod::getSignature: typeSig = %s\n", typeSig);
  return typeSig;
}

/** toString (for jobject)
  * @param env    The ubiquitous pointer to JNI.
  * @param method The method/constructor/field whose complete description is wanted
  * @return       a UTF String describing the method.
  */
char* JMethod::toString(JNIEnv* env, jobject method) {
  jclass clazz = env->GetObjectClass(method);                                   // get the reference to the class according to this method

  jmethodID mid = env->GetMethodID(clazz,                                       // get the reference to clazz
                                   "toString",                                  // use method toString
                                   "()Ljava/lang/String;");                     // return = String, parameters = none

  jstring str = (jstring) env->CallObjectMethod(method, mid, NULL);            // invoke "method" with predefinitions
  return JHelper::GetNativeChars(env, str);
}




/** getName
  * simmilar to toString, but returns only the method name and the paramters without all the other declarations.<br/>
  * Example : toString(int).
  * @param env    The ubiquitous pointer to JNI.
  * @param method The method/constructor/field whose complete description is wanted.
  * @return       a UTF string containing the name of the method.
  */
char* JMethod::getName(JNIEnv* env, jobject method) {
  //if (_debug>1) MFprintf("JMethod::getName : started\n");

  jclass objClazz = env->GetObjectClass(method);                                   // get the reference to the class according to this method
  jmethodID mid = env->GetMethodID(objClazz,                                       // get the reference to clazz
                                   "getName",                                   // use method getName
                                   "()Ljava/lang/String;");                     // return = String, parameters = none

  jstring name = (jstring) env->CallObjectMethod(method, mid, NULL);            // invoke "method" with predefinitions
  //if (_debug>1) MFprintf("JMethod::getName : before GetNativeChars.\n");

  char *buf = JHelper::GetNativeChars(env, name);
  //if (_debug>1) MFprintf("JMethod::getName : name is '%s'\n", buf);
  return buf;
}

/** getModifiers
  * Returns the Java language modifiers for the method represented by this Method object, as an integer.<br/>
  * Decoding is best done with the Modifier class from Java.
  * @param env    The ubiquitous pointer to JNI.
  * @param method The method/constructor/field whose complete description is wanted
  * @return       The integer code of the modifier.
  */
jint JMethod::getModifiers(JNIEnv* env, jobject method) {
  if (_debug>1) MFprintf("JMethod::getModifiers : started.\n");
  jclass clazz = env->GetObjectClass(method);                                   // get the reference to the class according to this method
  if (_debug>1) MFprintf("JMethod::getModifiers : got the Object class.\n");
  jmethodID mid = env->GetMethodID(clazz,                                       // get the reference to clazz
                                   "getModifiers",                              // use method getModifiers
                                   "()I");                                      // return = Integer, parameters = none
  if (_debug>1) MFprintf("JMethod::getModifiers : got the method ID.\n");
  return (jint) env->CallIntMethod(method, mid, NULL);                          // return the modifier code
}

/** isaNumber
  * checks if toTest is an instance of the Number class.
  * @param env    The ubiquitous pointer to JNI.
  * @param toTest The jobject that is tested.
  * @return       JNI_TRUE if it derives from class Number, JNI_FALSE if not.
  */
jboolean JMethod::isaNumber(JNIEnv* env, jobject toTest) {
  jclass nClass = env->FindClass("java/lang/Number");                           // use class Number for operations
  return env->IsInstanceOf(toTest, nClass);
}

// --------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------

/** JModifier : reflection support for the modifiers of classes/methods
  *
  * JModifier::isStatic
  */

/** isStatic
  * Returns true if the class/method is static, false if not.<br/>
  * @param  env The ubiquitous pointer to JNI.
  * @param  mod The number of the modifier.
  * @return     true if the method is static, false otherwise.
  */
jboolean JModifier::isStatic(JNIEnv* env, jint mods) {
  if (_debug>1) MFprintf("JHelper::isStatic : started.\n");
  jclass clazz = env->FindClass("java/lang/reflect/Modifier");                  // get the reference to the class according to this method
  jmethodID mid = env->GetStaticMethodID(clazz,                                 // get the reference to clazz
                                         "isStatic",                            // use method isStatic
                                         "(I)Z");                               // return = boolean, parameters = (Integer)
  return env->CallStaticBooleanMethod(clazz, mid, mods);                        // return true/false
}

/** isPublic
  * Returns true if the class/method is public, false if not.<br/>
  * @param  env The ubiquitous pointer to JNI.
  * @param  mod The number of the modifier.
  * @return     true if the method is static, false otherwise.
  */
jboolean JModifier::isPublic(JNIEnv* env, jint mods) {
  jclass clazz = env->FindClass("java/lang/reflect/Modifier");                  // get the reference to the class according to this method
  jmethodID mid = env->GetStaticMethodID(clazz,                                 // get the reference to clazz
                                         "isPublic",                            // use method isPublic
                                         "(I)Z");                               // return = boolean, parameters = (Integer)
  return env->CallStaticBooleanMethod(clazz, mid, mods);                        // return true/false
}


/** isProtected
  * Returns true if the class/method is protected, false if not.<br/>
  * @param  env The ubiquitous pointer to JNI.
  * @param  mod The number of the modifier.
  * @return     true if the method is static, false otherwise.
  */
jboolean JModifier::isProtected(JNIEnv* env, jint mods) {
  jclass clazz = env->FindClass("java/lang/reflect/Modifier");                  // get the reference to the class according to this method
  jmethodID mid = env->GetStaticMethodID(clazz,                                 // get the reference to clazz
                                         "isProtected",                         // use method isProtected
                                         "(I)Z");                               // return = boolean, parameters = (Integer)
  return env->CallStaticBooleanMethod(clazz, mid, mods);                        // return true/false
}

/** isPrivate
  * Returns true if the class/method is private, false if not.<br/>
  * @param  env The ubiquitous pointer to JNI.
  * @param  mod The number of the modifier.
  * @return     true if the method is static, false otherwise.
  */
jboolean JModifier::isPrivate(JNIEnv* env, jint mods) {
  jclass clazz = env->FindClass("java/lang/reflect/Modifier");                  // get the reference to the class according to this method
  jmethodID mid = env->GetStaticMethodID(clazz,                                 // get the reference to clazz
                                         "isPrivate",                           // use method isPrivate
                                         "(I)Z");                               // return = boolean, parameters = (Integer)
  return env->CallStaticBooleanMethod(clazz, mid, mods);                        // return true/false
}

/** matchModifier
  * Returns true if the  is static, false if not.<br/>
  * @param  env   The ubiquitous pointer to JNI.
  * @param  mod   The number of the modifier.
  * @param  check The number to be matched (1=public, 2=protected, 3=private).
  * @return     true if the method is static, false otherwise.
  */
jboolean JModifier::matchModifier(JNIEnv* env, jint mods, jint check) {

  switch (check) {
    case 1: if (JModifier::isPublic(env, mods) == JNI_TRUE) {
              return JNI_TRUE;
            }
            break;
    case 2: if (JModifier::isProtected(env, mods) == JNI_TRUE) {
              return JNI_TRUE;
            }
            if (JModifier::isPublic(env, mods) == JNI_TRUE) {
              return JNI_TRUE;
            }
            break;
    case 4: return JNI_TRUE;                                                    // private contains everything.
            break;
  }
  // If it comes this far, it has to be false.
  return JNI_FALSE;
}



// --------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------

/** JHelper : some functions neccessary to convert and being generally helpful
  *
  * JHelper::long2text
  * JHelper::matchMethods
  */

/** long2text
  * converts a jlong number (64bit) into a string.<br/>
  * @param  env       The ubiquitous pointer to JNI.
  * @param  toConvert The 64bit number.
  * @return           The char array representing the number.
  */

char* JHelper::jlong2text(JNIEnv* env, jlong toConvert) {
  jclass hClass = env->FindClass("java/lang/Long");                             // use class Long for operations

  jmethodID mid = env->GetStaticMethodID(hClass,                                // use hClass for invokation
                                         "toString",                            // use method listClasses from class Long
                                         "(J)Ljava/lang/String;");              // return = String, parameters = (long)
  jstring str = (jstring)env->CallStaticObjectMethod(hClass,                 // invoke the method
                                                        mid,                    // listClasses
                                                        toConvert);             // with the jlong argument
  if (env->ExceptionOccurred()) {                                               // If an exception occurred
     env->ExceptionDescribe();                                                  // print it
     if (showErrors == JNI_TRUE) MFprintf("Error: Method jlong2text threw an exception.");
     return(NULL);                                                              // return a failure
  }
  env->DeleteLocalRef(hClass);
  return JHelper::GetNativeChars(env, str);
}

/** text2long
  * converts a string to a jlong number (64bit).<br/>
  * @param  env       The ubiquitous pointer to JNI.
  * @param  toConvert The 64bit number.
  * @return           The char array representing the number.
  */

jlong JHelper::text2jlong(JNIEnv* env, char* toConvert) {
  jlong result;
  jclass hClass = env->FindClass("java/lang/Long");                             // use class Long for operations
  jmethodID mid = env->GetStaticMethodID(hClass,                                // use hClass for invokation
                                         "parseLong",                           // use method parseLong from class Long
                                         "(Ljava/lang/String;)J");              // return = String, parameters = (long)
  jstring argument = JSystem::NewPlatformString(env, toConvert);
  result = env->CallStaticLongMethod(hClass, mid, argument);                    // return the converted long (64bit!)
  env->DeleteLocalRef(hClass);
  return result;
}

/** object2text
  * converts an arbitrary object into a string. The object MUST have a toString method.<br/>
  * @param  env       The ubiquitous pointer to JNI.
  * @param  toConvert The object.
  * @return           The char array representing the number.
  */

char* JHelper::object2text(JNIEnv* env, jobject toConvert) {
  jclass oClass = env->GetObjectClass(toConvert);
  jmethodID mid = env->GetMethodID(oClass,                                      // use oClass for invokation
                                   "toString",                                  // use method listClasses from class Long
                                   "()Ljava/lang/String;");                     // return = String, parameters = none
  jstring str = (jstring)env->CallObjectMethod(toConvert,                    // invoke the method
                                                  mid,                          // the object
                                                  NULL);                        // with no argument
  if (env->ExceptionOccurred()) {                                               // If an exception occurred
     env->ExceptionDescribe();                                                  // print it
      if (showErrors == JNI_TRUE) MFprintf("Error: Method object2text threw an exception.");
     return(NULL);                                                              // return a failure
  }
  env->DeleteLocalRef(oClass);
  return JHelper::GetNativeChars(env, str);
}

/** text2object
  * converts a string to a object number (only limited by memory).<br/>
  * @param  env       The ubiquitous pointer to JNI.
  * @param  toConvert The 64bit number.
  * @param  className The signature name of the class without L and the added ; (Example : Ljava/lang/String; = java/lang/String)
  * @return           The instanciated object.
  */

jobject JHelper::text2object(JNIEnv* env, char* toConvert, char* className) {
  //MFprintf("JHelper::text2object was started...\n");
  jobject result;
  jclass hClass = env->FindClass(className);                                    // use class className for operations
  //MFprintf("JHelper::text2object after loading class.\n");
  jmethodID mid = env->GetMethodID(hClass,                                      // use hClass for invokation
                                   "<init>",                                    // since it is a constructor, it has to be created.
                                   "(Ljava/lang/String;)V");                    // return = void (constructor), parameters = (String)
  //MFprintf("JHelper::text2object after creating mid.\n");
  jstring argument = JSystem::NewPlatformString(env, toConvert);
  //MFprintf("JHelper::text2object after creating argument.\n");

  result = env->NewObject(hClass, mid, argument);                                 // create a new object object
  env->DeleteLocalRef(hClass);
  return result;
}

/** hasNativeMethod
 * finds out whether the method 'calcMuPAD' is contained in mclass or not.
 * @param mClass The class to be searched
 * @return JNI_TRUE if it contains the method 'calcMuPAD(String)'
 *         JNI_FALSE if not.
 */
jboolean JHelper::hasNativeMethod(JNIEnv*  env, jclass mClass) {
  char *tmpChar1;
  char *tmpChar2;
  if (_debug>1) MFprintf("JHelper::hasNativeMethod : started.\n");
  jobjectArray classMethods = JClass::getMethods(env, mClass, JNI_TRUE);        // all available public methods of the class.
  // If it has no methods at all... ?
  if (classMethods == NULL)
  {
    return JNI_FALSE;
  }
  int nMethods = env->GetArrayLength(classMethods);                             // get the number of declared methods
  for (jint j=0; j < nMethods; j++) {
    jobject method = env->GetObjectArrayElement(classMethods, j);               // store the j'th class in method.
    tmpChar1 = JMethod::getName(env, method);
    if (strcmp(tmpChar1, "calcMuPAD") == 0) {
      if (_debug>1) MFprintf("JHelper::hasNativeMethod : POS3 loop %d\n", j);
      tmpChar2 = JMethod::getSignature(env, method, NULL);
      if (strcmp(tmpChar2, "(Ljava/lang/String;)Ljava/lang/String;") == 0) {
        if (_debug>1) MFprintf("JHelper::hasNativeMethod : found the Method calcMuPAD\n");
        env->DeleteLocalRef(classMethods);
        return JNI_TRUE;
      }
      MFcfree(tmpChar2);
    }
    MFcfree(tmpChar1);
    env->DeleteLocalRef(method);
  }
  env->DeleteLocalRef(classMethods);
  if (_debug>1) MFprintf("JHelper::hasNativeMethod : Method calcMuPAD not available in class.\n");
  return JNI_FALSE;
}

/** matchMethod - new
  * tries to find a Java-matching for an invokation from the MuPAD-side.<br/>
  * @param env        The ubiquitous pointer to JNI.
  * @param javaParam  A pointer to the java class of the object.
  * @param mupParam   A pointer to a MuPAD array containing possible matches.
  * @param index      The value of the signature.
  * @param jindex     The defined value of the data type.
  * @return           JNI_TRUE if a match is possible, JNI_FALSE else.
  */
jboolean JHelper::matchMethod(JNIEnv* env, jclass javaParam, MTcell theMupadParam, MTcell mupParam, jint *index, jint *jindex) {
  // Find out the type of the parameter
  char *signature = JClass::getSignature(env, javaParam);                       // and get the signature
  if (_debug>1) MFprintf("JHelper::matchMethod : Signature = '%s'\n", signature);
  if (_debug>1) MFprintf("JHelper::matchMethod : Parameter = ");
  if (_debug>1) MFout( mupParam );
  if (_debug>1) MFprintf("JHelper::matchMethod : Type = %s\n", MFexpr2text(MFtype(mupParam)));
  jboolean foundType = JNI_FALSE;

  *index = 0;
  while (*signature == '[') {
    if (_debug>1) MFprintf("JHelper::matchMethod : signature is now %s\n", signature);
    *signature++;                                                             // one char further right
    *index+=JAVA_ARRAY;                                                       // index = index + 100
    *jindex+=VALUE_ARRAY;
    if (_debug>1) MFprintf("JHelper::matchMethod : index is now %d\n", *index);
      // Since java does not allow different types inside of arrays [[1,2],[2,"Hallo"]]
      // it is okay to take the first element out of the list.
  }

  if (_debug>1) MFprintf("JHelper::matchMethod : Before long loop.\n");
  if (_debug>1) MFprintf("JHelper::matchMethod : Signature = %s.\n", signature);
  if (_debug>1) MFprintf("JHelper::matchMethod : index = %d.\n", *index);
  if (_debug>1) MFprintf("JHelper::matchMethod : nops = %d.\n", MFnopsList(mupParam));
  for (long j=0; j < MFnopsList(mupParam); j++)
  {
    if (_debug>1) MFprintf("JHelper::matchMethod : The j'ts parameter in list has value %d.\n", MFint(MFgetList(&mupParam, j)));
    if (_debug>1) MFprintf("JHelper::matchMethod : *index is %d.\n", *index);
    // Byte
    if ((*signature == 'B') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BYTE)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a byte.\n");
      *index += JAVA_BYTE;
      *jindex+=VALUE_BYTE;
      return JNI_TRUE;
    } else
    if ((*signature == 'S') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_SHORT)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a short.\n");
      *index += JAVA_SHORT;
      *jindex+=VALUE_SHORT;
      return JNI_TRUE;
    } else
    if ((*signature == 'I') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_INT)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be an int.\n");
      *index += JAVA_INT;
      *jindex+=VALUE_INT;
      return JNI_TRUE;
    } else
    if ((*signature == 'J') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_LONG)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a long.\n");
      *index += JAVA_LONG;
      *jindex+=VALUE_LONG;
      return JNI_TRUE;
    } else
    if ((*signature == 'F') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_FLOAT)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a float.\n");
      *index += JAVA_FLOAT;
      *jindex+=VALUE_FLOAT;
      return JNI_TRUE;
    } else
    if ((*signature == 'D') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_DOUBLE)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a double.\n");
      *index += JAVA_DOUBLE;
      *jindex+=VALUE_DOUBLE;
      return JNI_TRUE;
    } else
    if ((*signature == 'Z') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BOOLEAN)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a boolean.\n");
      *index += JAVA_BOOLEAN;
      *jindex+=VALUE_BOOLEAN;
      return JNI_TRUE;
    } else
    if ((*signature == 'C') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_CHAR)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a char.\n");
      *index += JAVA_CHAR;
      *jindex+=VALUE_CHAR;
      return JNI_TRUE;
    } else
    if ((strcmp("Ljava/lang/String;", signature) == 0) && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_STRING)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a string.\n");
      *index += JAVA_STRING;
      *jindex+=VALUE_STRING;
      return JNI_TRUE;
    } else
    if ((strcmp("Ljava/math/BigInteger;", signature) == 0) && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BIGINTEGER)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a biginteger.\n");
      *index += JAVA_BIGINTEGER;
      *jindex+=VALUE_BIGINTEGER;
      return JNI_TRUE;
    } else
    if ((strcmp("Ljava/math/BigDecimal;", signature) == 0) && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BIGDECIMAL)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a bigdecimal.\n");
      *index += JAVA_BIGDECIMAL;
      *jindex+=VALUE_BIGDECIMAL;
      return JNI_TRUE;
    } else
    if ((strncmp("L", signature,1) == 0)) {
      if (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_OBJECT))
      {
        if (_debug>1) MFprintf("JHelper::matchMethod : Is a known java object (so far only @NULL).\n");
        *index += JAVA_OBJECT;
        *jindex+=VALUE_OBJECT;
        return JNI_TRUE;
      } else
      if (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_UNKNOWN))
      {
        // theMupadParam has to be of type string (otherwise it could not be of type JAVA_UNKNOWN)!
        jobject storedObj = JSystem::HO_getObject(env, MFstring(theMupadParam));
        if (storedObj != NULL)
        {
          if ( env->IsInstanceOf(storedObj, javaParam) )
          {
            if (_debug > 0) MFprintf("The stated object can by typecasted to the parameter.\n");
            *index += JAVA_UNKNOWN;
            *jindex+=VALUE_UNKNOWN;
            return JNI_TRUE;
          }
          else {
            char *theObject = JClass::toString(env, javaParam);
            char *wrongObject = JClass::toString(env, env->GetObjectClass(storedObj));
            MFprintf("The stated object (%s) is no instance of (%s).\n", wrongObject, theObject);
            MFcfree(theObject);
            MFcfree(wrongObject);
          }
        }
      }
    } /* else
    if ((strcmp("Ljava/lang/Object;",signature) == 0))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : It is a java/lang/object.\n");
      if (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_OBJECT))
        {
        // Here a change could allow all objects to enter, since every data type has derived from it.
        if (_debug>1) MFprintf("JHelper::matchMethod : Is a known java object (so far only @NULL).\n");
        *index += JAVA_OBJECT;
        *jindex+=VALUE_OBJECT;
        return JNI_TRUE;
      } else if (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_UNKNOWN))
      {
        // Every object is an instance of java/lang/object
        *index += JAVA_UNKNOWN;
        *jindex+=VALUE_UNKNOWN;
        return JNI_TRUE;
      }
    } else */
  }

  // signature does not match to any parameter in list.
  return JNI_FALSE;
}

/** matchMethod - old
  * tries to find a Java-matching for an invokation from the MuPAD-side.<br/>
  * @param env        The ubiquitous pointer to JNI.
  * @param signature  The signature of the class.
  * @param mupParam   A pointer to a MuPAD array containing possible matches.
  * @param index      The value of the signature.
  * @param jindex     The defined value of the data type.
  * @return           JNI_TRUE if a match is possible, JNI_FALSE else.
  */
/*
jboolean JHelper::matchMethod(JNIEnv* env, char *signature, MTcell mupParam, jint *index, jint *jindex) {
  // Find out the type of the parameter
  if (_debug>1) MFprintf("JHelper::matchMethod : Signature = '%s'\n", signature);
  if (_debug>1) MFprintf("JHelper::matchMethod : Parameter = ");
  if (_debug>1) MFout( mupParam );
  if (_debug>1) MFprintf("JHelper::matchMethod : Type = %s\n", MFexpr2text(MFtype(mupParam)));
  jboolean foundType = JNI_FALSE;

  *index = 0;
  while (*signature == '[') {
    if (_debug>1) MFprintf("JHelper::matchMethod : signature is now %s\n", signature);
    *signature++;                                                             // one char further right
    *index+=JAVA_ARRAY;                                                       // index = index + 100
    *jindex+=VALUE_ARRAY;
    if (_debug>1) MFprintf("JHelper::matchMethod : index is now %d\n", *index);
      // Since java does not allow different types inside of arrays [[1,2],[2,"Hallo"]]
      // it is okay to take the first element out of the list.
  }

  if (_debug>1) MFprintf("JHelper::matchMethod : Before long loop.\n");
  if (_debug>1) MFprintf("JHelper::matchMethod : nops = %d.\n", MFnopsList(mupParam));
  for (long j=0; j < MFnopsList(mupParam); j++)
  {
    if (_debug>1) MFprintf("JHelper::matchMethod : The j'ts parameter in list has value %d.\n", MFint(MFgetList(&mupParam, j)));
    if (_debug>1) MFprintf("JHelper::matchMethod : *index is %d.\n", *index);
    // Byte
    if ((*signature == 'B') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BYTE)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a byte.\n");
      *index += JAVA_BYTE;
      *jindex+=VALUE_BYTE;
      return JNI_TRUE;
    } else
    if ((*signature == 'S') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_SHORT)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a short.\n");
      *index += JAVA_SHORT;
      *jindex+=VALUE_SHORT;
      return JNI_TRUE;
    } else
    if ((*signature == 'I') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_INT)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be an int.\n");
      *index += JAVA_INT;
      *jindex+=VALUE_INT;
      return JNI_TRUE;
    } else
    if ((*signature == 'J') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_LONG)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a long.\n");
      *index += JAVA_LONG;
      *jindex+=VALUE_LONG;
      return JNI_TRUE;
    } else
    if ((strcmp("Ljava/math/BigInteger;",signature) == 0) && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BIGINTEGER)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a biginteger.\n");
      *index += JAVA_BIGINTEGER;
      *jindex+=VALUE_BIGINTEGER;
      return JNI_TRUE;
    } else
    if ((strcmp("Ljava/math/BigDecimal;",signature) == 0) && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BIGDECIMAL)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a bigdecimal.\n");
      *index += JAVA_BIGDECIMAL;
      *jindex+=VALUE_BIGDECIMAL;
      return JNI_TRUE;
    } else
    if ((strcmp("Ljava/lang/Object;",signature) == 0))
    {
      if (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_OBJECT))
        {
        // Here a change could allow all objects to enter, since every data type has derived from it.
        if (_debug>1) MFprintf("JHelper::matchMethod : Is a known java object (so far only @NULL).\n");
        *index += JAVA_OBJECT;
        *jindex+=VALUE_OBJECT;
        return JNI_TRUE;
      } else if (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_UNKNOWN))
      {
        if (_debug>1) MFprintf("JHelper::matchMethod : Is an unknown java object (MuPAD_JNI_xxxxxxxx).\n");
        *index += JAVA_UNKNOWN;
        *jindex+=VALUE_UNKNOWN;
        return JNI_TRUE;
      }
    } else
    if ((*signature == 'F') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_FLOAT)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a float.\n");
      *index += JAVA_FLOAT;
      *jindex+=VALUE_FLOAT;
      return JNI_TRUE;
    } else
    if ((*signature == 'D') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_DOUBLE)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a double.\n");
      *index += JAVA_DOUBLE;
      *jindex+=VALUE_DOUBLE;
      return JNI_TRUE;
    } else
    if ((*signature == 'Z') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_BOOLEAN)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a boolean.\n");
      *index += JAVA_BOOLEAN;
      *jindex+=VALUE_BOOLEAN;
      return JNI_TRUE;
    } else
    if ((*signature == 'C') && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_CHAR)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a char.\n");
      *index += JAVA_CHAR;
      *jindex+=VALUE_CHAR;
      return JNI_TRUE;
    } else
    if ((strcmp("Ljava/lang/String;", signature) == 0) && (MFint(MFgetList(&mupParam, j)) == (*index + JAVA_STRING)))
    {
      if (_debug>1) MFprintf("JHelper::matchMethod : Could be a string.\n");
      *index += JAVA_STRING;
      *jindex+=VALUE_STRING;
      return JNI_TRUE;
    }
  }
  // signature does not match to any parameter in list.
  return JNI_FALSE;
}
*/

/** createSingleJNIArray
 * make sure to call this procedure with the right index, since otherwise
 * the invokation of the chosen match (depending on max/min/native...) will
 * not work.
 * @param env         The ubiquitous pointer to JNI.
 * @param mupadArray   A pointer to a MuPAD array.
 * @param index        The calculated index for the parameter or return value.
 * @param currentArray A pointer to a jobjectArray. Memory will be appointed to currentArray and must be freed later !
 */
jboolean JHelper::createSingleJNIArray(JNIEnv* env, MTcell mupadArray, jint index, jobjectArray *currentArray) {

  int i;
  int arrayNumber = MFnops(mupadArray);
  if (_debug>2) MFprintf("JHelper::createSingleJNIArray : index is now %d\n", index);


  if (index - JAVA_ARRAY > 0) {
    index -= JAVA_ARRAY;                                                        // take the next step
  } else
    return JNI_FALSE;                                                           // No array !!!

  if (_debug>2) MFprintf("JHelper::createSingleJNIArray : with (last) arrayNumber %d and index %d\n", arrayNumber, index);
  if (_debug>2) MFprintf("The elements in this array are:\n");
  for (i=0;i<arrayNumber;i++) {
    if (_debug>2) MFprintf("Number %d = %d\n", i, MFexpr2text(MFop(mupadArray, i)));
  }
  /*
   Now the elements are put into the created object according to the signature.
   Z            boolean
   B            byte
   C            char
   D            double
   F            float
   I            int
   J            long
   Lclassname;  class or interface "classname"
   S            short
   V           void
   */

  if (_debug>2) MFprintf("JHelper::createSingleJNIArray : primitive data type with arrayNumber %d and index %d\n", arrayNumber, index);

  jclass tClass;
  jobject basicElement;
  jmethodID mid;

  if (index == JAVA_BOOLEAN) {
/*
   // This approach does not work !!!
   MFprintf("createSingleJNIArray: In JAVA_BOOLEAN with arrayNumber = %d\n", arrayNumber);
   tClass = env->FindClass("Ljava/lang/Boolean;");
   if (tClass == NULL) {
    MFprintf("Could not find tClass or not enough memory left...\n");
    return JNI_FALSE;
   }

   *currentArray = env->NewObjectArray(arrayNumber, tClass, NULL);
   for (i=0;i<arrayNumber;i++) {
     MFprintf("createSingleJNIArray: Before setting array position %d\n",i);
     // Here is, where it crashes:
     env->SetObjectArrayElement(*currentArray, i, (jobject)(jboolean)(MFbool(MFop(mupadArray,i))));
     MFprintf("createSingleJNIArray: After setting array position %d\n",i);
   }
   MFprintf("createSingleJNIArray: After freeing memory\n");
*/
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_BOOLEAN with arrayNumber = %d\n", arrayNumber);
   jbooleanArray booleanArray = env->NewBooleanArray(arrayNumber);
   jboolean* p = (jboolean*) MFcmalloc(arrayNumber* sizeof(jboolean));
   if (p == NULL) {
     if (_debug>2) MFprintf("JHelper::createSingleJNIArray : No more memory...");
     return JNI_FALSE;
   }
   for (i=0;i<arrayNumber;i++) {
     p[i] = (jboolean)MFbool(MFop(mupadArray,i));
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %d\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetBooleanArrayRegion(booleanArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)booleanArray;

   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");
  } else if (index == JAVA_CHAR) {
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_CHAR with arrayNumber = %d\n", arrayNumber);

   jcharArray charArray = env->NewCharArray(arrayNumber);
   jchar* p = (jchar*) MFcmalloc(arrayNumber* sizeof(jchar));
   for (i=0;i<arrayNumber;i++) {
     p[i] = (jchar) MFstring(MFop(mupadArray,i))[0];
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %d\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetCharArrayRegion(charArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)charArray;
   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");
  } else if (index == JAVA_BYTE) {
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_BYTE with arrayNumber = %d\n", arrayNumber);

   jbyteArray byteArray = env->NewByteArray(arrayNumber);
   jbyte* p = (jbyte*) MFcmalloc(arrayNumber* sizeof(jbyte));
   for (i=0;i<arrayNumber;i++) {
     p[i] = (jbyte) MFint(MFop(mupadArray,i));
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %d\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetByteArrayRegion(byteArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)byteArray;
   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");

  } else if (index == JAVA_SHORT) {
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_SHORT with arrayNumber = %d\n", arrayNumber);

   jshortArray shortArray = env->NewShortArray(arrayNumber);
   jshort* p = (jshort*) MFcmalloc(arrayNumber* sizeof(jshort));
   for (i=0;i<arrayNumber;i++) {
     p[i] = (jshort)MFint(MFop(mupadArray,i));
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %d\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetShortArrayRegion(shortArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)shortArray;
   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");

  } else if (index == JAVA_INT) {
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_INT with arrayNumber = %d\n", arrayNumber);

   jintArray intArray = env->NewIntArray(arrayNumber);
   jint* p = (jint*) MFcmalloc(arrayNumber* sizeof(jint));
   for (i=0;i<arrayNumber;i++) {
     p[i] = (jint)MFint(MFop(mupadArray,i));
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %d\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetIntArrayRegion(intArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)intArray;
   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");

  } else if (index == JAVA_LONG) {
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_LONG with arrayNumber = %d\n", arrayNumber);

   jlongArray longArray = env->NewLongArray(arrayNumber);
   jlong* p = (jlong*) MFcmalloc(arrayNumber* sizeof(jlong));
   for (i=0;i<arrayNumber;i++) {
     p[i] = JHelper::text2jlong(env, MFexpr2text(MFop(mupadArray,i)));
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %d\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetLongArrayRegion(longArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)longArray;
   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");

  } else if (index == JAVA_FLOAT) {
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_FLOAT with arrayNumber = %d\n", arrayNumber);

   jfloatArray floatArray = env->NewFloatArray(arrayNumber);
   jfloat* p = (jfloat*) MFcmalloc(arrayNumber* sizeof(jfloat));
   for (i=0;i<arrayNumber;i++) {
     p[i] = (jfloat) MFfloat(MFop(mupadArray,i));
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %f\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetFloatArrayRegion(floatArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)floatArray;
   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");
  } else if (index == JAVA_DOUBLE) {
   if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_DOUBLE with arrayNumber = %d\n", arrayNumber);

   jdoubleArray doubleArray = env->NewDoubleArray(arrayNumber);
   jdouble* p = (jdouble*) MFcmalloc(arrayNumber* sizeof(jdouble));
   for (i=0;i<arrayNumber;i++) {
     p[i] = (jdouble) MFdouble(MFop(mupadArray,i));
     if (_debug>2) MFprintf("createSingleJNIArray: Element %d = %f\n",i, p[i]);
   }
   if (_debug>2) MFprintf("createSingleJNIArray: Before setting array\n");
   env->SetDoubleArrayRegion(doubleArray, 0, arrayNumber, p);
   MFcfree(p);
   *currentArray = (jobjectArray)doubleArray;
   if (_debug>2) MFprintf("createSingleJNIArray: After freeing memory\n");
  } else if (index == JAVA_BIGINTEGER) {                                               // Now check all the non-trivial but supported types
    if (_debug>2) MFprintf("createSingleJNIArray: In JAVA_BIGINTEGER with arrayNumber = %d\n", arrayNumber);

    tClass = env->FindClass("java/math/BigInteger");
    *currentArray = env->NewObjectArray(arrayNumber, tClass, NULL);
    mid = env->GetMethodID(tClass, "<init>", "(Ljava/lang/String;)V");
    jstring utf_string;

    if (_debug>2) MFprintf("createSingleJNIArray: biArrayNumber = %d\n", arrayNumber);

    for (i=0;i<arrayNumber;i++) {
      if (_debug>2) MFprintf("createSingleJNIArray: Setting basic element %d = %s\n", i, MFexpr2text(MFop(mupadArray,i)));
      utf_string = JSystem::NewPlatformString(env, MFexpr2text(MFop(mupadArray,i)));
      basicElement = env->NewObject(tClass, mid, utf_string);
      env->DeleteLocalRef(utf_string);
      if (basicElement == NULL) {
        if (_debug>2) MFprintf("createSingleJNIArray:The %dth element was NULL. No more memory. Returning\n",i);
        return JNI_FALSE;
      }
      else
        env->SetObjectArrayElement(*currentArray, i, basicElement);

      env->DeleteLocalRef(basicElement);                                        // To free memory
    }
  } else if (index == JAVA_BIGDECIMAL) {

     tClass = env->FindClass("java/math/BigDecimal");
     *currentArray = env->NewObjectArray(arrayNumber, tClass, NULL);
     jstring utf_string;
     mid = env->GetMethodID(tClass, "<init>", "(Ljava/lang/String;)V");

     for (i=0;i<arrayNumber;i++) {
      utf_string = JSystem::NewPlatformString(env, MFexpr2text(MFop(mupadArray,i)));
      basicElement = env->NewObject(tClass, mid, utf_string);
      env->DeleteLocalRef(utf_string);

      //basicElement = env->NewObject(tClass, mid, env->NewStringUTF(MFexpr2text(MFop(mupadArray,i))));
      if (basicElement == NULL) {
        if (_debug>1) MFprintf("createSingleJNIArray:The %dth element was NULL. No more memory. Returning\n",i);
        return JNI_FALSE;
      }
      else
        env->SetObjectArrayElement(*currentArray, i, basicElement);

      env->DeleteLocalRef(basicElement);                                        // To free memory
     }
  } else if (index == JAVA_STRING) {

    tClass = env->FindClass("java/lang/String");
    *currentArray = env->NewObjectArray(arrayNumber, tClass, NULL);
    jstring utf_string;
    mid = env->GetMethodID(tClass, "<init>", "(Ljava/lang/String;)V");
    for (i=0;i<arrayNumber;i++) {
      utf_string = JSystem::NewPlatformString(env, MFstring(MFop(mupadArray,i)));
      if (_debug>2) MFprintf("createSingleJNIArray: %dth element = '%s'\n",i, MFstring(MFop(mupadArray,i)));
      basicElement = env->NewObject(tClass, mid, utf_string);
      env->DeleteLocalRef(utf_string);

      //basicElement = env->NewObject(tClass, mid, env->NewStringUTF(MFstring(MFop(mupadArray,i))));
      if (basicElement == NULL) {
        if (_debug>1) MFprintf("createSingleJNIArray:The %dth element was NULL. No more memory. Returning\n",i);
        return JNI_FALSE;
      }
      else
        env->SetObjectArrayElement(*currentArray, i, basicElement);

      env->DeleteLocalRef(basicElement);                                        // To free memory
    }
  } else if ((index == JAVA_UNKNOWN) || (index == JAVA_OBJECT)) {

    // it has to have at least one element
    char *objectChars = MFstring(MFop(mupadArray, 0));
    if (index == JAVA_UNKNOWN) {
      if (_debug > 2) MFprintf("createSingleJNIArray: getting object from JSystem.\n");
      jobject tmpObject = JSystem::HO_getObject(env, objectChars);
      if (_debug > 2) MFprintf("createSingleJNIArray: Now getting class of the object.\n");
      tClass = env->GetObjectClass(tmpObject);
      env->DeleteLocalRef(tmpObject);
    }
    else {
      tClass = env->FindClass("java/lang/Object");
    }
    if (_debug > 2) MFprintf("createSingleJNIArray: getting object from JSystem.\n");
    // Create array consisting of only the object of the first element.
    *currentArray = env->NewObjectArray(arrayNumber, tClass, NULL);

    for (i=0;i<arrayNumber;i++) {
      char *objectChars = MFstring(MFop(mupadArray,i));
      if (_debug>2) MFprintf("createSingleJNIArray: getting %dth element = '%s'\n",i, objectChars);
      jobject tmpObject = JSystem::HO_getObject(env, objectChars);

      if (tmpObject == NULL) {
        if (_debug>1) MFprintf("createSingleJNIArray:The %dth element was NULL. No more memory. Returning\n",i);
        return JNI_FALSE;
      }
      else
        env->SetObjectArrayElement(*currentArray, i, tmpObject);
    }
  } else {
    MFprintf("createSingleJNIArray: This array type is not (yet) supported.\n",i);
    return JNI_FALSE;
  }

  if (_debug>1) MFprintf("JHelper::createSingleJNIArray: ===> size of the array : %d\n", env->GetArrayLength(*currentArray));
  return JNI_TRUE;
}

/** createDoubleJNIArray
 * make sure to call this procedure with the right index, since otherwise
 * the invokation of the chosen match (depending on max/min/native...) will
 * not work.
 *
 * @param env         The ubiquitous pointer to JNI.
 * @param mupadArray   A pointer to a MuPAD array.
 * @param index        The calculated index for the parameter or return value.
 * @param currentArray A pointer to a jobjectArray. Memory will be appointed to currentArray and must be freed later !
 */
jboolean JHelper::createDoubleJNIArray(JNIEnv* env, MTcell mupadArray, jint index, jobjectArray* currentArray) {

  jint i, innerLength;
  jclass tClass;                                                                // For the type of the class

  int arrayNumber = MFnops(mupadArray);
  jboolean worked;
  // Since the outer arrays are all derived from object, create them.
  jclass oClass = env->FindClass("java/lang/Object");
  if (oClass == NULL) {
   if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : Could not find the Object Class");
   return JNI_FALSE;
  }

  if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : index is now %d\n", index);

  // This is just a check if the function was called correctly (should never be doubted
  // since it will be invoked by createMultiJNIArray...)
  if (index - JAVA_ARRAY > 100) {                                               // If the signature shows a list in a list
    index -= JAVA_ARRAY;
  } else if (index - JAVA_ARRAY > 0) {
    return JHelper::createSingleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else
    return JNI_FALSE;                                                           // not a double array

  // General necessities to take care of:
  if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : primitive data type with arrayNumber %d and index %d\n", arrayNumber, index);
  *currentArray = env->NewObjectArray(arrayNumber, oClass, NULL);               // create dummy fields using object class.
  if (*currentArray == NULL) {                                                  // out of memory
    if (_debug>1) MFprintf("createDoubleJNIArray -> out of memory error\n");
    return JNI_FALSE;
  }
  env->DeleteLocalRef(oClass);

  switch ((index%JAVA_ARRAY)) {
    case JAVA_BOOLEAN: tClass = env->FindClass("[Z");	break;
    case JAVA_CHAR: tClass = env->FindClass("[C"); break;
    case JAVA_BYTE: tClass = env->FindClass("[B"); break;
    case JAVA_SHORT: tClass = env->FindClass("[S"); break;
    case JAVA_INT: tClass = env->FindClass("[I"); break;
    case JAVA_LONG: tClass = env->FindClass("[J"); break;
    case JAVA_FLOAT: tClass = env->FindClass("[F"); break;
    case JAVA_DOUBLE: tClass = env->FindClass("[D"); break;
		default: tClass = env->FindClass("[Ljava/lang/Object;"); break;
  }

  for (i=0;i<arrayNumber;i++) {                                             //for every element in the array a recursive call.
    innerLength = MFnops(MFop(mupadArray, i));
    if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : init with %d and innerLength %d\n", i, innerLength);
    innerLength = MFnops(MFop(mupadArray, i));
    // Preinitialization (will be filled with a later call...)
    jobjectArray tempArray = env->NewObjectArray(innerLength, tClass, NULL);
    if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : After init with %d\n", i);

    worked = JHelper::createSingleJNIArray(env, MFop(mupadArray, i), index, &tempArray);
    if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : After creating tempArray with %d\n", i);
    if (worked == JNI_FALSE)
      return JNI_FALSE;
    else
      env->SetObjectArrayElement(*currentArray, i, tempArray);                  // put it into the main array

    env->DeleteLocalRef(tempArray);                                             // free the memory
    if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : After setting object array element with %d\n", i);
  }
  env->DeleteLocalRef(tClass);
  if (_debug>1) MFprintf("JHelper::createDoubleJNIArray : After create...\n");
  return JNI_TRUE;

}

/** createTripleJNIArray
 * make sure to call this procedure with the right index, since otherwise
 * the invokation of the chosen match (depending on max/min/native...) will
 * not work.
 *
 * @param env         The ubiquitous pointer to JNI.
 * @param mupadArray   A pointer to a MuPAD array.
 * @param index        The calculated index for the parameter or return value.
 * @param currentArray A pointer to a jobjectArray. Memory will be appointed to currentArray and must be freed later !
 */
jboolean JHelper::createTripleJNIArray(JNIEnv* env, MTcell mupadArray, jint index, jobjectArray* currentArray) {

  jint i, innerLength;
  jclass tClass;                                                                // For the type of the class

  int arrayNumber = MFnops(mupadArray);
  jboolean worked;
  // Since the outer arrays are all derived from object, create them.
  jclass oClass = env->FindClass("java/lang/Object");
  if (oClass == NULL) {
   if (_debug>1) MFprintf("JHelper::createTripleJNIArray : Could not find the Object Class");
   return JNI_FALSE;
  }

  if (_debug>1) MFprintf("JHelper::createTripleJNIArray : index is now %d\n", index);

  // This is just a check if the function was called correctly (should never be doubted
  // since it will be invoked by createMultiJNIArray...)
  if (index - JAVA_ARRAY > 200) {                                               // If the signature shows a list in a list
    index -= JAVA_ARRAY;
  } else if (index - JAVA_ARRAY > 100) {
    return JHelper::createDoubleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else if (index - JAVA_ARRAY > 0) {
    return JHelper::createSingleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else
    return JNI_FALSE;                                                           // not a Triple array

  // General necessities to take care of:
  if (_debug>1) MFprintf("JHelper::createTripleJNIArray : primitive data type with arrayNumber %d and index %d\n", arrayNumber, index);
  *currentArray = env->NewObjectArray(arrayNumber, oClass, NULL);               // create dummy fields using object class.
  if (*currentArray == NULL) {                                                  // out of memory
    if (_debug>1) MFprintf("createTripleJNIArray -> out of memory error\n");
    return JNI_FALSE;
  }
  env->DeleteLocalRef(oClass);
  // In this depth the container holds only arrays, so they derive from Object...
  tClass = env->FindClass("[Ljava/lang/Object;");

  for (i=0;i<arrayNumber;i++) {                                             //for every element in the array a recursive call.
    innerLength = MFnops(MFop(mupadArray, i));
    if (_debug>1) MFprintf("JHelper::createTripleJNIArray : init with %d and innerLength %d\n", i, innerLength);
    innerLength = MFnops(MFop(mupadArray, i));
    // Preinitialization (will be filled with a later call...)
    jobjectArray tempArray = env->NewObjectArray(innerLength, tClass, NULL);
    if (_debug>1) MFprintf("JHelper::createTripleJNIArray : After init with %d\n", i);

    worked = JHelper::createDoubleJNIArray(env, MFop(mupadArray, i), index, &tempArray);
    if (_debug>1) MFprintf("JHelper::createTripleJNIArray : After creating tempArray with %d\n", i);
    if (worked == JNI_FALSE)
      return JNI_FALSE;
    else
      env->SetObjectArrayElement(*currentArray, i, tempArray);                  // put it into the main array

    env->DeleteLocalRef(tempArray);                                             // free the memory
    if (_debug>1) MFprintf("JHelper::createTripleJNIArray : After setting object array element with %d\n", i);
  }
  env->DeleteLocalRef(tClass);
  if (_debug>1) MFprintf("JHelper::createTripleJNIArray : After create...\n");
  return JNI_TRUE;
}

/** createQuadJNIArray
 * make sure to call this procedure with the right index, since otherwise
 * the invokation of the chosen match (depending on max/min/native...) will
 * not work.
 *
 * @param env         The ubiquitous pointer to JNI.
 * @param mupadArray   A pointer to a MuPAD array.
 * @param index        The calculated index for the parameter or return value.
 * @param currentArray A pointer to a jobjectArray. Memory will be appointed to currentArray and must be freed later !
 */
jboolean JHelper::createQuadJNIArray(JNIEnv* env, MTcell mupadArray, jint index, jobjectArray* currentArray) {

  jint i, innerLength;
  jclass tClass;                                                                // For the type of the class

  int arrayNumber = MFnops(mupadArray);
  jboolean worked;
  // Since the outer arrays are all derived from object, create them.
  jclass oClass = env->FindClass("java/lang/Object");
  if (oClass == NULL) {
   if (_debug>1) MFprintf("JHelper::createQuadJNIArray : Could not find the Object Class");
   return JNI_FALSE;
  }

  if (_debug>1) MFprintf("JHelper::createQuadJNIArray : index is now %d\n", index);

  // This is just a check if the function was called correctly (should never be doubted
  // since it will be invoked by createMultiJNIArray...)
  if (index - JAVA_ARRAY > 300) {                                               // If the signature shows a list in a list
    index -= JAVA_ARRAY;
  } else if (index - JAVA_ARRAY > 200) {
    return JHelper::createTripleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else if (index - JAVA_ARRAY > 100) {
    return JHelper::createDoubleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else if (index - JAVA_ARRAY > 0) {
    return JHelper::createSingleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else
    return JNI_FALSE;                                                           // not a Quad array

  // General necessities to take care of:
  if (_debug>1) MFprintf("JHelper::createQuadJNIArray : primitive data type with arrayNumber %d and index %d\n", arrayNumber, index);
  *currentArray = env->NewObjectArray(arrayNumber, oClass, NULL);               // create dummy fields using object class.
  if (*currentArray == NULL) {                                                  // out of memory
    if (_debug>1) MFprintf("createQuadJNIArray -> out of memory error\n");
    return JNI_FALSE;
  }
  env->DeleteLocalRef(oClass);
  // In this depth the container holds only arrays, so they derive from Object...
  tClass = env->FindClass("[Ljava/lang/Object;");

  for (i=0;i<arrayNumber;i++) {                                             //for every element in the array a recursive call.
    innerLength = MFnops(MFop(mupadArray, i));
    if (_debug>1) MFprintf("JHelper::createQuadJNIArray : init with %d and innerLength %d\n", i, innerLength);
    innerLength = MFnops(MFop(mupadArray, i));
    // Preinitialization (will be filled with a later call...)
    jobjectArray tempArray = env->NewObjectArray(innerLength, tClass, NULL);
    if (_debug>1) MFprintf("JHelper::createQuadJNIArray : After init with %d\n", i);

    worked = JHelper::createTripleJNIArray(env, MFop(mupadArray, i), index, &tempArray);
    if (_debug>1) MFprintf("JHelper::createQuadJNIArray : After creating tempArray with %d\n", i);
    if (worked == JNI_FALSE)
      return JNI_FALSE;
    else
      env->SetObjectArrayElement(*currentArray, i, tempArray);                  // put it into the main array

    env->DeleteLocalRef(tempArray);                                             // free the memory
    if (_debug>1) MFprintf("JHelper::createQuadJNIArray : After setting object array element with %d\n", i);
  }

  env->DeleteLocalRef(tClass);
  if (_debug>1) MFprintf("JHelper::createQuadJNIArray : After create...\n");
  return JNI_TRUE;
}

/** createQuadJNIArray
 * make sure to call this procedure with the right index, since otherwise
 * the invokation of the chosen match (depending on max/min/native...) will
 * not work.
 *
 * @param env         The ubiquitous pointer to JNI.
 * @param mupadArray   A pointer to a MuPAD array.
 * @param index        The calculated index for the parameter or return value.
 * @param currentArray A pointer to a jobjectArray. Memory will be appointed to currentArray and must be freed later !
 */
jboolean JHelper::createQuintJNIArray(JNIEnv* env, MTcell mupadArray, jint index, jobjectArray* currentArray) {

  jint i, innerLength;
  jclass tClass;                                                                // For the type of the class

  int arrayNumber = MFnops(mupadArray);
  jboolean worked;
  // Since the outer arrays are all derived from object, create them.
  jclass oClass = env->FindClass("java/lang/Object");
  if (oClass == NULL) {
   if (_debug>1) MFprintf("JHelper::createQuintJNIArray : Could not find the Object Class");
   return JNI_FALSE;
  }

  if (_debug>1) MFprintf("JHelper::createQuintJNIArray : index is now %d\n", index);

  // This is just a check if the function was called correctly (should never be doubted
  // since it will be invoked by createMultiJNIArray...)
  if (index - JAVA_ARRAY > 400) {                                               // If the signature shows a list in a list
    index -= JAVA_ARRAY;
  } else if (index - JAVA_ARRAY > 300) {
    return JHelper::createQuadJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else if (index - JAVA_ARRAY > 200) {
    return JHelper::createTripleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else if (index - JAVA_ARRAY > 100) {
    return JHelper::createDoubleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else if (index - JAVA_ARRAY > 0) {
    return JHelper::createSingleJNIArray(env, mupadArray, index, currentArray); // Just call the one array version.
  } else
    return JNI_FALSE;                                                           // not a Quint array

  // General necessities to take care of:
  if (_debug>1) MFprintf("JHelper::createQuintJNIArray : primitive data type with arrayNumber %d and index %d\n", arrayNumber, index);
  *currentArray = env->NewObjectArray(arrayNumber, oClass, NULL);               // create dummy fields using object class.
  if (*currentArray == NULL) {                                                  // out of memory
    if (_debug>1) MFprintf("createQuintJNIArray -> out of memory error\n");
    return JNI_FALSE;
  }
  env->DeleteLocalRef(oClass);
  // In this depth the container holds only arrays, so they derive from Object...
  tClass = env->FindClass("[Ljava/lang/Object;");

  for (i=0;i<arrayNumber;i++) {                                             //for every element in the array a recursive call.
    innerLength = MFnops(MFop(mupadArray, i));
    if (_debug>1) MFprintf("JHelper::createQuintJNIArray : init with %d and innerLength %d\n", i, innerLength);
    innerLength = MFnops(MFop(mupadArray, i));
    // Preinitialization (will be filled with a later call...)
    jobjectArray tempArray = env->NewObjectArray(innerLength, tClass, NULL);
    if (_debug>1) MFprintf("JHelper::createQuintJNIArray : After init with %d\n", i);

    worked = JHelper::createQuadJNIArray(env, MFop(mupadArray, i), index, &tempArray);
    if (_debug>1) MFprintf("JHelper::createQuintJNIArray : After creating tempArray with %d\n", i);
    if (worked == JNI_FALSE)
      return JNI_FALSE;
    else
      env->SetObjectArrayElement(*currentArray, i, tempArray);                  // put it into the main array

    env->DeleteLocalRef(tempArray);                                             // free the memory
    if (_debug>1) MFprintf("JHelper::createQuintJNIArray : After setting object array element with %d\n", i);
  }

  env->DeleteLocalRef(tClass);
  if (_debug>1) MFprintf("JHelper::createQuintJNIArray : After create...\n");
  return JNI_TRUE;
}

/** createMultiJNIArray
 * make sure to call this procedure with the right signature, since otherwise
 * the invokation of the chosen match (depending on max/min/native...) will
 * not work.
 * @param env         The ubiquitous pointer to JNI.
 * @param mupadArray   A pointer to a MuPAD array.
 * @param index        The calculated index for the parameter or return value.
 */
jboolean JHelper::createMultiJNIArray(JNIEnv* env, MTcell mupadArray, jint index, jobjectArray* currentArray) {

  if (_debug>1) MFprintf("JHelper::createMultiJNIArray : index is now %d\n", index);

  switch ((index/100)) {
    case 1: return JHelper::createSingleJNIArray(env, mupadArray, index, currentArray); break;
    case 2: return JHelper::createDoubleJNIArray(env, mupadArray, index, currentArray); break;
    case 3: return JHelper::createTripleJNIArray(env, mupadArray, index, currentArray); break;
    case 4: return JHelper::createQuadJNIArray(env, mupadArray, index, currentArray); break;
    case 5: return JHelper::createQuintJNIArray(env, mupadArray, index, currentArray); break;
		default: MFprintf("Only arrays with depth < 6 were implemented.\n"); return JNI_FALSE; break;
  }
}

/** createSingleMuPADList
 * @param env         The ubiquitous pointer to JNI.
 * @param arrayObject The objectArray to be transformed into a MuPAD list.
 * @param index       The number corresponding to the signature of the array.
 * @return            The complete MuPAD array.
 */
jboolean JHelper::createSingleMuPADList(JNIEnv *env, jobjectArray arrayObject, MTcell *mupadList, jint index) {

  if (_debug>1) MFprintf("JHelper::createSingleMuPADList: Started.\n");
  jint j;
  char *tmpChar;
  jint arrayNumber = env->GetArrayLength((jobjectArray) arrayObject);          // Get the length of the current array.

  // Just a small check (should never happen anyways...)
  if (index > 200) {
    MFprintf("Double Arrays not allowed in createSingleMuPADList.\n");
    return JNI_FALSE;
  }

  if (_debug>1) MFprintf("Array length = %d and index = %d.\n", arrayNumber, index%100);

  //*mupadList = MFnewList(arrayNumber);                                        // Create a new list with arrayNumber entries
  if ((index%100) == JAVA_BOOLEAN) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_BOOLEAN.");
    jboolean *value = (jboolean*) MFcmalloc(arrayNumber * sizeof(jboolean));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetBooleanArrayRegion((jbooleanArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      if (_debug>1) MFprintf("[%d] = %d.\n", j, value[j]);
      MFopSet(*mupadList, j, MFbool(value[j]));                                 // set the object in cell j
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_CHAR) {
    jstring tmpString;                                                          // for the unicode string (and therefore the jchar)                                                          // to hold the newly created char array
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_CHAR.");
    jchar *value = (jchar*) MFcmalloc(arrayNumber * sizeof(jchar));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetCharArrayRegion((jcharArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      tmpString = env->NewString(&value[j], 1);                                 // transform the jchar to a unicode string
      //tmpChar = env->GetStringUTFChars(tmpString, NULL);                        // and the unicode string to a UTF8 string
      tmpChar = JHelper::GetNativeChars(env, tmpString);
      env->DeleteLocalRef(tmpString);
      if (_debug>1) MFprintf("[%d] = %d.\n", j, tmpChar);
      MFopSet(*mupadList, j, MFstring(tmpChar));                                // set the object in cell j
      MFcfree(tmpChar);
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_BYTE) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_BYTE.");
    jbyte *value = (jbyte*) MFcmalloc(arrayNumber * sizeof(jbyte));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetByteArrayRegion((jbyteArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      if (_debug>1) MFprintf("[%d] = %d.\n", j, value[j]);
      MFopSet(*mupadList, j, MFint(value[j]));                                  // set the object in cell j
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_SHORT) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_SHORT.");
    jshort *value = (jshort*) MFcmalloc(arrayNumber * sizeof(jshort));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetShortArrayRegion((jshortArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      if (_debug>1) MFprintf("[%d] = %d.\n", j, value[j]);
      MFopSet(*mupadList, j, MFint(value[j]));                                  // set the object in cell j
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_INT) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_INT.");
    jint *value = (jint*) MFcmalloc(arrayNumber * sizeof(jint));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetIntArrayRegion((jintArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      if (_debug>1) MFprintf("[%d] = %d.\n", j, value[j]);
      MFopSet(*mupadList, j, MFint(value[j]));                                  // set the object in cell j
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_LONG) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_LONG.");
    jlong *value = (jlong*) MFcmalloc(arrayNumber * sizeof(jlong));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetLongArrayRegion((jlongArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      if (_debug>1) MFprintf("[%d] = %d.\n", j, value[j]);
      tmpChar = JHelper::jlong2text(env,value[j]);
      MFopSet(*mupadList, j, MFtext2expr(tmpChar));   // set the object in cell j
      MFcfree(tmpChar);
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_FLOAT) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_FLOAT.");
    jfloat *value = (jfloat*) MFcmalloc(arrayNumber * sizeof(jfloat));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetFloatArrayRegion((jfloatArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      if (_debug>1) MFprintf("[%d] = %f.\n", j, value[j]);
      MFopSet(*mupadList, j, MFfloat(value[j]));                                // set the object in cell j
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_DOUBLE) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_DOUBLE.");
    jdouble *value = (jdouble*) MFcmalloc(arrayNumber * sizeof(jdouble));
    if (value == NULL)                                                          // No more memory...
      return JNI_FALSE;
    env->GetDoubleArrayRegion((jdoubleArray) arrayObject, 0, arrayNumber, value);
    for (j=0;j < arrayNumber; j++) {
      if (_debug>1) MFprintf("[%d] = %f.\n", j, value[j]);
      MFopSet(*mupadList, j, MFdouble(value[j]));                               // set the object in cell j
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
    MFcfree(value);
  } else if ((index%100) == JAVA_BIGINTEGER) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_BIGINTEGER.");
    jobject value;
    char *tmpChar;
    for (j=0;j < arrayNumber; j++) {
      value = env->GetObjectArrayElement(arrayObject, j);
      tmpChar = JHelper::object2text(env, value);
      if (_debug>1) MFprintf("[%d] = %s.\n", j, tmpChar);
      MFopSet(*mupadList, j, MFtext2expr(tmpChar));                             // set the object in cell j
      MFcfree(tmpChar);
      env->DeleteLocalRef(value);                                               // free memory
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
  } else if ((index%100) == JAVA_BIGDECIMAL) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_BIGDECIMAL.");
    jobject value;
    char *tmpChar;
    for (j=0;j < arrayNumber; j++) {
      value = env->GetObjectArrayElement(arrayObject, j);
      tmpChar = JHelper::object2text(env, value);
      if (_debug>1) MFprintf("[%d] = %s.\n", j, tmpChar);
      MFopSet(*mupadList, j, MFtext2expr(tmpChar));                             // set the object in cell j
      MFcfree(tmpChar);
      env->DeleteLocalRef(value);                                               // free memory
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
  } else if ((index%100) == JAVA_STRING) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_STRING.");
    jobject value;
    jstring tmpString;                                                          // for the unicode string (and therefore the jchar)
    for (j=0;j < arrayNumber; j++) {
      value = env->GetObjectArrayElement(arrayObject, j);
      tmpString = (jstring)value;
      //tmpChar = env->GetStringUTFChars(tmpString, NULL);
      tmpChar = JHelper::GetNativeChars(env, tmpString);
      if (_debug>1) MFprintf("[%d] = %s.\n", j, tmpChar);
      MFopSet(*mupadList, j, MFstring(tmpChar));                                // set the object in cell j
      MFcfree(tmpChar);
      env->DeleteLocalRef(value);                                               // free memory
    }
    MFsig(*mupadList);                                                          // calculate signature (and therefore make the list available)
  } else if ((index%100) == JAVA_UNKNOWN) {
    if (_debug>1) MFprintf("JHelper::createSingleMuPADList: In JAVA_UNKNOWN.");
    jboolean createObjectWorked;
    jobject value;
    MTcell mupad_result;
    for (j=0;j < arrayNumber; j++) {
     tmpChar = (char *) MFcmalloc(20 * sizeof(char));
     sprintf(tmpChar, "@MuPAD_JNI_%08d", oH_counter);
     value = env->GetObjectArrayElement(arrayObject, j);

     if (_debug>0) MFprintf("Before creating createObjectWorked in array with MuPAD_JNI_%08d...\n", oH_counter);
     createObjectWorked = JSystem::addToList(env, tmpChar, value);
     if (_debug>0) MFprintf("After creating creatObjectWorked in array ...\n");
     if (createObjectWorked == JNI_TRUE) {
       if (_debug>0) MFprintf("The creation of the object did work. It is stored as %s\n", tmpChar);
       oH_counter++;
       mupad_result = MFstring(tmpChar);
     } else {
       MFprintf("The creation of the object failed.\n");
       env->DeleteLocalRef(value);
       MFcfree(tmpChar);
       MFsig(*mupadList); // at least finish list creation (who knows what was before ?)
       return JNI_FALSE;
     }
     if (_debug>1) MFprintf("[%08d] = %s.\n", j, tmpChar);
     MFopSet(*mupadList, j, mupad_result);                             // set the object in cell j
     MFcfree(tmpChar);
     env->DeleteLocalRef(value);                                       // free memory
    }
    MFsig(*mupadList);                   // calculate signature (and therefore make the list available)
  } else {
    MFprintf("This kind of array is not supported (yet).");
    return JNI_FALSE;
  }

  return JNI_TRUE;
}

/** createDoubleMuPADList
 * @param env         The ubiquitous pointer to JNI.
 * @param arrayObject The objectArray to be transformed into a MuPAD list.
 * @param index       The number corresponding to the signature of the array.
 * @return            The complete MuPAD array.
 */
jboolean JHelper::createDoubleMuPADList(JNIEnv *env, jobjectArray arrayObject, MTcell *mupadList, jint index) {

  if (_debug>1) MFprintf("JHelper::createDoubleMuPADList: Started.\n");
  jint arrayNumber = env->GetArrayLength(arrayObject);                          // Get the length of the current array.
  if (_debug>1) MFprintf("JHelper::createDoubleMuPADList: create new outer list with %d entries.\n", arrayNumber);

  jobjectArray innerArray;
  jint innerArrayLength;

  for (int i = 0; i < arrayNumber; i++) {
    innerArray = (jobjectArray) env->GetObjectArrayElement(arrayObject, i);     // Get the i'th inner array
    innerArrayLength = env->GetArrayLength(innerArray);                         // and its length
    if (_debug>1) MFprintf("JHelper::createDoubleMuPADList: create new inner list with %d entries.\n", innerArrayLength);
    MTcell innerMupadList = MFnewList(innerArrayLength);                        // create a new MuPAD list
    if (JHelper::createSingleMuPADList(env, innerArray, &innerMupadList, index-100) == JNI_TRUE) {
      if (_debug>1) MFprintf("JHelper::createDoubleMuPADList: before setting list %d.\n", i);
      MFopSet(*mupadList, i, innerMupadList);                                   // place the array at position in cell i
      if (_debug>1) MFprintf("JHelper::createDoubleMuPADList: after setting list %d.\n", i);
    } else {
      return JNI_FALSE;                                                         // something severe happened
      // To be checked, since there could be memory leaks here !!!
    }
    env->DeleteLocalRef(innerArray);
  }

  if (_debug>1) MFprintf("JHelper::createDoubleMuPADList: before setting mupadList.\n");
  MFsig(*mupadList);                                                             // calculate signature (and therefore make the list available)
  if (_debug>1) MFprintf("JHelper::createDoubleMuPADList: after setting mupadList.\n");
  return JNI_TRUE;
}

/** createTripleMuPADList
 * @param env         The ubiquitous pointer to JNI.
 * @param arrayObject The objectArray to be transformed into a MuPAD list.
 * @param index       The number corresponding to the signature of the array.
 * @return            The complete MuPAD array.
 */
jboolean JHelper::createTripleMuPADList(JNIEnv *env, jobjectArray arrayObject, MTcell *mupadList, jint index) {

  if (_debug>1) MFprintf("JHelper::createTripleMuPADList: Started.\n");
  jint arrayNumber = env->GetArrayLength(arrayObject);                          // Get the length of the current array.
  if (_debug>1) MFprintf("JHelper::createTripleMuPADList: create new outer list with %d entries.\n", arrayNumber);

  jobjectArray innerArray;
  jint innerArrayLength;

  for (int i = 0; i < arrayNumber; i++) {
    innerArray = (jobjectArray) env->GetObjectArrayElement(arrayObject, i);     // Get the i'th inner array
    innerArrayLength = env->GetArrayLength(innerArray);                         // and its length
    if (_debug>1) MFprintf("JHelper::createTripleMuPADList: create new inner list with %d entries.\n", innerArrayLength);

    MTcell innerMupadList = MFnewList(innerArrayLength);                        // create a new MuPAD list
    if (JHelper::createDoubleMuPADList(env, innerArray, &innerMupadList, index-100) == JNI_TRUE) {
      if (_debug>1) MFprintf("JHelper::createTripleMuPADList: before setting list %d.\n", i);
      MFopSet(*mupadList, i, innerMupadList);                                   // place the array at position in cell i
      if (_debug>1) MFprintf("JHelper::createTripleMuPADList: after setting list %d.\n", i);
    } else {
      return JNI_FALSE;                                                         // something severe happened
      // To be checked, since there could be memory leaks here !!!
    }
    env->DeleteLocalRef(innerArray);
 }

  if (_debug>1) MFprintf("JHelper::createTripleMuPADList: before setting mupadList.\n");
  MFsig(*mupadList);                                                             // calculate signature (and therefore make the list available)
  if (_debug>1) MFprintf("JHelper::createTripleMuPADList: after setting mupadList.\n");
  return JNI_TRUE;
}

/** createQuadMuPADList
 * @param env         The ubiquitous pointer to JNI.
 * @param arrayObject The objectArray to be transformed into a MuPAD list.
 * @param index       The number corresponding to the signature of the array.
 * @return            The complete MuPAD array.
 */
jboolean JHelper::createQuadMuPADList(JNIEnv *env, jobjectArray arrayObject, MTcell *mupadList, jint index) {

  if (_debug>1) MFprintf("JHelper::createQuadMuPADList: Started.\n");
  jint arrayNumber = env->GetArrayLength(arrayObject);                          // Get the length of the current array.
  if (_debug>1) MFprintf("JHelper::createQuadMuPADList: create new outer list with %d entries.\n", arrayNumber);

  jobjectArray innerArray;
  jint innerArrayLength;

  for (int i = 0; i < arrayNumber; i++) {
    innerArray = (jobjectArray) env->GetObjectArrayElement(arrayObject, i);     // Get the i'th inner array
    innerArrayLength = env->GetArrayLength(innerArray);                         // and its length
    if (_debug>1) MFprintf("JHelper::createQuadMuPADList: create new inner list with %d entries.\n", innerArrayLength);

    MTcell innerMupadList = MFnewList(innerArrayLength);                        // create a new MuPAD list
    if (JHelper::createTripleMuPADList(env, innerArray, &innerMupadList, index-100) == JNI_TRUE) {
      if (_debug>1) MFprintf("JHelper::createQuadMuPADList: before setting list %d.\n", i);
      MFopSet(*mupadList, i, innerMupadList);                                   // place the array at position in cell i
      if (_debug>1) MFprintf("JHelper::createQuadMuPADList: after setting list %d.\n", i);
    } else {
      return JNI_FALSE;                                                         // something severe happened
      // To be checked, since there could be memory leaks here !!!
    }
    env->DeleteLocalRef(innerArray);
 }

  if (_debug>1) MFprintf("JHelper::createQuadMuPADList: before setting mupadList.\n");
  MFsig(*mupadList);                                                             // calculate signature (and therefore make the list available)
  if (_debug>1) MFprintf("JHelper::createQuadMuPADList: after setting mupadList.\n");
  return JNI_TRUE;
}

/** createQuintMuPADList
 * @param env         The ubiquitous pointer to JNI.
 * @param arrayObject The objectArray to be transformed into a MuPAD list.
 * @param index       The number corresponding to the signature of the array.
 * @return            The complete MuPAD array.
 */
jboolean JHelper::createQuintMuPADList(JNIEnv *env, jobjectArray arrayObject, MTcell *mupadList, jint index) {

  if (_debug>1) MFprintf("JHelper::createQuintMuPADList: Started.\n");
  jint arrayNumber = env->GetArrayLength(arrayObject);                          // Get the length of the current array.
  if (_debug>1) MFprintf("JHelper::createQuintMuPADList: create new outer list with %d entries.\n", arrayNumber);

  jobjectArray innerArray;
  jint innerArrayLength;

  for (int i = 0; i < arrayNumber; i++) {
    innerArray = (jobjectArray) env->GetObjectArrayElement(arrayObject, i);     // Get the i'th inner array
    innerArrayLength = env->GetArrayLength(innerArray);                         // and its length
    if (_debug>1) MFprintf("JHelper::createQuintMuPADList: create new inner list with %d entries.\n", innerArrayLength);

    MTcell innerMupadList = MFnewList(innerArrayLength);                        // create a new MuPAD list
    if (JHelper::createQuadMuPADList(env, innerArray, &innerMupadList, index-100) == JNI_TRUE) {
      if (_debug>1) MFprintf("JHelper::createQuintMuPADList: before setting list %d.\n", i);
      MFopSet(*mupadList, i, innerMupadList);                                   // place the array at position in cell i
      if (_debug>1) MFprintf("JHelper::createQuintMuPADList: after setting list %d.\n", i);
    } else {
      return JNI_FALSE;                                                         // something severe happened
      // To be checked, since there could be memory leaks here !!!
    }
    env->DeleteLocalRef(innerArray);
 }

  if (_debug>1) MFprintf("JHelper::createQuintMuPADList: before setting mupadList.\n");
  MFsig(*mupadList);                                                             // calculate signature (and therefore make the list available)
  if (_debug>1) MFprintf("JHelper::createQuintMuPADList: after setting mupadList.\n");
  return JNI_TRUE;
}

/** createMultiMuPADList
 * @param env         The ubiquitous pointer to JNI.
 * @param arrayObject The objectArray to be transformed into a MuPAD list.
 * @param index       The number corresponding to the signature of the array.
 * @return            The complete MuPAD array.
 */
MTcell JHelper::createMultiMuPADList(JNIEnv *env, jobjectArray arrayObject, jint index) {

  if (_debug>1) MFprintf("JHelper::createMultiMuPADList: Started.\n");
  jint arrayNumber = env->GetArrayLength(arrayObject);          // Get the length of the current array.
  if (_debug>1) MFprintf("JHelper::createMultiMuPADList: create new List with %d entries.\n", arrayNumber);
  MTcell mupadList = MFnewList(arrayNumber);

  switch (index/100) {
		case 1: if (JHelper::createSingleMuPADList(env, arrayObject, &mupadList, index) == JNI_TRUE) {
              if (_debug>1) MFprintf("JHelper::createMultiMuPADList: before returning single array.\n");
              return mupadList;
            }
            else
              return MFcopy(MVfail);
            break;
    case 2: if (JHelper::createDoubleMuPADList(env, arrayObject, &mupadList, index) == JNI_TRUE) {
              if (_debug>1) MFprintf("JHelper::createMultiMuPADList: before returning double array.\n");
              return mupadList;
            }
            else
              return MFcopy(MVfail);
            break;
    case 3: if (JHelper::createTripleMuPADList(env, arrayObject, &mupadList, index) == JNI_TRUE) {
              if (_debug>1) MFprintf("JHelper::createMultiMuPADList: before returning triple array.\n");
              return mupadList;
            }
            else
              return MFcopy(MVfail);
            break;
    case 4: if (JHelper::createQuadMuPADList(env, arrayObject, &mupadList, index) == JNI_TRUE) {
              if (_debug>1) MFprintf("JHelper::createMultiMuPADList: before returning quadruple array.\n");
              return mupadList;
            }
            else
              return MFcopy(MVfail);
            break;
    case 5: if (JHelper::createQuintMuPADList(env, arrayObject, &mupadList, index) == JNI_TRUE) {
              if (_debug>1) MFprintf("JHelper::createMultiMuPADList: before returning quintuple array.\n");
              return mupadList;
            }
            else
              return MFcopy(MVfail);
            break;
    default: MFprintf("Only arrays with depth < 6 were implemented.\n"); return MFcopy(MVfail); break;
	}
}


char *JHelper::GetNativeChars(JNIEnv *env, jstring jstr)
{
    jbyteArray bytes = 0;
    jthrowable exc;
    jmethodID MID_String_getBytes;
    char *result = 0;

    jclass Class_java_lang_String = env->FindClass("java/lang/String");
    MID_String_getBytes = env->GetMethodID(Class_java_lang_String, "getBytes", "()[B");

    if (env->EnsureLocalCapacity(2) < 0) {
        return 0; /* out of memory error */
    }
    //if (_debug>1) MFprintf("JHelper::GetNativeChars: Getting jbyteArray.\n");
    bytes = (jbyteArray) env->CallObjectMethod(jstr, MID_String_getBytes);
    //if (_debug>1) MFprintf("JHelper::GetNativeChars: After getting jbyteArray.\n");
    exc = env->ExceptionOccurred();
    if (!exc) {
        //if (_debug>1) MFprintf("JHelper::GetNativeChars: Before getting length.\n");
        jint len = env->GetArrayLength(bytes);
        //if (_debug>1) MFprintf("JHelper::GetNativeChars: Before allocating memory. %d\n", len);
        result = (char *)MFcmalloc(len + 1);
        //if (_debug>1) MFprintf("JHelper::GetNativeChars: After allocating memory.\n");
        if (result == NULL) {
            //JNU_ThrowByName(env, "java/lang/OutOfMemoryError", 0);
            if (_debug>1) MFprintf("JHelper::GetNativeChars: No more memory for result.\n");
            env->DeleteLocalRef(bytes);
            return NULL;
        }
        //if (_debug>1) MFprintf("JHelper::GetNativeChars: Before GetByteArrayRegion.\n");
//MFprintf("JHelper::GetNativeChars: Before GetByteArrayRegion.\n");
        env->GetByteArrayRegion(bytes, 0, len, (jbyte *)result);
        //if (_debug>1) MFprintf("JHelper::GetNativeChars: After GetByteArrayRegion.\n");
//MFprintf("JHelper::GetNativeChars: After GetByteArrayRegion.\n");
        result[len] = '\0'; /* NULL-terminate */
    } else {
        env->DeleteLocalRef(exc);
    }
    env->DeleteLocalRef(bytes);
    //if (_debug>1) MFprintf("JHelper::GetNativeChars: Before returning result.\n");
//MFprintf("JHelper::GetNativeChars: Before returning result.\n");
    env->DeleteLocalRef(Class_java_lang_String);
    env->DeleteLocalRef(bytes);
    return result;
}

/** addMuPADSecurityListener
 * @param env         The ubiquitous pointer to JNI.
 * @param arrayObject The objectArray to be transformed into a MuPAD list.
 * @param index       The number corresponding to the signature of the array.
 * @return            The complete MuPAD array.
 */
jboolean JSystem::addMuPADSecurityListener(JNIEnv *env) {

  if (_debug>1) MFprintf("addMuPADSecurityListener: started.\n");

  jclass hClass = env->FindClass("MuPADSecurityManager");
  if (hClass == NULL) {
    if (_debug>1) MFprintf("addMuPADSecurityListener: Class not found.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("addMuPADSecurityListener: Class found.\n");
  }

  jmethodID mid = env->GetStaticMethodID(hClass, "setSecurityManager", "()V");

  if (mid == NULL) {
    if (_debug>1) MFprintf("addMuPADSecurityListener: Method setSecurityManager not found.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("addMuPADSecurityListener: Method setSecurityManager found.\n");
  }

  env->CallStaticVoidMethod(hClass, mid, NULL);
  env->DeleteLocalRef(hClass);
  if (_debug>1) MFprintf("addMuPADSecurityListener: After invocation.\n");

  if (env->ExceptionOccurred()) {                                               // If an exception occurred
     env->ExceptionDescribe();                                                  // print it
     if (showErrors == JNI_TRUE) MFprintf("Error: Method setSecurityManager threw an exception.\n");
     return(JNI_FALSE);
  }
  return(JNI_TRUE);
}

/** startList
 * @param env         The ubiquitous pointer to JNI.
 * @return The created object.
 */
jobject JSystem::startList(JNIEnv *env) {

  if (_debug>1) MFprintf("startList: started.\n");

  jclass hClass = env->FindClass("HandleObjects");                              // Load the class
  if (hClass == NULL) {
    if (_debug>1) MFprintf("startList: Class not found.\n");
    return NULL;
  } else {
    if (_debug>1) MFprintf("startList: Class found.\n");
  }

  // First the basic constructor has to be invoked to avoid problems
  jmethodID mid = env->GetMethodID(hClass, "<init>", "()V");                    // Instanciate the class

  if (mid == NULL) {
    if (_debug>1) MFprintf("startList: Could not load constructor.\n");
    return NULL;
  }

  return env->NewObject(hClass, mid, NULL);                                     // Instanciate the class using a constructor with no arguments (default)
}

/** addToList
 * @param env  The ubiquitous pointer to JNI.
 * @param name The representative name that was given to the object.
 * @param data The java object that is unknown to MuPAD.
 * @return JNI_TRUE if everything went wrong, JNI_FALSE otherwise.
 */
jboolean JSystem::addToList(JNIEnv *env, char* name, jobject data) {

  jthrowable excp;
  jclass hClass = NULL;
  //jclass dataClass = NULL;

  if (_debug>1) MFprintf("addToList: started.\n");

  /*
  dataClass = env->GetObjectClass(data);
  if (dataClass == NULL) {
    if (_debug>1) MFprintf("addToList: No more memory.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("addToList: dataClass was set.\n");
  }
  */

  if (javaList != NULL) {
    if (_debug>1) MFprintf("addToList: javaList available.\n");

    hClass = env->GetObjectClass(javaList);                              // Use the global reference

    if (hClass == NULL) {
      if (_debug>1) MFprintf("addToList: No more memory.\n");
      return JNI_FALSE;
    } else {
      if (_debug>1) MFprintf("addToList: javaList available.\n");
    }

    //if (_debug>1) MFprintf("addToList: Name of the class: %s\n", JClass::toString(env, hClass) );
  } else {
    if (_debug>1) MFprintf("addToList: javaList not available.\n");
    return JNI_FALSE;
  }

  if (_debug>1) MFprintf("addToList: before getting mid.\n");

  jmethodID mid = env->GetMethodID(hClass, "put", "(Ljava/lang/String;Ljava/lang/Object;)V");

  // Get the superclass of the object.

  if (mid == NULL) {
    if (_debug>1) MFprintf("addToList: could not find method put.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("addToList: addToList available.\n");
  }

  jstring argument = JSystem::NewPlatformString(env, name);
  if (_debug>1) MFprintf("addToList: after creating jstring. Now calling method addToList in javaList.\n");

  env->CallVoidMethod(javaList, mid, argument, data);
  env->DeleteLocalRef(argument);
  env->DeleteLocalRef(hClass);
  if (_debug>1) MFprintf("addToList: after calling method.\n");

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("addToList: something went wrong while running the java method.\n");
    env->ExceptionClear();
    return JNI_FALSE;
  }

 return JNI_TRUE;
}

/** HO_removeObject
 * @param env         The ubiquitous pointer to JNI.
 * @param name The representative name that was given to the object.
 */
void JSystem::HO_removeObject(JNIEnv *env, char* name) {

  jthrowable excp;
  jclass hClass = NULL;

  if (_debug>1) MFprintf("HO_removeFromList: started.\n");

  if (javaList != NULL) {
    hClass = env->GetObjectClass(javaList);                              // Use the global reference
  } else {
    if (_debug>1) MFprintf("HO_removeFromList: javaList not available.\n");
    return;
  }

  if (hClass == NULL) {
    if (_debug>1) MFprintf("HO_removeFromList: No more memory.\n");
    return;
  } else {
    if (_debug>1) MFprintf("HO_removeFromList: javaList available.\n");
  }

  jmethodID mid = env->GetMethodID(hClass, "remove", "(Ljava/lang/String;)V");

  if (mid == NULL) {
    if (_debug>1) MFprintf("HO_removeFromList: could not find method removeFromList.\n");
    return;
  } else {
    if (_debug>1) MFprintf("HO_removeFromList: removeFromList available.\n");
  }

  jstring argument = JSystem::NewPlatformString(env, name);
  if (_debug>1) MFprintf("HO_removeFromList: after creating jstring.\n");
  env->CallVoidMethod(javaList, mid, argument);
  env->DeleteLocalRef(argument);
  env->DeleteLocalRef(hClass);

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("HO_removeFromList: something went wrong while running the java method.\n");
    env->ExceptionClear();
    return;
  }
}

/** HO_removeObject
 * @param env         The ubiquitous pointer to JNI.
 * @param name The representative name that was given to the object.
 */
 /*
void JSystem::HO_replaceObject(JNIEnv *env, char* name, jobject data) {

  jthrowable excp;
  jclass hClass = NULL;

  if (_debug>1) MFprintf("HO_replaceObject: started.\n");

  if (javaList != NULL) {
    hClass = env->GetObjectClass(javaList);                              // Use the global reference
  } else {
    if (_debug>1) MFprintf("HO_replaceObject: javaList not available.\n");
    return;
  }

  if (hClass == NULL) {
    if (_debug>1) MFprintf("HO_replaceObject: No more memory.\n");
    return;
  } else {
    if (_debug>1) MFprintf("HO_replaceObject: javaList available.\n");
  }

  jmethodID mid = env->GetMethodID(hClass, "replaceObject", "(Ljava/lang/String;Ljava/lang/Object;)V");

  if (mid == NULL) {
    if (_debug>1) MFprintf("HO_replaceObject: could not find method replaceObject.\n");
    return;
  } else {
    if (_debug>1) MFprintf("HO_replaceObject: removeFromList available.\n");
  }

  jstring argument = JSystem::NewPlatformString(env, name);
  if (_debug>1) MFprintf("HO_replaceObject: after creating jstring.\n");
  env->CallVoidMethod(javaList, mid, argument, data);
  env->DeleteLocalRef(argument);
  env->DeleteLocalRef(hClass);

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("HO_replaceObject: something went wrong while running the java method.\n");
    env->ExceptionClear();
    return;
  }
}
*/

/** HO_clearList
 * @param env         The ubiquitous pointer to JNI.
 */
void JSystem::HO_clearList(JNIEnv *env) {

  jthrowable excp;
  jclass hClass = NULL;

  if (_debug>1) MFprintf("HO_clearList: started.\n");

  if (javaList != NULL) {
    hClass = env->GetObjectClass(javaList);                              // Use the global reference
  } else {
    if (_debug>1) MFprintf("HO_clearList: javaList not available.\n");
    return;
  }

  if (hClass == NULL) {
    if (_debug>1) MFprintf("HO_clearList: No more memory.\n");
    return;
  } else {
    if (_debug>1) MFprintf("HO_clearList: javaList available.\n");
  }

  jmethodID mid = env->GetMethodID(hClass, "clear", "()V");

  if (mid == NULL) {
    if (_debug>1) MFprintf("HO_clearList: could not find method removeFromList.\n");
    return;
  } else {
    if (_debug>1) MFprintf("HO_clearList: removeFromList available.\n");
  }

  env->CallVoidMethod(javaList, mid, NULL);
  env->DeleteLocalRef(hClass);

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("HO_clearList: something went wrong while running the java method.\n");
    env->ExceptionClear();
    return;
  }
}


/** HO_getSignature
 * @param env  The ubiquitous pointer to JNI.
 * @param name The representative name that was given to the object.
 * @return JNI_TRUE if everything went wrong, JNI_FALSE otherwise.
 */
char* JSystem::HO_getSignature(JNIEnv *env, char *name) {
  char *sigName;
  jthrowable excp;
  jclass hClass;
  jstring argument;
  jstring str;

  if (_debug>1) MFprintf("HO_getSignature: started with %s.\n", name);

  if (javaList != NULL) {
    hClass = env->GetObjectClass(javaList);                              // Use the global reference
  } else {
    if (_debug>1) MFprintf("HO_getSignature: javaList not available.\n");
    return JNI_FALSE;
  }

  if (hClass == NULL) {
    if (_debug>1) MFprintf("HO_getSignature: No more memory.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("HO_getSignature: javaList available.\n");
  }

  jmethodID mid = env->GetMethodID(hClass, "getSignature", "(Ljava/lang/String;)Ljava/lang/String;");

  if (mid == NULL) {
    if (_debug>1) MFprintf("HO_getSignature: could not find method removeFromList.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("HO_getSignature: getSignatureFromList available.\n");
  }

  argument = JSystem::NewPlatformString(env, name);
  if (_debug>1) MFprintf("HO_getSignature: after creating jstring.\n");

  str = (jstring)env->CallObjectMethod(javaList, mid, argument);

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("HO_getSignature: something went wrong while running the java method.\n");
    env->ExceptionClear();
    return NULL;
  }

  env->DeleteLocalRef(argument);
  env->DeleteLocalRef(hClass);

  if (str!=NULL) {
    sigName = JHelper::GetNativeChars(env, str);
    env->DeleteLocalRef(str);
    if (_debug>1) MFprintf("HO_getSignature: sigName=%s\n",sigName);
    return sigName;
  }

  return NULL; // If no mapping could be found.
}

/** HO_getClassname
 * @param env  The ubiquitous pointer to JNI.
 * @param name The representative name that was given to the object.
 * @return JNI_TRUE if everything went wrong, JNI_FALSE otherwise.
 */
char* JSystem::HO_getClassname(JNIEnv *env, char *name) {
  char *sigName;
  jthrowable excp;
  jclass hClass;
  jstring argument;
  jstring str;

  if (_debug>1) MFprintf("HO_getClassname: started with %s.\n", name);

  if (javaList != NULL) {
    hClass = env->GetObjectClass(javaList);                              // Use the global reference
  } else {
    if (_debug>1) MFprintf("HO_getClassname: javaList not available.\n");
    return JNI_FALSE;
  }

  if (hClass == NULL) {
    if (_debug>1) MFprintf("HO_getClassname: No more memory.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("HO_getClassname: javaList available.\n");
  }

  jmethodID mid = env->GetMethodID(hClass, "getClassname", "(Ljava/lang/String;)Ljava/lang/String;");

  if (mid == NULL) {
    if (_debug>1) MFprintf("HO_getClassname: could not find method getClassname.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("HO_getClassname: getSignatureFromList available.\n");
  }

  argument = JSystem::NewPlatformString(env, name);
  if (_debug>1) MFprintf("HO_getClassname: after creating jstring.\n");

  str = (jstring)env->CallObjectMethod(javaList, mid, argument);

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("HO_getClassname: something went wrong while running the java method.\n");
    env->ExceptionClear();
    return NULL;
  }

  env->DeleteLocalRef(argument);
  env->DeleteLocalRef(hClass);

  if (str!=NULL) {
    sigName = JHelper::GetNativeChars(env, str);
    env->DeleteLocalRef(str);
    if (_debug>1) MFprintf("HO_getClassname: sigName=%s\n",sigName);
    return sigName;
  }

  return NULL; // If no mapping could be found.
}

/** HO_getObject
 * @param env  The ubiquitous pointer to JNI.
 * @param name The representative name that was given to the object.
 * @return The object stored under the given name.
 */
jobject JSystem::HO_getObject(JNIEnv *env, char *name) {
  jthrowable excp;
  jclass hClass;
  jstring objName;
  jobject result1;

  if (_debug>1) MFprintf("getObject: started with %s.\n", name);

  if (javaList != NULL) {
    hClass = env->GetObjectClass(javaList);                              // Use the global reference
  } else {
    if (_debug>1) MFprintf("getObject: javaList not available.\n");
    return NULL;
  }

  //char *tmpClassName = JClass::toString(env, hClass);
  //if (_debug>1) MFprintf("getObject: Classname:\n", tmpClassName);
  //MFcfree(tmpClassName);

  if (hClass == NULL) {
    if (_debug>1) MFprintf("getObject: No more memory.\n");
    return NULL;
  } else {
    if (_debug>1) MFprintf("getObject: javaList available.\n");
  }

  jmethodID mid = env->GetMethodID(hClass, "getObject", "(Ljava/lang/String;)Ljava/lang/Object;");

  if (mid == NULL) {
    if (_debug>1) MFprintf("getObject: could not find method getObject.\n");
    return JNI_FALSE;
  } else {
    if (_debug>1) MFprintf("getObject: getObject available.\n");
  }

  objName = JSystem::NewPlatformString(env, name);
  if (_debug>1) MFprintf("getObject: after creating jstring, before calling method.\n");

  result1 = (jobject) env->CallObjectMethod(javaList, mid, objName);
  env->DeleteLocalRef(objName);
  env->DeleteLocalRef(hClass);
  if (result1 == NULL)
  {
    if (_debug>1) MFprintf("getObject: could not find the requested class.\n");
    return NULL;
  }
  if (_debug>1) MFprintf("getObject: Now returning...\n");

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("getObject: something went wrong while running the java method.\n");
    env->ExceptionClear();
    return NULL;
  }

  return result1;
}

/** HO_getList
 * @param env  The ubiquitous pointer to JNI.
 * @param name The representative name that was given to the object.
 * @return JNI_TRUE if everything went wrong, JNI_FALSE otherwise.
 */
MTcell JSystem::HO_getList(JNIEnv *env, jboolean showInJava) {
  jthrowable excp;
  jclass hClass;

  if (_debug>1) MFprintf("getList: started.\n");

  if (javaList != NULL) {
    hClass = env->GetObjectClass(javaList);                              // Use the global reference
  } else {
    if (_debug>1) MFprintf("getList: javaList not available.\n");
    return NULL;
  }

  if (hClass == NULL) {
    if (_debug>1) MFprintf("getList: No more memory.\n");
    return NULL;
  } else {
    if (_debug>1) MFprintf("getList: javaList available.\n");
  }

  jmethodID mid = env->GetMethodID(hClass, "getList", "(Z)[Ljava/lang/String;");

  if (mid == NULL) {
    if (_debug>1) MFprintf("getList: could not find method getList.\n");
    return NULL;
  } else {
    if (_debug>1) MFprintf("getList: showStoredObjects available.\n");
  }

  if (_debug>1) MFprintf("getList: calling showStoredObjects.\n");
  jobject retValue = env->CallObjectMethod(javaList, mid, showInJava);

  if (retValue!=NULL) {
    MTcell theList = JHelper::createMultiMuPADList(env, (jobjectArray) retValue, 100 + JAVA_STRING);
    //  JHelper::GetNativeChars(env, str);
    env->DeleteLocalRef(retValue);
    if (_debug>1) MFprintf("getList: theList=%s\n", MFexpr2text(theList));
    return theList;
  }

  if ((excp = env->ExceptionOccurred()) != NULL) {
    MFprintf("getList: something went wrong while running the java method.\n");
    env->ExceptionClear();
  }

  return MFcopy(MVnull);
}

/** getExceptionMessage
 * It returns the message and also removes it from stack.
 * @param env    The ubiquitous pointer to JNI.
 * @param throwObj The throwable object containing information about the exception.
 * @return The message connected to this exception.
 */
void JSystem::checkForException(JNIEnv *env) {
  if (_debug>1) MFprintf("printExceptionMessage: started.\n");
  jthrowable exc = env->ExceptionOccurred();
  if (exc == NULL) {
    // No exception
    return;
  }

  if (_debug>1) MFprintf("printExceptionMessage: getting class Exception.\n");

  if (jExceptionClass == NULL)
  {
    if (_debug>1) MFprintf("printExceptionMessage: jclass == NULL!.\n");
    env->ExceptionClear();
    return;
  }
  if (_debug>1) MFprintf("printExceptionMessage: creating message.\n");

  if (jExceptionID == NULL)
  {
    if (_debug>1) MFprintf("printExceptionMessage: getMsgID == NULL!.\n");
    env->ExceptionClear();
    return;
  }

  // Get the jstring version of the message
  if (_debug>1) MFprintf("printExceptionMessage: creating jstring.\n");
  jstring msg = (jstring) env->CallObjectMethod(exc, jExceptionID, NULL);
  if (msg == NULL)
  {
    if (showErrors == JNI_TRUE) MFprintf("Java method failed. Look at console for more details.\n");
    //env->ThrowNew(exc, "(from Java module:)");
    env->ExceptionDescribe();
    env->ExceptionClear();
    return;
  }

  if (_debug>1) MFprintf("printExceptionMessage: creating c-string.\n");
  char *cmsg = JHelper::GetNativeChars(env, msg);
  if (showErrors == JNI_TRUE) MFprintf("Java method failed. Look at console for more details.\nGot the following exception output from java:\n%s\n", cmsg);
  MFcfree(cmsg);
  env->DeleteLocalRef(msg);
  env->ExceptionDescribe();
  //env->ThrowNew(exc, "(from Java module:)");
  env->ExceptionClear();
}

void JSystem::InitEncodingFlag(JNIEnv *env) {
    jclass system;
    jmethodID getProperty;
    jstring fileEncoding;
    jstring value;
    const char* str;

    system = env->FindClass("java/lang/System");
    getProperty =
            env->GetStaticMethodID(system,
                                   "getProperty",
                                   "(Ljava/lang/String;)Ljava/lang/String;");
    fileEncoding = env->NewStringUTF("file.encoding");
    value = (jstring) env->CallStaticObjectMethod(system, getProperty, fileEncoding);
    if (value == NULL) {
        isUTF16 = JNI_FALSE;
        return;
    }
    str = env->GetStringUTFChars(value, JNI_FALSE);
    if (strcmp(str, "utf-16le") == 0)
        isUTF16 = JNI_TRUE;
    else
        isUTF16 = JNI_FALSE;
    env->ReleaseStringUTFChars(value, str);
    env->DeleteLocalRef(value);
    env->DeleteLocalRef(fileEncoding);
}

/*
 * Returns a new Java string object for the specified platform string.
 */
jstring JSystem::NewPlatformString(JNIEnv *env, char *s) {
    int len = strlen(s);
    jclass cls;
    jmethodID mid;
    jbyteArray ary;

    if (isUTF16)
        return env->NewStringUTF(s);

    NULL_CHECK0(cls = env->FindClass("java/lang/String"));
    NULL_CHECK0(mid = env->GetMethodID(cls, "<init>", "([B)V"));
    ary = env->NewByteArray(len);
    if (ary != 0) {
	jstring str = 0;
	env->SetByteArrayRegion(ary, 0, len, (jbyte *)s);
	if (!env->ExceptionOccurred()) {
	    str = (jstring) env->NewObject(cls, mid, ary);
	}
	env->DeleteLocalRef(ary);
	return str;
    }
    return 0;
}

/*
 * Returns a new Java string object for the specified platform string.
 */
void JSystem::garbageCollect(JNIEnv *env) {
  if (_debug>1) MFprintf("garbageCollect: started.\n");

  jclass hClass = env->FindClass("java/lang/System");
  if (hClass == NULL) {
    if (_debug>1) MFprintf("garbageCollect: Class System not found.\n");
    return;
  } else {
    if (_debug>1) MFprintf("garbageCollect: Class System found.\n");
  }

  jmethodID mid = env->GetStaticMethodID(hClass, "gc", "()V");
  if (mid == NULL) {
    if (_debug>1) MFprintf("garbageCollect: Method gc not found.\n");
    return;
  } else {
    if (_debug>1) MFprintf("garbageCollect: Method gc found.\n");
  }

  env->CallStaticVoidMethod(hClass, mid, NULL);
  JSystem::checkForException(env);
  env->DeleteLocalRef(hClass);
}

/*
 * Returns a new Java string object for the specified platform string.
 */
void JSystem::runFinalization(JNIEnv *env) {
  if (_debug>1) MFprintf("runFinalization: started.\n");

  jclass hClass = env->FindClass("java/lang/System");
  if (hClass == NULL) {
    if (_debug>1) MFprintf("runFinalization: Class System not found.\n");
    return;
  } else {
    if (_debug>1) MFprintf("runFinalization: Class System found.\n");
  }

  jmethodID mid = env->GetStaticMethodID(hClass, "runFinalization", "()V");
  if (mid == NULL) {
    if (_debug>1) MFprintf("runFinalization: Method runFinalization not found.\n");
    return;
  } else {
    if (_debug>1) MFprintf("runFinalization: Method runFinalization found.\n");
  }

  env->CallStaticVoidMethod(hClass, mid, NULL);
  JSystem::checkForException(env);
  env->DeleteLocalRef(hClass);
}
