/*
 * File         : .c
 * Headerfile   : .h 
 * Author       : SungHoon Ko, Xinying Li (contributions from MAEDA Atusi)
 * Created      : Thu Apr  9 12:22:15 1998
 * Revision     : $Revision: 1.10 $
 * Updated      : $Date: 1999/09/16 02:50:10 $
 * Copyright: Northeast Parallel Architectures Center
 *            at Syracuse University 1998
 */

#include <stdio.h>
#include <string.h>
#include <mpi.h>
#include "mpi_MPI.h"

int len = 0;
char** sargs = 0;

#define PHASE 1			/* Declare variables. */
#include "initID.h"

/*
 * Class:     mpi_MPI
 * Method:    InitNative
 * Signature: ([Ljava/lang/String;)[Ljava/lang/String;
 */
JNIEXPORT jobjectArray JNICALL Java_mpi_MPI_InitNative
    (JNIEnv *env, jclass obj, jobjectArray argv)
{
  jsize i;
  jstring jc;
  jclass string;
  jobject value;

  len = (*env)->GetArrayLength(env,argv);
  sargs = (char**)calloc(len+1, sizeof(char*));
  /* C binding may not look at argv[0].
  sargs[0] = "mpiJava"; */
  for (i = 0; i < len; i++) {
    const char *arg;

    jc = (jstring)(*env)->GetObjectArrayElement(env, argv, i);
    arg = (*env)->GetStringUTFChars(env, jc, NULL);
    sargs[i] = (char*)malloc((*env)->GetStringUTFLength(env, jc) + 1);
    strcpy(sargs[i], arg);
    (*env)->ReleaseStringUTFChars(env, jc, arg);
  }

  MPI_Init(&len, &sargs);

# undef PHASE
# define PHASE 2		/* Initialize variables */
# include "initID.h"

  string = (*env)->FindClass(env, "java/lang/String");
  value = (*env)->NewObjectArray(env, len, string, NULL);
  for (i = 0; i < len; i++) {
    jc = (*env)->NewStringUTF(env, sargs[i]);
    (*env)->SetObjectArrayElement(env, value, i, jc);
  }
  return value;
}                                                   

/*
 * Class:     mpi_MPI
 * Method:    Finalize
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_mpi_MPI_Finalize
  (JNIEnv *env, jclass obj) {
  int i;

  MPI_Finalize();

# undef PHASE
# define PHASE 3		/* Release variables. */
# include "initID.h"

  /* shko: Do not free sargs.
     sargs might be changed after MPI_Init called. */
  /*
  for (i=0; i<len; i++)
    free(sargs[i]);
  free(sargs);     
  */                       
}
                                             
/*
 * Class:     mpi_MPI
 * Method:    Get_processor_name
 * Signature: ([B)I
 */
JNIEXPORT jint JNICALL Java_mpi_MPI_Get_1processor_1name
  (JNIEnv *env, jclass obj, jbyteArray buf)
{
  int len;
  jboolean isCopy; 
  MPI_Get_processor_name((char*)((*env)->GetByteArrayElements(env,buf,&isCopy)),&len); 
  return len;
}

/*
 * Class:     mpi_MPI
 * Method:    Wtime
 * Signature: ()D
 */
JNIEXPORT jdouble JNICALL Java_mpi_MPI_Wtime
  (JNIEnv *env, jclass jthis)
{
  /*double t;
  t=MPI_Wtime();
  printf("ttttttt = %lf \n",t);
  return t;*/

  return MPI_Wtime();
}

/*
 * Class:     mpi_MPI
 * Method:    Wtick
 * Signature: ()D
 */
JNIEXPORT jdouble JNICALL Java_mpi_MPI_Wtick
  (JNIEnv *env, jclass jthis)
{
	return MPI_Wtick();
}

/*
 * Class:     mpi_MPI
 * Method:    Initialized
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_mpi_MPI_Initialized
  (JNIEnv *env, jclass jthis)
{
	int flag;
	MPI_Initialized(&flag);
	if(flag==0)
		return JNI_FALSE;
	else
		return JNI_TRUE;
}

/*
 * Class:     mpi_MPI
 * Method:    Buffer_attach_native
 * Signature: ([B)V
 */
JNIEXPORT void JNICALL Java_mpi_MPI_Buffer_1attach_1native
  (JNIEnv *env, jclass jthis, jbyteArray buf)
{
  jboolean isCopy;

  int size=(*env)->GetArrayLength(env,buf);
  /*char* bufptr = (*env)->GetByteArrayElements(env,buf,&isCopy) ;*/
  jbyte* bufptr = (*env)->GetByteArrayElements(env,buf,&isCopy) ;

  MPI_Buffer_attach(bufptr,size); 
}

/*
 * Class:     mpi_MPI
 * Method:    Buffer_detach_native
 * Signature: ([B)V
 */
JNIEXPORT void JNICALL Java_mpi_MPI_Buffer_1detach_1native
  (JNIEnv *env, jclass jthis, jbyteArray buf)
{
  jboolean isCopy;

  int size;
  /*char* bufptr ;*/
  jbyte* bufptr ;

  MPI_Buffer_detach(&bufptr, &size);

  if(buf != NULL)
    (*env)->ReleaseByteArrayElements(env,buf,bufptr,0);
}

/*
 * Class:     mpi_MPI
 * Method:    SetConstant
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_mpi_MPI_SetConstant
  (JNIEnv *env, jclass jthis)
{
   jfieldID anysourceID=(*env)->GetStaticFieldID(env,jthis,"ANY_SOURCE","I");
   jfieldID anytagID=(*env)->GetStaticFieldID(env,jthis,"ANY_TAG","I");
   jfieldID procnullID=(*env)->GetStaticFieldID(env,jthis,"PROC_NULL","I");  
   jfieldID graphID=(*env)->GetStaticFieldID(env,jthis,"GRAPH","I");
   jfieldID cartID=(*env)->GetStaticFieldID(env,jthis,"CART","I");
   jfieldID bsendoverID=(*env)->GetStaticFieldID(env,jthis,"BSEND_OVERHEAD","I");
   jfieldID undefinedID=(*env)->GetStaticFieldID(env,jthis,"UNDEFINED","I");
   
   jfieldID identID=(*env)->GetStaticFieldID(env,jthis,"IDENT","I");
   jfieldID congruentID=(*env)->GetStaticFieldID(env,jthis,"CONGRUENT","I");
   jfieldID similarID=(*env)->GetStaticFieldID(env,jthis,"SIMILAR","I");
   jfieldID unequalID=(*env)->GetStaticFieldID(env,jthis,"UNEQUAL","I");
   jfieldID tagubID=(*env)->GetStaticFieldID(env,jthis,"TAG_UB","I");
   jfieldID hostID=(*env)->GetStaticFieldID(env,jthis,"HOST","I");
   jfieldID ioID=(*env)->GetStaticFieldID(env,jthis,"IO","I");

   (*env)->SetStaticIntField(env,jthis,anysourceID,MPI_ANY_SOURCE);
   (*env)->SetStaticIntField(env,jthis,anytagID,MPI_ANY_TAG);
   (*env)->SetStaticIntField(env,jthis,procnullID,MPI_PROC_NULL);
   (*env)->SetStaticIntField(env,jthis,graphID,MPI_GRAPH);
   (*env)->SetStaticIntField(env,jthis,cartID,MPI_CART);
   (*env)->SetStaticIntField(env,jthis,bsendoverID,MPI_BSEND_OVERHEAD);

   (*env)->SetStaticIntField(env,jthis,undefinedID,MPI_UNDEFINED);
    
   (*env)->SetStaticIntField(env,jthis,identID,MPI_IDENT);
   (*env)->SetStaticIntField(env,jthis,congruentID,MPI_CONGRUENT);
   (*env)->SetStaticIntField(env,jthis,similarID,MPI_SIMILAR);
   (*env)->SetStaticIntField(env,jthis,unequalID,MPI_UNEQUAL);
   (*env)->SetStaticIntField(env,jthis,tagubID,MPI_TAG_UB);
   (*env)->SetStaticIntField(env,jthis,hostID,MPI_HOST);
   (*env)->SetStaticIntField(env,jthis,ioID,MPI_IO);
}
