/* **************************************************************************

  $Archive:  $
  $Revision: $
  $Modtime:  $

  Copyright (c) 1997 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/
#include <sys_api.h>
#include "com_novell_service_jncpv2_clx_ClxJNI.h"
#include "CLXJNI.h"
#include "jncp.h"
#include <jni.h>

#ifdef N_PLAT_NLM
#include "nwadv.h"
#include "nwthread.h"
nint32 NLMHandle;
#else
HINSTANCE inst;
#endif

CLXFunctionTable ClxFuncTable;
char *CLXSymbols[1] = { "NWCCFragmentRequest"};

//do not call this function from DLLMain. LoadLibrary is not safe to call
void __InitCLXJNI(void)
{
   #ifdef N_PLAT_NLM
   NLMHandle = GetNLMHandle();
   ClxFuncTable.NWCCFragmentRequest = (NWCCFragmentRequest_fp)ImportSymbol(NLMHandle, CLXSymbols[0]);
   #else
   inst = LoadLibrary("clxwin32.dll");
   ClxFuncTable.NWCCFragmentRequest = (NWCCFragmentRequest_fp)GetProcAddress(inst, CLXSymbols[0]);
   #endif
}

//do not call this function from DLLMain. FreeLibrary is not safe to call
void __CleanupCLXJNI(void)
{
   #ifdef N_PLAT_NLM
   if(ClxFuncTable.NWCCFragmentRequest != NULL)
      UnimportSymbol(NLMHandle, CLXSymbols[0]);
   #else
      FreeLibrary(inst); //not safe to call FreeLibrary from DLLMain
   #endif
}

JNIEXPORT jint JNICALL
Java_com_novell_service_jncpv2_clx_ClxJNI_NWCCFragmentRequest
(
   JNIEnv *env,
   jclass obj,
   jint connHandle,
   jint function,
   jint verb,
   jint reserved,
   jobjectArray reqFragsArray,
   jobjectArray replyFragsArray
)
{
   NWRCODE ccode = 0xABCD; //Magic Number indicates problems. Reassigned on func call
   char *message;
   nuint numReqFrags, numReplyFrags;
   nuint x, skipRestOfReleases = 0, replyLen;
   NWCCFrag *reqFrags, *replyFrags;
   NWCCFrag *lockedReqFrags, *lockedReplyFrags;
   
   if(ClxFuncTable.NWCCFragmentRequest == NULL)
   {
      message = "Problem in ClxJNI_NWCCFragmentRequest. __InitCLXJNI() failed";
      goto FATAL_ERROR;
   }

   numReqFrags = (*env)->GetArrayLength(env, reqFragsArray);
   numReplyFrags = (*env)->GetArrayLength(env, replyFragsArray);
   
   lockedReqFrags = reqFrags = sysMalloc(sizeof(NWCCFrag) * numReqFrags);
   lockedReplyFrags = replyFrags = sysMalloc(sizeof(NWCCFrag) * numReplyFrags);
   if(NULL == reqFrags || NULL == replyFrags)
      goto FREE;

   #ifdef N_PLAT_NLM
   if(_usingAliasFunctions)
   {
      lockedReqFrags = (*_aliasFunctions[0])((nptr) reqFrags, (size_t) sizeof(NWCCFrag) * numReqFrags);
      lockedReplyFrags = (*_aliasFunctions[0])((nptr) replyFrags, (size_t) sizeof(NWCCFrag) * numReplyFrags);
      if(NULL == lockedReqFrags || NULL == lockedReplyFrags)
         goto UNLOCK_FREE;
   }
   #endif
   
   for(x=0; x<numReqFrags; x++)
   {
      NWCCFrag *frag = lockedReqFrags + x;
      jbyteArray arr = (*env)->GetObjectArrayElement(env, reqFragsArray, x);
      (*frag).length = (*env)->GetArrayLength(env, arr);
      (*frag).address = (*env)->GetByteArrayElements(env, arr, NULL);
      if((*frag).address == NULL)
         goto RELEASE_UNLOCK_FREE;
   }

   for(x=0; x<numReplyFrags; x++)
   {
      NWCCFrag *frag = lockedReplyFrags + x;
      jbyteArray arr = (*env)->GetObjectArrayElement(env, replyFragsArray, x);
      (*frag).length = (*env)->GetArrayLength(env, arr);
      (*frag).address = (*env)->GetByteArrayElements(env, arr, NULL);
      if((*frag).address == NULL)
         goto RELEASE_UNLOCK_FREE;
   }

   ccode = (ClxFuncTable.NWCCFragmentRequest)(connHandle, function, verb, reserved,
      numReqFrags, reqFrags, numReplyFrags, replyFrags, &replyLen);

   RELEASE_UNLOCK_FREE:
   for(x=0; x<numReqFrags && !skipRestOfReleases; x++)
   {
      NWCCFrag *frag = lockedReqFrags + x;
      if(frag->address != NULL)
      {
         jbyteArray arr = (*env)->GetObjectArrayElement(env, reqFragsArray, x);
         (*env)->ReleaseByteArrayElements(env, arr, (*frag).address, JNI_ABORT); //we dont care if copy
      }
      else
         skipRestOfReleases = 1; //once one is null the rest are bogus.
   }

   for(x=0; x<numReplyFrags && !skipRestOfReleases; x++)
   {
      NWCCFrag *frag = lockedReplyFrags + x;
      if((*frag).address != NULL)
      {
         jbyteArray arr = (*env)->GetObjectArrayElement(env, replyFragsArray, x);
         (*env)->ReleaseByteArrayElements(env, arr, (*frag).address, 0); //we want copied back
      }
      else
         skipRestOfReleases = 1; //once one is null the rest are bogus.
   }

   #ifdef N_PLAT_NLM
   UNLOCK_FREE:
   if (_usingAliasFunctions)
   {
      if(NULL != lockedReqFrags)
         (*_aliasFunctions[1])((nptr) lockedReqFrags, (size_t) sizeof(NWCCFrag) * numReqFrags);
      if(NULL != lockedReplyFrags)
         (*_aliasFunctions[1])((nptr) lockedReplyFrags, (size_t) sizeof(NWCCFrag) * numReplyFrags);
   }
   #endif

   FREE:
   if(reqFrags != NULL)
      sysFree(reqFrags);
   if(replyFrags != NULL)
      sysFree(replyFrags);
   
   if(ccode == 0)  //sucessfull return.
      return replyLen;

   // If Memory problems or NWCCFragmentRequest returned nonzero
   {
   jclass class;
   jmethodID mid;
   jobject obj;
   message = "Problem throwing exception in ClxJNI_NWCCFragmentRequest.";

   class = (*env)->FindClass(env, "com/novell/service/jncp/NSIExceptionBuilder");
   if(NULL == class)
      goto FATAL_ERROR;
   mid = (*env)->GetStaticMethodID(env, class, "build", "(I)Lcom/novell/service/jncp/NSIException;");
   if(NULL == mid)
      goto FATAL_ERROR;
   obj = (*env)->CallStaticObjectMethod(env, class, mid, ccode);
   if(!(*env)->Throw(env, obj))
      return 0; //Exception was thrown so return code is irrelevant.
      
   FATAL_ERROR:
   (*env)->FatalError(env, message);
   return 0; //This line will never be hit. FatalError() does not return.
   }
}
