/*
 * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
 *                         University Research and Technology
 *                         Corporation.  All rights reserved.
 * Copyright (c) 2004-2005 The University of Tennessee and The University
 *                         of Tennessee Research Foundation.  All rights
 *                         reserved.
 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
 *                         University of Stuttgart.  All rights reserved.
 * Copyright (c) 2004-2005 The Regents of the University of California.
 *                         All rights reserved.
 * Copyright (c) 2015      Los Alamos National Security, LLC. All rights
 *                         reserved.
 * $COPYRIGHT$
 *
 * Additional copyrights may follow
 *
 * $HEADER$
 *
 *
 * This file is almost a complete re-write for Open MPI compared to the
 * original mpiJava package. Its license and copyright are listed below.
 * See <path to ompi/mpi/java/README> for more information.
 *
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 * File         : Group.java
 * Author       : Xinying Li, Bryan Carpenter
 * Created      : Thu Apr  9 12:22:15 1998
 * Revision     : $Revision: 1.8 $
 * Updated      : $Date: 2003/01/16 16:39:34 $
 * Copyright: Northeast Parallel Architectures Center
 *            at Syracuse University 1998
 */

package mpi;

/**
 * This class represents {@code MPI_Group}.
 */
public final class Group implements Freeable
{
	protected long handle;
	private static long nullHandle;

	static
	{
		init();
	}

	private static native void init();

	protected static native long getEmpty();

	protected Group(long handle)
	{
		this.handle = handle;
	}

	/**
	 * Java binding of the MPI operation {@code MPI_GROUP_SIZE}.
	 * @return number of processes in the group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public int getSize() throws MPIException
	{
		MPI.check();
		return getSize(handle);
	}

	private native int getSize(long group) throws MPIException;

	/**
	 * Rank of this process in the group.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_RANK}.
	 * @return rank of this process in the group, or {@code MPI.UNDEFINED}
	 *         if this process is not a member of the group.
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public int getRank() throws MPIException
	{
		MPI.check();
		return getRank(handle);
	}

	private native int getRank(long group) throws MPIException;

	/**
	 * Java binding of the MPI operation {@code MPI_GROUP_FREE}.
	 */
	@Override public void free() throws MPIException
	{
		MPI.check();
		handle = free(handle);
	}

	private native long free(long group);

	/**
	 * Test if group object is null.
	 * @return true if the group object is null.
	 */
	public boolean isNull()
	{
		return handle == nullHandle;
	}

	/**
	 * Translate ranks within one group to ranks within another.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_TRANSLATE_RANKS}.
	 * <p>Result elements are {@code MPI.UNDEFINED} where no correspondence exists.
	 * @param group1 a group
	 * @param ranks1 array of valid ranks in group1
	 * @param group2 another group
	 * @return array of corresponding ranks in group2
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public static int[] translateRanks(Group group1, int[] ranks1, Group group2)
			throws MPIException
	{
		MPI.check();
		return translateRanks(group1.handle, ranks1, group2.handle);
	}

	private static native int[] translateRanks(
			long group1, int[] ranks1, long group2) throws MPIException;

	/**
	 * Compare two groups.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_COMPARE}.
	 * @param group1 first group
	 * @param group2 second group
	 * @return {@code MPI.IDENT} if the group members and group order are exactly
	 *         the same in both groups, {@code MPI.SIMILAR} if the group members are
	 *         the same but the order is different, {@code MPI.UNEQUAL} otherwise.
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public static int compare(Group group1, Group group2) throws MPIException
	{
		MPI.check();
		return compare(group1.handle, group2.handle);
	}

	private static native int compare(long group1, long group2) throws MPIException;

	/**
	 * Set union of two groups.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_UNION}.
	 * @param group1 first group
	 * @param group2 second group
	 * @return union group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public static Group union(Group group1, Group group2) throws MPIException
	{
		MPI.check();
		return new Group(union(group1.handle, group2.handle));
	}

	private static native long union(long group1, long group2);

	/**
	 * Set intersection of two groups.
	 * Java binding of the MPI operation {@code MPI_GROUP_INTERSECTION}.
	 * @param group1 first group
	 * @param group2 second group
	 * @return intersection group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public static Group intersection(Group group1, Group group2) throws MPIException
	{
		MPI.check();
		return new Group(intersection(group1.handle, group2.handle));
	}

	private static native long intersection(long group1, long group2);

	/**
	 * Set difference of two groups.
	 * Java binding of the MPI operation {@code MPI_GROUP_DIFFERENCE}.
	 * @param group1 first group
	 * @param group2 second group
	 * @return difference group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public static Group difference(Group group1, Group group2) throws MPIException
	{
		MPI.check();
		return new Group(difference(group1.handle, group2.handle));
	}

	private static native long difference(long group1, long group2);

	/**
	 * Create a subset group including specified processes.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_INCL}.
	 * @param ranks ranks from this group to appear in new group
	 * @return new group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public Group incl(int[] ranks) throws MPIException
	{
		MPI.check();
		return new Group(incl(handle, ranks));
	}

	private native long incl(long group, int[] ranks);

	/**
	 * Create a subset group excluding specified processes.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_EXCL}.
	 * @param ranks ranks from this group <em>not</em> to appear in new group
	 * @return new group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public Group excl(int[] ranks) throws MPIException
	{
		MPI.check();
		return new Group(excl(handle, ranks));
	}

	private native long excl(long group, int[] ranks);

	/**
	 * Create a subset group including processes specified
	 * by strided intervals of ranks.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_RANGE_INCL}.
	 * <p>The triplets are of the form (first rank, last rank, stride)
	 * indicating ranks in this group to be included in the new group.
	 * The size of the first dimension of {@code ranges} is the number
	 * of triplets.  The size of the second dimension is 3.
	 * @param ranges array of integer triplets
	 * @return new group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public Group rangeIncl(int[][] ranges) throws MPIException
	{
		MPI.check();
		return new Group(rangeIncl(handle, ranges));
	}

	private native long rangeIncl(long group, int[][] ranges);

	/**
	 * Create a subset group excluding processes specified
	 * by strided intervals of ranks.
	 * <p>Java binding of the MPI operation {@code MPI_GROUP_RANGE_EXCL}.
	 * <p>Triplet array is defined as for {@code rangeIncl}, the ranges
	 * indicating ranks in this group to be excluded from the new group.
	 * @param ranges array of integer triplets
	 * @return new group
	 * @throws MPIException Signals that an MPI exception of some sort has occurred.
	 */
	public Group rangeExcl(int[][] ranges) throws MPIException
	{
		MPI.check();
		return new Group(rangeExcl(handle, ranges));
	}

	private native long rangeExcl(long group, int[][] ranges);

} // Group
