/*
 * File         : mpi_Cartcomm.c
 * Headerfile   : mpi_Cartcomm.h 
 * Author       : Sung-Hoon Ko, Xinying Li
 * Created      : Thu Apr  9 12:22:15 1998
 * Revision     : $Revision: 1.3 $
 * Updated      : $Date: 1999/09/13 16:14:14 $
 * Copyright: Northeast Parallel Architectures Center
 *            at Syracuse University 1998
 */

#include "mpi.h"
#include "mpi_Cartcomm.h"

#include "ID.h"

DECLARE_CLASS("mpi/Comm", comm_class)
DECLARE_FIELD_ID(comm_class, "handle", "J", CommhandleID)

DECLARE_CLASS("mpi/CartParms", cartparms_class)
DECLARE_FIELD_ID(cartparms_class, "dims", "[I", dimsID)
DECLARE_FIELD_ID(cartparms_class, "periods", "[Z", periodsID)
DECLARE_FIELD_ID(cartparms_class, "coords", "[I", coordsID)
DECLARE_METHOD_ID(cartparms_class, "<init>", "()V", handleConstructorID)

DECLARE_CLASS("mpi/ShiftParms", shiftparms_class)
DECLARE_FIELD_ID(shiftparms_class, "rank_source", "I", rsID)
DECLARE_FIELD_ID(shiftparms_class, "rank_dest", "I", rdID)
DECLARE_METHOD_ID(shiftparms_class, "<init>", "()V", shiftparmsConstructorID)


void WriteBoolAndRelease(JNIEnv *env, jbooleanArray jbarray,
			 int *iarray, int len)
{
  int i;
  jboolean *barray = (*env)->GetBooleanArrayElements(env, jbarray, NULL);
  for (i = 0; i < len; i++) {
    barray[i] = iarray[i];
  }
  (*env)->ReleaseBooleanArrayElements(env, jbarray, barray, 0);
}


/*
 * Class:     mpi_Cartcomm
 * Method:    Get
 * Signature: (I)Lmpi/CartParms;
 */
JNIEXPORT jobject JNICALL Java_mpi_Cartcomm_Get
  (JNIEnv *env, jobject jthis)
{
  jintArray dims, coords;
  jbooleanArray periods;
  jint *ds, *cs, *ps_tmp; 
  jboolean *ps;
  jboolean isCopy1=JNI_TRUE, isCopy2=JNI_TRUE ,isCopy3=JNI_TRUE;
  int maxdims, i;

  jobject cartparms = 
    (*env)->NewObject(env,cartparms_class, handleConstructorID);

  MPI_Cartdim_get((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),&maxdims);

  dims=(*env)->NewIntArray(env,maxdims);
  periods=(*env)->NewBooleanArray(env,maxdims);
  coords=(*env)->NewIntArray(env,maxdims);
  ds=(*env)->GetIntArrayElements(env,dims,&isCopy1);

  ps_tmp=(int*)calloc(maxdims,sizeof(int));

  cs=(*env)->GetIntArrayElements(env,coords,&isCopy3);

  MPI_Cart_get((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
        maxdims, (int*)ds, (int*)ps_tmp, (int*)cs);

  (*env)->SetObjectField(env, cartparms, dimsID, dims);
  (*env)->SetObjectField(env, cartparms, periodsID, periods);
  (*env)->SetObjectField(env, cartparms, coordsID, coords);


  (*env)->ReleaseIntArrayElements(env,dims,ds,0);
  WriteBoolAndRelease(env, periods, ps_tmp, maxdims);
  free(ps_tmp);


    /*FATAL ERROR in native method: Try to unpin an object that is not pinned
        at mpi.Cartcomm.Get(Native Method)  
	Why? */
   
  (*env)->ReleaseIntArrayElements(env,coords,cs,0);

  return cartparms;
}

/*
 * Class:     mpi_Cartcomm
 * Method:    Shift
 * Signature: (II)Lmpi/ShiftParms;
 */
JNIEXPORT jobject JNICALL Java_mpi_Cartcomm_Shift
  (JNIEnv *env, jobject jthis, jint direction, jint disp)
{
  int sr, dr;
  jobject shiftparms=(*env)->NewObject(env,shiftparms_class,
				       shiftparmsConstructorID);

  MPI_Cart_shift((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), 
	direction, disp, &sr, &dr);
  (*env)->SetIntField(env, shiftparms, rsID, sr);
  (*env)->SetIntField(env, shiftparms, rdID, dr);
  /* printf("Shift finished.\n"); */
  return shiftparms;
}

/*
 * Class:     mpi_Cartcomm
 * Method:    Coords
 * Signature: (I)[I
 */
JNIEXPORT jintArray JNICALL Java_mpi_Cartcomm_Coords
  (JNIEnv *env, jobject jthis, jint rank)
{
	jint *coords;
    jboolean isCopy=JNI_TRUE;
    jintArray jcoords;
    int maxdims;
/*
	jclass jthis_class=(*env)->FindClass(env,"mpi/Cartcomm");
    jfieldID maxdimsID=(*env)->GetFieldID(env,jthis_class,"maxdims","I");
    maxdims=(*env)->GetIntField(env,jthis, maxdimsID);
*/
    MPI_Cartdim_get((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
		&maxdims);
	jcoords=(*env)->NewIntArray(env,maxdims);
	coords=(*env)->GetIntArrayElements(env,jcoords,&isCopy);
	MPI_Cart_coords((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
    	rank,maxdims,(int*)coords);
	(*env)->ReleaseIntArrayElements(env,jcoords,coords,0);
	return jcoords;
}

/*
 * Class:     mpi_Cartcomm
 * Method:    Map
 * Signature: ([I[Z)I
 */
JNIEXPORT jint JNICALL Java_mpi_Cartcomm_Map
  (JNIEnv *env, jobject jthis, jintArray dims, jbooleanArray periods)
{
    int newrank;
    jint *ds;
    jboolean *ps;
    jboolean isCopy=JNI_TRUE;
    int ndims;
	int *int_re_ds=(int*)calloc(
		 (*env)->GetArrayLength(env,periods), sizeof(int));
	int i;

    ndims=(*env)->GetArrayLength(env,dims);
    ds=(*env)->GetIntArrayElements(env,dims,&isCopy);
    ps=(*env)->GetBooleanArrayElements(env,periods,&isCopy);

	for(i=0;i<=(*env)->GetArrayLength(env,periods);i++)
	  if(ps[i]==JNI_TRUE)
	    int_re_ds[i]=1;
	  else
	    int_re_ds[i]=0;

    MPI_Cart_map((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
        ndims,(int*)ds,int_re_ds, &newrank);
    (*env)->ReleaseIntArrayElements(env,dims,ds,0);
    (*env)->ReleaseBooleanArrayElements(env,periods,ps,0);
    free(int_re_ds);
    return newrank;
}

/*
 * Class:     mpi_Cartcomm
 * Method:    Rank
 * Signature: ([I)I
 */
JNIEXPORT jint JNICALL Java_mpi_Cartcomm_Rank
  (JNIEnv *env, jobject jthis, jintArray coords)
{
	int rank;
	jint *crds;
	jboolean isCopy=JNI_TRUE;
	crds=(*env)->GetIntArrayElements(env,coords,&isCopy);
	MPI_Cart_rank((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
        (int*)crds, &rank);
	(*env)->ReleaseIntArrayElements(env,coords,crds,0);
	return rank;
}

/*
 * Class:     mpi_Cartcomm
 * Method:    Sub
 * Signature: ([Z)Lmpi/Cartcomm;
 */
JNIEXPORT jlong JNICALL Java_mpi_Cartcomm_sub
  (JNIEnv *env, jobject jthis, jbooleanArray remain_dims)
{
	MPI_Comm newcomm;
	jboolean *re_ds;
	jboolean isCopy=JNI_TRUE;
	int *int_re_ds=(int*)calloc(
		 (*env)->GetArrayLength(env,remain_dims), sizeof(int));
	int i;

	re_ds=(*env)->GetBooleanArrayElements(env,remain_dims,&isCopy);
	for(i=0;i<=(*env)->GetArrayLength(env,remain_dims);i++)
	  if(re_ds[i]==JNI_TRUE)
	    int_re_ds[i]=1;
	  else
	    int_re_ds[i]=0;

	MPI_Cart_sub((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
		     int_re_ds, &newcomm);
	(*env)->ReleaseBooleanArrayElements(env,remain_dims,re_ds,0);

	free(int_re_ds);
	return (jlong)newcomm;
}

/*
 * Class:     mpi_Cartcomm
 * Method:    Dims_create
 * Signature: (I[I)V
 */
JNIEXPORT void JNICALL Java_mpi_Cartcomm_Dims_1create
  (JNIEnv *env, jclass jthis, jint nnodes, jintArray dims )
{
	jint *cdims;
	jboolean isCopy=JNI_TRUE;
        int ndims = (*env)->GetArrayLength(env,dims) ;
	cdims=(*env)->GetIntArrayElements(env,dims,&isCopy);
        MPI_Dims_create(nnodes,ndims,(int*)cdims);
	(*env)->ReleaseIntArrayElements(env,dims,cdims,0);
}
