//- ****************************************************************************
//-
//- Copyright 2009 National Technology & Engineering Solutions of Sandia, LLC
//- (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
//- Government retains certain rights in this software.
//-
//- BSD Open Source License
//- All rights reserved.
//-
//- Redistribution and use in source and binary forms, with or without
//- modification, are permitted provided that the following conditions are met:
//-
//-   1. Redistributions of source code must retain the above copyright notice,
//-      this list of conditions and the following disclaimer.
//-
//-   2. Redistributions in binary form must reproduce the above copyright
//-      notice, this list of conditions and the following disclaimer in the
//-      documentation and/or other materials provided with the distribution.
//-
//-   3. Neither the name of the copyright holder nor the names of its
//-      contributors may be used to endorse or promote products derived from
//-      this software without specific prior written permission.
//-
//- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
//- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//- POSSIBILITY OF SUCH DAMAGE.
//-
//- ****************************************************************************

/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile: pglJavaUtil.cc,v $
  Language:  C++
  Date:      $Date: 2013/05/04 19:41:48 $
  Version:   $Revision: 1.9 $

  MODIFIED FOR SANDIA NATIONAL LABS KNOWLEDGE BASE CLIENT GRID INTERFACE
  (GNEM PROJECT)  4/00


Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

// include stdmutex for borland
#ifdef __BORLANDC__
#include <stdmutex.h>
#endif

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <stdint.h>
#ifdef _INTEGRAL_MAX_BITS
#undef _INTEGRAL_MAX_BITS
#endif
#define _INTEGRAL_MAX_BITS 64


//#include "pglJNIObject.h"



#if defined(_WIN32) || defined(WIN32)
//***NOTE include windows.h or get error for "HANDLE"
#include <windows.h>
HANDLE pglJNIGlobalMutex = NULL;
#define PGLJAVA_GET_MUTEX() WaitForSingleObject(pglJNIGlobalMutex,INFINITE)
#define PGLJAVA_RELEASE_MUTEX() ReleaseMutex(pglJNIGlobalMutex)
//#include <mapiform.h>
#else

#ifdef PGLJAVA_USE_SPROC
// for SGI's
#include <abi_mutex.h>
abilock_t pglJNIGlobalMutex;
static void pglJNI_get_mutex() {
    static int inited = 0;
    if (!inited) {
        if (init_lock(&pgljavaGlobalMutex) < 0)
            perror("initializing mutex");
        inited = 1;
    }
    spin_lock(&pgljavaGlobalMutex);
}
static void pgljava_release_mutex() {
    if (release_lock(&pgljavaGlobalMutex) < 0)
        perror("releasing mutex");
}
#define PGLJAVA_GET_MUTEX()  pgljava_get_mutex()
#define PGLJAVA_RELEASE_MUTEX() pgljava_release_mutex()
#elif defined(__FreeBSD__) || defined(__linux__) || defined(sgi) || (defined(__APPLE__) && defined(__MACH__))
#include <pthread.h>
pthread_mutex_t pgljavaGlobalMutex;
#define PGLJAVA_GET_MUTEX()  pthread_mutex_lock(&pgljavaGlobalMutex)
#define PGLJAVA_RELEASE_MUTEX() pthread_mutex_unlock(&pgljavaGlobalMutex)
#else
// for solaris
#include <thread.h>
#include <synch.h>
mutex_t pgljavaGlobalMutex;
#define PGLJAVA_GET_MUTEX()  mutex_lock(&pgljavaGlobalMutex)
#define PGLJAVA_RELEASE_MUTEX() mutex_unlock(&pgljavaGlobalMutex)
#endif

#endif

#include "pglJavaUtil.h"

int pglJavaIdCount = 1;

//#define PGLJAVADEBUG


class pgljavaHashNode
{
public:
  pgljavaHashNode *next;
  void *key;
  void *value;
};


class pgljavaHashTable
{
public:
  pgljavaHashTable();
  pgljavaHashNode *(nodes[64]);
  void AddHashEntry(void *key,void *value);
  void *GetHashTableValue(void *key);
  void DeleteHashEntry(void *key);
};

pgljavaHashTable::pgljavaHashTable()
{
  int i;
  for (i = 0; i < 64; i++)
    {
    this->nodes[i] = NULL;
    }
}

pgljavaHashTable *pgljavaInstanceLookup = NULL;
pgljavaHashTable *pgljavaPointerLookup = NULL;
pgljavaHashTable *pgljavaTypecastLookup = NULL;


void pgljavaHashTable::AddHashEntry(void *key,void *value)
{
  pgljavaHashNode *pos;
  pgljavaHashNode *newpos;
  int loc;

  newpos = new pgljavaHashNode;
  newpos->key = key;
  newpos->value = value;
  newpos->next = NULL;

  loc = (((unsigned long)key) & 0x03f0) / 16;

  pos = this->nodes[loc];
  if (!pos)
    {
    this->nodes[loc] = newpos;
    return;
    }
  while (pos->next)
    {
    pos = pos->next;
    }
  pos->next = newpos;
}

void *pgljavaHashTable::GetHashTableValue(void *key)
{
  pgljavaHashNode *pos;
  int loc = (((unsigned long)key) & 0x03f0) / 16;

  pos = this->nodes[loc];

  if (!pos)
    {
    return NULL;
    }
  while ((pos)&&(pos->key != key))
    {
    pos = pos->next;
    }
  if (pos)
    {
    return pos->value;
    }
  return NULL;
}

void pgljavaHashTable::DeleteHashEntry(void *key)
{
  pgljavaHashNode *pos;
  pgljavaHashNode *prev = NULL;
  int loc = (((unsigned long)key) & 0x03f0) / 16;

  pos = this->nodes[loc];

  while ((pos)&&(pos->key != key))
    {
    prev = pos;
    pos = pos->next;
    }
  if (pos)
    {
    // we found this object
    if (prev)
      {
      prev->next = pos->next;
      }
    else
      {
      this->nodes[loc] = pos->next;
      }
    delete pos;
    }
}

JNIEXPORT int pglJavaGetId(JNIEnv *env,jobject obj)
{
  jfieldID id;
  int result;


  // Note from RWS: This fails with a segmentation fault if vtkId isn't
  // defined in the object.
  id = env->GetFieldID(env->GetObjectClass(obj),"vtkId","I");

  result = (int)env->GetIntField(obj,id);
  return result;
}



JNIEXPORT void pglJavaSetId(JNIEnv *env,jobject obj, int newVal)
{
  jfieldID id;
  jint jNewVal = (jint)newVal;

  id = env->GetFieldID(env->GetObjectClass(obj),"vtkId","I");

  env->SetIntField(obj,id,jNewVal);
}



JNIEXPORT void pglJavaRegisterCastFunction(JNIEnv *env,
                       jobject obj,
                       int id, void *tcFunc)
{
  PGLJAVA_GET_MUTEX();
#ifdef PGLJAVADEBUG
  if (id == 0) {
    pglJavaGenericWarningMacro("RegisterCastFunction: Try to add a CastFuction to a unregistered function");
  }
#endif
  pgljavaTypecastLookup->AddHashEntry((void *)(intptr_t)id,tcFunc);
  PGLJAVA_RELEASE_MUTEX();
}



// add an object to the hash table
JNIEXPORT int pglJavaRegisterNewObject(JNIEnv *env, jobject obj, void *ptr)
{

  if (!pgljavaInstanceLookup) // first call ?
    {
    pgljavaInstanceLookup = new pgljavaHashTable();
    pgljavaPointerLookup = new pgljavaHashTable();
    pgljavaTypecastLookup = new pgljavaHashTable();

#if defined(_WIN32) || defined(WIN32)
    pglJNIGlobalMutex = CreateMutex(NULL, FALSE, NULL);
#endif
    }


PGLJAVA_GET_MUTEX();


#ifdef PGLJAVADEBUG
  pglJavaGenericWarningMacro("RegisterNewObject: Adding an object to hash ptr = " << ptr);
#endif


  // lets make sure it isn't already there
  int id= 0;



  if ((id= pglJavaGetId(env,obj)))
    {

#ifdef PGLJAVADEBUG
    pglJavaGenericWarningMacro("RegisterNewObject: Attempt to add an object to the hash when one already exists!!!");
#endif

    PGLJAVA_RELEASE_MUTEX();

    return id;

    }


  // get a unique id for this object
  // just use pglJavaIdCount and then increment
  // to handle loop around make sure the id isn't currently in use
  while (pgljavaInstanceLookup->GetHashTableValue((void *)(intptr_t)pglJavaIdCount))
    {
    pglJavaIdCount++;
    if (pglJavaIdCount > 268435456) pglJavaIdCount = 1;
    }
  id= pglJavaIdCount;
  pgljavaInstanceLookup->AddHashEntry((void *)(intptr_t)pglJavaIdCount,ptr);
  pgljavaPointerLookup->AddHashEntry(ptr,(void *)env->NewGlobalRef(obj));

  pglJavaSetId(env,obj,pglJavaIdCount);

#ifdef PGLJAVADEBUG
  pglJavaGenericWarningMacro("RegisterNewObject: Added object to hash id= " << pglJavaIdCount << " " << ptr);
#endif
  pglJavaIdCount++;
  PGLJAVA_RELEASE_MUTEX();
  return id;


  printf("Done in pglJavaRegisterNewObject.\n\n");
}



// should we delete this object
JNIEXPORT void pglJavaDeleteObject(JNIEnv *env,jobject obj)
{
  int id = pglJavaGetId(env,obj);

  PGLJAVA_GET_MUTEX();

#ifdef PGLJAVADEBUG
  pglJavaGenericWarningMacro("DeleteObject: Deleting id = " << id);
#endif
  pglJavaDeleteObjectFromHash(env, id);
  PGLJAVA_RELEASE_MUTEX();
}


// delete an object from the hash
// doesn't need a mutex because it is only called from within
// the above func which does have a mutex
JNIEXPORT void pglJavaDeleteObjectFromHash(JNIEnv *env, int id)
{
  void *ptr;
  void *vptr;

  ptr = pgljavaInstanceLookup->GetHashTableValue((void *)(intptr_t)id);
  if (!ptr)
    {
#ifdef PGLJAVADEBUG
    pglJavaGenericWarningMacro("DeleteObjectFromHash: Attempt to delete an object that doesn't exist!");
#endif
    return;
    }
  pgljavaInstanceLookup->DeleteHashEntry((void *)(intptr_t)id);
  pgljavaTypecastLookup->DeleteHashEntry((void *)(intptr_t)id);
  vptr = pgljavaPointerLookup->GetHashTableValue(ptr);
  env->DeleteGlobalRef((jobject)vptr);
  pgljavaPointerLookup->DeleteHashEntry(ptr);
}

JNIEXPORT jobject pglJavaGetObjectFromPointer(void *ptr)
{
  jobject obj;

#ifdef PGLJAVADEBUG
  pglJavaGenericWarningMacro("GetObjectFromPointer: Checking into pointer " << ptr);
#endif
  obj = (jobject)pgljavaPointerLookup->GetHashTableValue((jobject *)ptr);
#ifdef PGLJAVADEBUG
  pglJavaGenericWarningMacro("GetObjectFromPointer: Checking into pointer " << ptr << " obj = " << obj);
#endif
  return obj;
}

JNIEXPORT void *pglJavaGetPointerFromObject(JNIEnv *env, jobject obj, const string& result_type)
{
  void *ptr;
  void *(*command)(void *, const string&);
  int id;

  id = pglJavaGetId(env,obj);
  PGLJAVA_GET_MUTEX();
  ptr = pgljavaInstanceLookup->GetHashTableValue((void *)(intptr_t)id);
  command = (void *(*)(void *, const string&))pgljavaTypecastLookup->GetHashTableValue((void *)(intptr_t)id);
  PGLJAVA_RELEASE_MUTEX();

#ifdef PGLJAVADEBUG
  pglJavaGenericWarningMacro("GetPointerFromObject: Checking into id " << id << " ptr = " << ptr);
#endif

  if (!ptr)
    {
    return (void*) NULL;
    }

  void* res;
  if ((res= command(ptr,result_type)))
    {
#ifdef PGLJAVADEBUG
      //pglJavaGenericWarningMacro("GetPointerFromObject: Got id= " << id << " ptr= " << ptr << " " << result_type);
#endif
    return res;
    }
  else
    {
      //pglJavaGenericWarningMacro("GetPointerFromObject: pgljava bad argument, type conversion failed.");
    return (void*) NULL;
    }
}

/*
JNIEXPORT jobject pglJavaCreateNewJavaStubForObject(JNIEnv *env, pglJNIObject* obj)
{
  char fullname[512];
  const char* classname= obj->GetClassName();
  fullname[0]= 'v';
  fullname[1]= 't';
  fullname[2]= 'k';
  fullname[3]= '/';
  strcpy(&fullname[4], classname);
  return pglJavaCreateNewJavaStub(env, fullname, (void*)obj);
}

JNIEXPORT jobject pglJavaCreateNewJavaStub(JNIEnv *env, const char* fullclassname, void* obj)
{
  jclass cl= env->FindClass(fullclassname);
  if (!cl) { return NULL; }

  jobject stub= env->NewObject(cl, env->GetMethodID(cl, "<init>","(I)V"), (int)0 );
  pglJavaRegisterNewObject(env, stub, obj);
  env->CallVoidMethod(stub, env->GetMethodID(cl, "PGLCastInit", "()V"));
  return stub;
}
*/



//
// copy the contents of a java double array to a double array
// Written by sballar@sandia.gov February 25, 2013
//
JNIEXPORT void javaMakeArrayOfDoubleFromJArray(JNIEnv *env, jdoubleArray javaArray, double doubleArray[], const int& maxSize, int& size)
{
    int i;
    jdouble *array;


    array = env->GetDoubleArrayElements(javaArray, NULL);
    size = env->GetArrayLength (javaArray);

    if (size > maxSize)
        size = -1;
    else
    {
        for (i = 0; i < size; i++)
            doubleArray[i] = array[i];

    }

    env->ReleaseDoubleArrayElements(javaArray,array,0);
}


//
// copy the contents of a java double array to a double vector
// and return the double vector
//
JNIEXPORT void javaMakeVectorOfDoubleFromJArray(JNIEnv *env, jdoubleArray javaArray, vector<double>& doubleVector)
{
  int i, arrayLength;
  jdouble *array;


  array = env->GetDoubleArrayElements(javaArray, NULL);
  arrayLength = env->GetArrayLength (javaArray);
  doubleVector.reserve(arrayLength);
  doubleVector.clear();


  // copy the data
  for (i = 0; i < arrayLength; i++)
  {
    doubleVector.push_back(array[i]);
  }


  env->ReleaseDoubleArrayElements(javaArray,array,0);
}



//
// copy the contents of a java Integer array to an integer vector
// and return the int vector
//
JNIEXPORT void javaMakeVectorOfIntFromJArray(JNIEnv *env, jintArray javaArray, vector<int>& intVector)
{
  int i, arrayLength;
  jint *array;


  array = env->GetIntArrayElements(javaArray, NULL);
  arrayLength = env->GetArrayLength (javaArray);
  intVector.reserve(arrayLength);
  intVector.clear();


  // copy the data
  for (i = 0; i < arrayLength; i++)
  {
    intVector.push_back(array[i]);
  }


  env->ReleaseIntArrayElements(javaArray,array,0);
}


//
// copy the contents of a java boolean array to an boolean vector
// and return the bool vector
//
JNIEXPORT void javaMakeVectorOfBoolFromJArray(JNIEnv *env, jbooleanArray javaArray, vector<bool>& boolVector)
{
  int i, arrayLength;
  jboolean *array;


  array = env->GetBooleanArrayElements(javaArray, NULL);
  arrayLength = env->GetArrayLength (javaArray);
  boolVector.reserve(arrayLength);
  boolVector.clear();


  // copy the data
  for (i = 0; i < arrayLength; i++)
  {
    boolVector.push_back(array[i]);
  }


  env->ReleaseBooleanArrayElements(javaArray,array,0);
}

//
// copy the contents of a constant double vector reference to a java
// double array and return the java double array
//
JNIEXPORT jarray javaMakeJArrayOfDoubleFromVector(JNIEnv *env, const vector<double>& doubleVector)
{
  jdoubleArray ret;
  int i;
  jdouble *array;

  ret = env->NewDoubleArray(doubleVector.size());
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetDoubleArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < (int)doubleVector.size(); i++)
    {
    array[i] = doubleVector[i];
    }

  env->ReleaseDoubleArrayElements(ret,array,0);
  return ret;
}

//
// copy the contents of a constant float vector reference to a java
// float array and return the java float array
//
JNIEXPORT jarray javaMakeJArrayOfFloatFromVector(JNIEnv *env, const vector<float>& floatVector)
{
  jfloatArray ret;
  int i;
  jfloat *array;

  ret = env->NewFloatArray(floatVector.size());
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetFloatArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < (int)floatVector.size(); i++)
    {
    array[i] = floatVector[i];
    }

  env->ReleaseFloatArrayElements(ret,array,0);
  return ret;
}

//
// copy the contents of a constant int vector reference to a java
// int array and return the java int array
//
JNIEXPORT jarray javaMakeJArrayOfIntFromVector(JNIEnv *env, const vector<int>& intVector)
{
  jintArray ret;
  int i;
  jint *array;

  ret = env->NewIntArray(intVector.size());
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetIntArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < (int)intVector.size(); i++)
    {
    array[i] = intVector[i];
    }

  env->ReleaseIntArrayElements(ret,array,0);
  return ret;
}

//
// copy the contents of a constant bool vector reference to a java
// boolean array and return the java boolean array
//
JNIEXPORT jarray javaMakeJArrayOfBoolFromVector(JNIEnv *env, const vector<bool>& boolVector)
{
  jbooleanArray ret;
  int i;
  jboolean *array;

  ret = env->NewBooleanArray(boolVector.size());
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetBooleanArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < (int)boolVector.size(); i++)
    {
    array[i] = boolVector[i];
    }

  env->ReleaseBooleanArrayElements(ret,array,0);
  return ret;
}

//
// copy the contents of a constant string vector reference to a java
// String array and return the java String array
//
JNIEXPORT jobjectArray javaMakeJArrayOfStringFromVector(JNIEnv *env, const vector<string>& stringVector)
{
  jobjectArray objArray;
  int i;
  //jstring *array;
  jclass stringClass;

  stringClass = env->FindClass("java/lang/String");

  objArray = env->NewObjectArray(stringVector.size(), stringClass,
                            env->NewStringUTF(""));
  if (objArray == 0)
  {
    // should throw an exception here
    return 0;
  }


  // copy the data
  for (i = 0; i < (int)stringVector.size(); i++)
  {
    env->SetObjectArrayElement(objArray, i,
            env->NewStringUTF(stringVector[i].c_str()));
  }

  return objArray;
}




JNIEXPORT jarray pglJavaMakeJArrayOfDoubleFromDouble(JNIEnv *env, double *ptr, int size)
{
  jdoubleArray ret;
  int i;
  jdouble *array;

  ret = env->NewDoubleArray(size);
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetDoubleArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < size; i++)
    {
    array[i] = ptr[i];
    }

  env->ReleaseDoubleArrayElements(ret,array,0);
  return ret;
}



JNIEXPORT jarray pglJavaMakeJArrayOfDoubleFromDouble(JNIEnv *env, const double *ptr, int size)
{
  jdoubleArray ret;
  int i;
  jdouble *array;

  ret = env->NewDoubleArray(size);
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetDoubleArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < size; i++)
    {
    array[i] = ptr[i];
    }

  env->ReleaseDoubleArrayElements(ret,array,0);
  return ret;
}


JNIEXPORT jarray pglJavaMakeJArrayOfDoubleFromFloat(JNIEnv *env, float *ptr, int size)
{
  jdoubleArray ret;
  int i;
  jdouble *array;

  ret = env->NewDoubleArray(size);
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetDoubleArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < size; i++)
    {
    array[i] = ptr[i];
    }

  env->ReleaseDoubleArrayElements(ret,array,0);
  return ret;
}

JNIEXPORT jarray pglJavaMakeJArrayOfIntFromInt(JNIEnv *env, int *ptr, int size)
{
  jintArray ret;
  int i;
  jint *array;

  ret = env->NewIntArray(size);
  if (ret == 0)
    {
    // should throw an exception here
    return 0;
    }

  array = env->GetIntArrayElements(ret,NULL);

  // copy the data
  for (i = 0; i < size; i++)
    {
    array[i] = ptr[i];
    }

  env->ReleaseIntArrayElements(ret,array,0);
  return ret;
}

JNIEXPORT char *pglJavaUTFToChar(JNIEnv *env, jstring in)
{
  char *result;
  const char *inBytes;
  int length, i;
  int resultLength = 1;

  length = env->GetStringUTFLength(in);
  inBytes = env->GetStringUTFChars(in,NULL);

  for (i = 0; i < length; i++)
    {
    if (((int)inBytes[i] >= 0)&&((int)inBytes[i] < 128 )) resultLength++;
    }
  result = new char [resultLength];

  resultLength = 0; // the 0 versus 1 up above is on purpose
  for (i = 0; i < length; i++)
    {
    if (((int)inBytes[i] >= 0)&&((int)inBytes[i] < 128 ))
      {
      result[resultLength] = inBytes[i];
      resultLength++;
      }
    }
  result[resultLength] = '\0';
  env->ReleaseStringUTFChars(in,inBytes);
  return result;
}

JNIEXPORT void pglJavaUTFToString(JNIEnv *env, jstring in, string& str)
{
  const char *inBytes;
  int length, i;

  // get the java string

  length = env->GetStringUTFLength(in);
  inBytes = env->GetStringUTFChars(in,NULL);

  // find all bytes less than 128 and append to string

  str.clear();
  str.reserve(length);
  for (i = 0; i < length; i++)
  {
    if (((int)inBytes[i] >= 0) && ((int)inBytes[i] < 128 )) str.push_back(inBytes[i]);
  }

  // release string and exit

  env->ReleaseStringUTFChars(in,inBytes);
}

JNIEXPORT jstring pglJavaMakeJavaString(JNIEnv *env, const char *in)
{
  if (!in) {
    return env->NewStringUTF("");
  } else {
    return env->NewStringUTF(in);
  }
}


JNIEXPORT jstring pglJavaMakeJavaString(JNIEnv *env, string in)
{
  if (!in.length()) {
    return env->NewStringUTF("");
  } else {
    return env->NewStringUTF(in.c_str());
  }
}



//**jcp this is the callback inteface stub for Java. no user parms are passed
//since the callback must be a method of a class. We make the rash assumption
//that the <this> pointer will anchor any required other elements for the
//called functions. - edited by km
JNIEXPORT void pglJavaVoidFunc(void* f)
{
  pglJavaVoidFuncArg *iprm = (pglJavaVoidFuncArg *)f;
  // make sure we have a valid method ID
  if (iprm->mid)
    {
    JNIEnv *e;
    // it should already be atached
#ifdef JNI_VERSION_1_2
    iprm->vm->AttachCurrentThread((void **)(&e),NULL);
#else
    iprm->vm->AttachCurrentThread((JNIEnv_**)(&e),NULL);
#endif
    e->CallVoidMethod(iprm->uobj,iprm->mid,NULL);
    }
}

JNIEXPORT void pglJavaVoidFuncArgDelete(void* arg)
{
  pglJavaVoidFuncArg *arg2;

  arg2 = (pglJavaVoidFuncArg *)arg;

  JNIEnv *e;
  // it should already be atached
#ifdef JNI_VERSION_1_2
  arg2->vm->AttachCurrentThread((void **)(&e),NULL);
#else
  arg2->vm->AttachCurrentThread((JNIEnv_**)(&e),NULL);
#endif
  // free the structure
  e->DeleteGlobalRef(arg2->uobj);

  delete arg2;
}

jobject pglJavaExportedGetObjectFromPointer(void *ptr)
{
    return pglJavaGetObjectFromPointer(ptr);
}

void* pglJavaExportedGetPointerFromObject(JNIEnv *env,jobject obj, char *result_type)
{
    return pglJavaGetPointerFromObject(env, obj, result_type);
}
