/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *	Ohio Trollius
 *	Copyright 1997 The Ohio State University
 *	NJN
 *
 *	$Id: getelem.c,v 6.4 1999/05/25 22:07:54 kmeyer1 Exp $
 *
 *	Function:	- get # bottom-level elements
 *	Accepts:	- status
 *			- datatype
 *			- count (out)
 *	Returns:	- MPI_SUCCESS or error code
 */

#include <blktype.h>
#include <mpi.h>
#include <mpisys.h>

/*
 * private functions
 */
static int		subcount();


int
MPI_Get_elements(stat, dtype, count)

MPI_Status		*stat;
MPI_Datatype		dtype;
int			*count;

{
	int		elts;			/* # basic elements */
	int		integral;		/* # integral dtype copies */
	int		left;			/* packed data length left */

	lam_initerr_m();
	lam_setfunc_m(BLKMPIGETELEM);
/*
 * Check the arguments.
 */
	if ((count == 0) || (stat == 0) || (stat->st_length < 0)) {
		return(lam_errfunc(MPI_COMM_WORLD,
			BLKMPIGETELEM, lam_mkerr(MPI_ERR_ARG, 0)));
	}

	if (dtype == MPI_DATATYPE_NULL) {
		return(lam_errfunc(MPI_COMM_WORLD,
			BLKMPIGETELEM, lam_mkerr(MPI_ERR_TYPE, 0)));
	}
/*
 * Compute the element count.
 */ 
	if (dtype->dt_size == 0) {
		*count = MPI_UNDEFINED;
	}
	else if (dtype->dt_format == LAM_DTBASIC) {
		*count = ((stat->st_length % dtype->dt_size) == 0)
			? stat->st_length / dtype->dt_size : MPI_UNDEFINED;
	} else {
		integral = stat->st_length / dtype->dt_size;
		*count = integral * dtype->dt_nelem;
		left = stat->st_length - integral * dtype->dt_size;

		if (left) {
			elts = subcount(left, dtype);

			if (elts == MPI_UNDEFINED) {
				*count = MPI_UNDEFINED;
			} else {
				*count += elts;
			}
		}
	}

	lam_resetfunc_m(BLKMPIGETELEM);
	return(MPI_SUCCESS);
}

/*
 *	subcount
 *
 *	Function:	- get count of bottom level elements in
 *			  fractional part of a datatype
 *			- counting is done recursively
 *	Accepts:	- packed length left
 *			- datatype
 *	Returns:	- count of bottom level elements
 */
static int
subcount(left, dtype)

int			left;
MPI_Datatype		dtype;

{
	int		i;
	int		elts;			/* # basic elements */
	int		totelts = 0;		/* total # basic elements */
	int		integral;		/* # integral subtype copies */
	int		blksize;		/* size of subtype block */

	if (dtype->dt_format == LAM_DTBASIC) {
		
	    if (left % dtype->dt_size) {
		totelts = MPI_UNDEFINED;
	    } else {
		totelts += left / dtype->dt_size;
	    }
	}
	else if (dtype->dt_format == LAM_DTSTRUCT
	        || dtype->dt_format == LAM_DTSTRUCTCREAT
	    	|| dtype->dt_format == LAM_DTDARRAY
	    	|| dtype->dt_format == LAM_DTSUBARRAY) {
/*
 * Count sub blocks one by one.
 */
	    for (i = 0; i < dtype->dt_count && left > 0; ++i) {

		blksize = dtype->dt_lengths[i] * dtype->dt_dtypes[i]->dt_size;
		if (blksize == 0) {
		    continue;
		}

		if (left >= blksize) {
		    left -= blksize;
		    totelts += dtype->dt_lengths[i]
				* dtype->dt_dtypes[i]->dt_nelem;
		} else {
/*
 * There is a partial sub block.  Determine the number of elements in
 * the integral sub parts and then recursively count the fractional part
 * that is left over.
 */
		    integral =  left / dtype->dt_dtypes[i]->dt_size;
		    totelts += integral * dtype->dt_dtypes[i]->dt_nelem;
		    left -= integral * dtype->dt_dtypes[i]->dt_size;

		    if (left) {
			elts = subcount(left, dtype->dt_dtypes[i]);

			if (elts == MPI_UNDEFINED) {
			    totelts = MPI_UNDEFINED;
			} else {
			    totelts += elts;
			}
		    }

		    break;
		}
	    }
	}
	else {
/*
 * Type is vector or indexed.  This means that all the next level
 * elements are of the same subtype.
 */
	    integral = left / dtype->dt_dtype->dt_size;
	    totelts += integral * dtype->dt_dtype->dt_nelem;
	    left -= integral * dtype->dt_dtype->dt_size;

	    if (left) {
		elts = subcount(left, dtype->dt_dtype);

		if (elts == MPI_UNDEFINED) {
		    totelts = MPI_UNDEFINED;
		} else {
		    totelts += elts;
		}
	    }
	}

	return(totelts);
}
