/*
 * File         : .c
 * Headerfile   : .h 
 * Author       : Xinying Li
 * Created      : Thu Apr  9 12:22:15 1998
 * Revision     : $Revision: 1.6 $
 * Updated      : $Date: 1999/09/16 02:50:09 $
 * Copyright: Northeast Parallel Architectures Center
 *            at Syracuse University 1998
 */

#include <mpi.h>
#include "mpi_Comm.h"

#include "mpi_Intracomm.h"

#include "buffer.h"
#include "ID.h"

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

DECLARE_CLASS("mpi/Datatype", datatype_class)
DECLARE_FIELD_ID(datatype_class, "handle", "J", DatatypehandleID)
DECLARE_FIELD_ID(datatype_class, "baseSize", "I", DatatypebaseSizeID)

DECLARE_CLASS("mpi/Op", op_class)
DECLARE_FIELD_ID(op_class, "handle", "J", OphandleID)

DECLARE_CLASS("mpi/Group", group_class)
DECLARE_FIELD_ID(group_class, "handle", "J", GrouphandleID)


int elem_size(JNIEnv *env, jobject type) 
{
  return Java_mpi_Datatype_size(env, type) /
    (*env)->GetIntField(env, type, DatatypebaseSizeID);
}

/*
 * Class:     mpi_Intracomm
 * Method:    split
 * Signature: (II)J
 */
JNIEXPORT jlong JNICALL Java_mpi_Intracomm_split
  (JNIEnv *env, jobject jthis, jint colour, jint key)
{
    MPI_Comm newcomm;

MPI_Comm_split((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), colour, key,&newcomm);
    return (jlong)newcomm;
}

/*
 * Class:     mpi_Intracomm
 * Method:    creat
 * Signature: (Lmpi/Group;)J
 */
JNIEXPORT jlong JNICALL Java_mpi_Intracomm_creat
  (JNIEnv *env, jobject jthis, jobject group)
{
    MPI_Comm newcomm;

MPI_Comm_create((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
        (MPI_Group)((*env)->GetLongField(env,group,GrouphandleID)), &newcomm);
    if(newcomm==MPI_COMM_NULL)
        return (jlong) NULL;
    return (jlong)newcomm;
}

/*
 * Class:     mpi_Intracomm
 * Method:    Barrier
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_Barrier
  (JNIEnv *env, jobject jthis)
{
	MPI_Barrier((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
}

/*
 * Class:     mpi_Intracomm
 * Method:    GetCart
 * Signature: ([I[ZZ)J
 */
JNIEXPORT jlong JNICALL Java_mpi_Intracomm_GetCart
  (JNIEnv *env, jobject jthis, jintArray dims, jbooleanArray periods, 
	jboolean reorder)
{
  MPI_Comm cart;
  int ndims=(*env)->GetArrayLength(env,dims);
  jboolean isCopy=JNI_TRUE;
  jint *ds; jboolean *ps;
  int i;
  int *int_re_ds=(int*)calloc(
		 (*env)->GetArrayLength(env,periods), sizeof(int));

  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_create((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), 
	ndims, (int*)ds, int_re_ds, reorder, &cart);
  (*env)->ReleaseIntArrayElements(env,dims,ds,0);
  (*env)->ReleaseBooleanArrayElements(env,periods,ps,0);
  /* printf("Create cart\n"); */
  free(int_re_ds);
  return (jlong)cart;
}

/*
 * Class:     mpi_Intracomm
 * Method:    GetGraph
 * Signature: ([I[IZ)J
 */
JNIEXPORT jlong JNICALL Java_mpi_Intracomm_GetGraph
  (JNIEnv *env, jobject jthis, jintArray index, jintArray edges, jboolean reorder)
{
  MPI_Comm graph;
  int nnodes=(*env)->GetArrayLength(env,index);
  jboolean isCopy=JNI_TRUE;
  jint *ind, *edg;
  ind=(*env)->GetIntArrayElements(env,index,&isCopy);
  edg=(*env)->GetIntArrayElements(env,edges,&isCopy);
  MPI_Graph_create((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
    nnodes, (int*)ind, (int*)edg, reorder, &graph);
  (*env)->ReleaseIntArrayElements(env,index,ind,0);
  (*env)->ReleaseIntArrayElements(env,edges,edg,0);
  return (jlong)graph;
}

/*
 * Class:     mpi_Intracomm
 * Method:    bcast
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;I)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_bcast
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint root)
{
   void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);
   MPI_Bcast(bufptr,count,
             (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
             root,
             (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,buf,type,bufptr,offset, count, BUF_RELEASE|BUF_WRITEBACK);
}


/*
 * Class:     mpi_Intracomm
 * Method:    Gather
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;Ljava/lang/Object;IILmpi/Dataty
pe;I)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_gather
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, jint
sendcount, jobject sendtype, jobject recvbuf, jint recvoffset, jint recvcount,
jobject recvtype, jint root)
{
   void* sendptr=getBufPtr(env,sendbuf,sendtype,sendoffset, sendcount, JNI_TRUE);
   int recvlen;
   void* recvptr;
   jint me = Java_mpi_Comm_Rank(env, jthis);
   /* The following actually should not be done.  But mpich-1.1.2 barks
      if we pass MPI_TYPE_NULL. */
   MPI_Datatype recvtypehandle =
     (MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID));

   if (me == root) {
     recvlen = recvcount * Java_mpi_Comm_Size(env, jthis);
     recvptr = getBufPtr(env,recvbuf,recvtype,recvoffset, recvlen, JNI_FALSE);
     /*
     recvtypehandle =
       (MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID));
       */
   }

   MPI_Gather(
        sendptr,
        sendcount,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)), 
	recvptr,
        recvcount,
	recvtypehandle,
	root,
        (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));

   releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendcount, BUF_RELEASE);
   if (me == root) {
     releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvlen, BUF_RELEASE|BUF_WRITEBACK);
   }
}

/*
 * Class:     mpi_Intracomm
 * Method:    Gatherv
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;Ljava/lang/Object;I[I[ILmpi/Dat
atype;I)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_gatherv
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, jint sendcount,jobject sendtype, jobject recvbuf, jint recvoffset,
jintArray recvcount, jintArray displs, jobject recvtype, jint root)
{
   jint *rcount;
   jint *dps;
   void* sendptr=getBufPtr(env,sendbuf,sendtype,sendoffset, sendcount, JNI_TRUE);
   int recvlen;
   void* recvptr;
   MPI_Datatype recvtypehandle;
   jint me = Java_mpi_Comm_Rank(env, jthis);

   if (me == root) {
     jint group_size = Java_mpi_Comm_Size(env, jthis);;
     rcount=(*env)->GetIntArrayElements(env,recvcount,NULL);
     dps=(*env)->GetIntArrayElements(env,displs,NULL);
     recvlen = (dps[group_size - 1] + rcount[group_size - 1]) /
       elem_size(env, recvtype) - recvoffset;
     recvptr = getBufPtr(env,recvbuf,recvtype,recvoffset, recvlen, JNI_FALSE);
     recvtypehandle =
       (MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID));
   }
   MPI_Gatherv(sendptr,sendcount,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)),
	recvptr,(int*) rcount,
	(int*)dps,
        recvtypehandle,
	root,(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendcount, BUF_RELEASE);
   if (me == root) {
     (*env)->ReleaseIntArrayElements(env,recvcount,rcount,JNI_ABORT);
     (*env)->ReleaseIntArrayElements(env,displs,dps,JNI_ABORT);
     releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvlen, BUF_RELEASE|BUF_WRITEBACK);
   }
}

/*
 * Class:     mpi_Intracomm
 * Method:    Scatter
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;Ljava/lang/Object;IILmpi/Dataty
pe;I)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_scatter
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, jint
sendcount, jobject sendtype, jobject recvbuf, jint recvoffset, jint recvcount,
jobject recvtype, jint root)
{
   int sendlen;
   void* sendptr;
   void* recvptr=getBufPtr(env,recvbuf,recvtype,recvoffset, recvcount, JNI_FALSE);
   jint me = Java_mpi_Comm_Rank(env, jthis);

   if (me == root) {
     sendlen = sendcount * Java_mpi_Comm_Size(env, jthis);
     sendptr = getBufPtr(env,sendbuf,sendtype,sendoffset, sendlen, JNI_TRUE);
   }
   MPI_Scatter(sendptr, sendcount,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)), 
	recvptr, recvcount,
	(MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID)),
	root,(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   if (me == root) {
     releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendlen, BUF_RELEASE);
   }
   releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvcount, BUF_RELEASE|BUF_WRITEBACK);
}


/*
 * Class:     mpi_Intracomm
 * Method:    Scatterv
 * Signature:
(Ljava/lang/Object;II[ILmpi/Datatype;Ljava/lang/Object;I[ILmpi/Dat
atype;I)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_scatterv
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, 
	jintArray sendcount,jintArray displs, 
	jobject sendtype, jobject recvbuf, jint recvoffset,
	jint recvcount,jobject recvtype, jint root)
{
   jint *scount;
   jint *dps;
   int sendlen;
   void* sendptr;
   void* recvptr=getBufPtr(env,recvbuf,recvtype,recvoffset, recvcount, JNI_FALSE);
   jint me = Java_mpi_Comm_Rank(env, jthis);

   if (me == root) {
     jint group_size = Java_mpi_Comm_Size(env, jthis);
     scount=(*env)->GetIntArrayElements(env,sendcount,NULL);
     dps=(*env)->GetIntArrayElements(env,displs,NULL);
     sendlen = (dps[group_size - 1] + scount[group_size - 1]) /
       elem_size(env, sendtype) - sendoffset;
     sendptr=getBufPtr(env,sendbuf,sendtype,sendoffset, sendlen, JNI_TRUE);
   }

   MPI_Scatterv(sendptr,(int*)scount,(int*) dps,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)),
	recvptr, recvcount,
	(MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID)),
	root,(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvcount, BUF_RELEASE|BUF_WRITEBACK);
   if (me == root) {
     (*env)->ReleaseIntArrayElements(env,displs,dps,JNI_ABORT);
     (*env)->ReleaseIntArrayElements(env,sendcount,scount,JNI_ABORT);
     releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendlen, BUF_RELEASE);
   }
}

/*
 * Class:     mpi_Intracomm
 * Method:    Allgather
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;Ljava/lang/Object;IILmpi/Dataty
pe;)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_allgather
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, jint
sendcount, jobject sendtype, jobject recvbuf, jint recvoffset, jint recvcount,
jobject recvtype)
{
   jbyte * sendptr=getBufPtr(env,sendbuf,sendtype,sendoffset, sendcount, JNI_TRUE);
   int recvlen = recvcount * Java_mpi_Comm_Size(env, jthis);
   jbyte * recvptr=getBufPtr(env,recvbuf,recvtype,recvoffset, recvlen, JNI_FALSE);
   MPI_Allgather(sendptr, sendcount,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)), 
	recvptr, recvcount,
	(MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID)),
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendcount, BUF_RELEASE);
   releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvlen, BUF_WRITEBACK);
}

/*
 * Class:     mpi_Intracomm
 * Method:    Allgatherv
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;Ljava/lang/Object;I[I[ILmpi/Dat
atype;)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_allgatherv
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, jint sendcount,jobject sendtype, jobject recvbuf, jint recvoffset,
jintArray recvcount, jintArray displs, jobject recvtype)
{
   jint *rcount;
   jint *dps;
   jbyte * sendptr=getBufPtr(env,sendbuf,sendtype,sendoffset, sendcount, JNI_TRUE);
   int recvlen;
   jbyte * recvptr;
   jint group_size = Java_mpi_Comm_Size(env, jthis);

   rcount=(*env)->GetIntArrayElements(env,recvcount,NULL);
   dps=(*env)->GetIntArrayElements(env,displs,NULL);
   recvlen = (dps[group_size - 1] + rcount[group_size - 1]) /
     elem_size(env, recvtype) - recvoffset;
   recvptr = getBufPtr(env,recvbuf,recvtype,recvoffset, recvlen, JNI_FALSE);
   MPI_Allgatherv(sendptr,sendcount,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)),
	recvptr,(int*) rcount,
	(int*)dps,
        (MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID)),
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   (*env)->ReleaseIntArrayElements(env,recvcount,rcount,JNI_ABORT);
   (*env)->ReleaseIntArrayElements(env,displs,dps,JNI_ABORT);
   releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendcount, BUF_RELEASE);
   releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvlen, BUF_RELEASE|BUF_WRITEBACK);
}
 
/*
 * Class:     mpi_Intracomm
 * Method:    Alltoall
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;Ljava/lang/Object;IILmpi/Dataty
pe;)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_alltoall
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, jint
sendcount, jobject sendtype, jobject recvbuf, jint recvoffset, jint recvcount,
jobject recvtype)
{
   int sendlen = sendcount * Java_mpi_Comm_Size(env, jthis);
   void* sendptr=getBufPtr(env,sendbuf,sendtype,sendoffset, sendlen, JNI_TRUE);
   int recvlen = recvcount * Java_mpi_Comm_Size(env, jthis);
   void* recvptr=getBufPtr(env,recvbuf,recvtype,recvoffset, recvlen, JNI_FALSE);
   MPI_Alltoall(sendptr, sendcount,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)), 
	recvptr, recvcount,
	(MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID)),
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendlen, BUF_RELEASE);
   releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvlen, BUF_RELEASE|BUF_WRITEBACK);
}

/*
 * Class:     mpi_Intracomm
 * Method:    Alltoallv
 * Signature:
(Ljava/lang/Object;II[ILmpi/Datatype;Ljava/lang/Object;I[I[ILmpi/D
atatype;)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_alltoallv
   (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, jintArray sendcount, 
	  jintArray sdispls, jobject sendtype, jobject recvbuf, jint recvoffset,
	  jintArray recvcount, jintArray rdispls, jobject recvtype)
{
   jint *rcount, *scount;
   jint *sdps,*rdps;
   int sendlen;
   void* sendptr;
   int recvlen;
   void* recvptr;
   jint group_size = Java_mpi_Comm_Size(env, jthis);

   scount=(*env)->GetIntArrayElements(env,sendcount,NULL);
   rcount=(*env)->GetIntArrayElements(env,recvcount,NULL);
   sdps=(*env)->GetIntArrayElements(env,sdispls,NULL);
   rdps=(*env)->GetIntArrayElements(env,rdispls,NULL);
   sendlen = (sdps[group_size - 1] + scount[group_size - 1]) /
     elem_size(env, sendtype) - sendoffset;
   sendptr=getBufPtr(env,sendbuf,sendtype,sendoffset, sendlen, JNI_TRUE);
   recvlen = (rdps[group_size - 1] + rcount[group_size - 1]) /
     elem_size(env, recvtype) - recvoffset;
   recvptr = getBufPtr(env,recvbuf,recvtype,recvoffset, recvlen, JNI_FALSE);
   MPI_Alltoallv(sendptr,(int*)scount, (int*)sdps,
	(MPI_Datatype)((*env)->GetLongField(env,sendtype,DatatypehandleID)),
	recvptr, (int*)rcount,
	(int*)rdps,
        (MPI_Datatype)((*env)->GetLongField(env,recvtype,DatatypehandleID)),
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   (*env)->ReleaseIntArrayElements(env,recvcount,rcount,JNI_ABORT);
   (*env)->ReleaseIntArrayElements(env,sendcount,scount,JNI_ABORT);
   (*env)->ReleaseIntArrayElements(env,sdispls,sdps,JNI_ABORT);
   (*env)->ReleaseIntArrayElements(env,rdispls,rdps,JNI_ABORT);
   releaseBufPtr(env,sendbuf,sendtype,sendptr,sendoffset,sendlen, BUF_RELEASE);
   releaseBufPtr(env,recvbuf,recvtype,recvptr,recvoffset,recvlen, BUF_RELEASE|BUF_WRITEBACK);
}
 
/*
 * Class:     mpi_Intracomm
 * Method:    Reduce
 * Signature:
(Ljava/lang/Object;ILjava/lang/Object;IILmpi/Datatype;Lmpi/Op;I)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_reduce
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, 
	  jobject recvbuf, jint recvoffset, jint count,
	  jobject type, jobject op, jint root)
{
   void* sendptr=getBufPtr(env,sendbuf,type,sendoffset, count, JNI_TRUE);
   void* recvptr;
   jint me = Java_mpi_Comm_Rank(env, jthis);
   if (me == root) {
     recvptr = getBufPtr(env,recvbuf,type,recvoffset, count, JNI_FALSE);
   }
   MPI_Reduce(sendptr, recvptr, count,
	(MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	(MPI_Op)((*env)->GetLongField(env,op,OphandleID)),
	root,(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,sendbuf,type,sendptr,sendoffset,count, BUF_RELEASE);
   if (me == root) {
     releaseBufPtr(env,recvbuf,type,recvptr,recvoffset,count, BUF_RELEASE|BUF_WRITEBACK);
   }
}

/*
 * Class:     mpi_Intracomm
 * Method:    Allreduce
 * Signature:
(Ljava/lang/Object;ILjava/lang/Object;IILmpi/Datatype;Lmpi/Op;)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_allreduce
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, 
	  jobject recvbuf, jint recvoffset, jint count,
	  jobject type, jobject op)
{
   void* sendptr=getBufPtr(env,sendbuf,type,sendoffset, count, JNI_TRUE);
   void* recvptr=getBufPtr(env,recvbuf,type,recvoffset, count, JNI_FALSE);
   MPI_Allreduce(sendptr, recvptr, count,
	(MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	(MPI_Op)((*env)->GetLongField(env,op,OphandleID)),
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,sendbuf,type,sendptr,sendoffset,count, BUF_RELEASE);
   releaseBufPtr(env,recvbuf,type,recvptr,recvoffset,count, BUF_RELEASE|BUF_WRITEBACK);
}

/*
 * Class:     mpi_Intracomm
 * Method:    Reduce_scatter
 * Signature:
(Ljava/lang/Object;ILjava/lang/Object;I[ILmpi/Datatype;Lmpi/Op;)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_reduce_1scatter
  (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset,
	  jobject recvbuf, jint recvoffset, jintArray recvcount,
	  jobject type, jobject op)
{
   jint *rcount;
   int sendlen = 0;
   void* sendptr;
   int recvlen;
   void* recvptr;
   int i, me = Java_mpi_Comm_Rank(env, jthis);
   jint group_size = Java_mpi_Comm_Size(env, jthis);

   rcount=(*env)->GetIntArrayElements(env,recvcount,NULL);
   for (i = 0; i < group_size; i++) {
     sendlen += rcount[i];
   }
   sendlen = sendlen / elem_size(env, type) - sendoffset;
   sendptr = getBufPtr(env,sendbuf,type,sendoffset, sendlen, JNI_TRUE);
   recvlen = rcount[me] / elem_size(env, type) - recvoffset;
   recvptr = getBufPtr(env,recvbuf,type,recvoffset, recvlen, JNI_FALSE);
   MPI_Reduce_scatter(sendptr, recvptr,(int*) rcount,
	(MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	(MPI_Op)((*env)->GetLongField(env,op,OphandleID)),
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   (*env)->ReleaseIntArrayElements(env,recvcount,rcount,JNI_ABORT);
   releaseBufPtr(env,sendbuf,type,sendptr,sendoffset,sendlen, BUF_RELEASE);
   releaseBufPtr(env,recvbuf,type,recvptr,recvoffset,recvlen, BUF_RELEASE|BUF_WRITEBACK);
}

/*
 * Class:     mpi_Intracomm
 * Method:    Scan
 * Signature:
(Ljava/lang/Object;ILjava/lang/Object;IILmpi/Datatype;Lmpi/Op;)V
 */
JNIEXPORT void JNICALL Java_mpi_Intracomm_scan
 (JNIEnv *env, jobject jthis, jobject sendbuf, jint sendoffset, 
	  jobject recvbuf, jint recvoffset, jint count,
	 jobject type, jobject op)
{
   void* sendptr=getBufPtr(env,sendbuf,type,sendoffset, count, JNI_TRUE);
   void* recvptr=getBufPtr(env,recvbuf,type,recvoffset, count, JNI_FALSE);
   MPI_Scan(sendptr, recvptr, count,
	(MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	(MPI_Op)((*env)->GetLongField(env,op,OphandleID)),
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
   releaseBufPtr(env,sendbuf,type,sendptr,sendoffset,count, BUF_RELEASE);
   releaseBufPtr(env,recvbuf,type,recvptr,recvoffset,count, BUF_RELEASE|BUF_WRITEBACK);
}

