/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*-
 *     vim: ts=8 sts=4 sw=4 noexpandtab
 *
 *   Copyright (C) 1997 University of Chicago.
 *   See COPYRIGHT notice in top-level directory.
 */

#include "adio.h"
#include "adio_extern.h"
#include "ad_pvfs2.h"
#include "ad_pvfs2_io.h"
#include "ad_pvfs2_common.h"

void ADIOI_PVFS2_ReadContig(ADIO_File fd, void *buf, int count,
			    MPI_Datatype datatype, int file_ptr_type,
			    ADIO_Offset offset, ADIO_Status *status,
			    int *error_code)
{
    int ret;
    MPI_Count datatype_size, len;
    PVFS_Request file_req, mem_req;
    PVFS_sysresp_io resp_io;
    ADIOI_PVFS2_fs *pvfs_fs;
    static char myname[] = "ADIOI_PVFS2_READCONTIG";

    pvfs_fs = (ADIOI_PVFS2_fs*)fd->fs_ptr;

    MPI_Type_size_x(datatype, &datatype_size);
    len = datatype_size * count;

    ret = PVFS_Request_contiguous(len, PVFS_BYTE, &mem_req);
    /* --BEGIN ERROR HANDLING-- */
    if (ret != 0) {
	*error_code = MPIO_Err_create_code(MPI_SUCCESS,
					   MPIR_ERR_RECOVERABLE,
					   myname, __LINE__,
					   ADIOI_PVFS2_error_convert(ret),
					   "Error in pvfs_request_contig (memory)", 0);
	return;
    }
    /* --END ERROR HANDLING-- */

    ret = PVFS_Request_contiguous(len, PVFS_BYTE, &file_req);
    /* --BEGIN ERROR HANDLING-- */
    if (ret != 0) {
	*error_code = MPIO_Err_create_code(MPI_SUCCESS,
					   MPIR_ERR_RECOVERABLE,
					   myname, __LINE__,
					   ADIOI_PVFS2_error_convert(ret),
					   "Error in pvfs_request_contig (file)", 0);
	return;
    }
    /* --END ERROR HANDLING-- */

    if (file_ptr_type == ADIO_INDIVIDUAL) {
	/* copy individual file pointer into offset variable, continue */
	offset = fd->fp_ind;
    }

#ifdef ADIOI_MPE_LOGGING
    MPE_Log_event( ADIOI_MPE_read_a, 0, NULL );
#endif
    ret = PVFS_sys_read(pvfs_fs->object_ref, file_req, offset, buf,
			mem_req, &(pvfs_fs->credentials), &resp_io);
#ifdef ADIOI_MPE_LOGGING
    MPE_Log_event( ADIOI_MPE_read_b, 0, NULL );
#endif
    /* --BEGIN ERROR HANDLING-- */
    if (ret != 0 ) {
	*error_code = MPIO_Err_create_code(MPI_SUCCESS,
					   MPIR_ERR_RECOVERABLE,
					   myname, __LINE__,
					   ADIOI_PVFS2_error_convert(ret),
					   "Error in PVFS_sys_read", 0);
	goto fn_exit;
    }
    /* --END ERROR HANDLING-- */

    if (file_ptr_type == ADIO_INDIVIDUAL) {
	fd->fp_ind += (int) resp_io.total_completed;
	/* TODO: WHY THE INT CAST? */
    }
    fd->fp_sys_posn = offset + (int)resp_io.total_completed;

#ifdef HAVE_STATUS_SET_BYTES
    MPIR_Status_set_bytes(status, datatype, resp_io.total_completed);
#endif

    *error_code = MPI_SUCCESS;
fn_exit:
    PVFS_Request_free(&mem_req);
    PVFS_Request_free(&file_req);
    return;
}

static int ADIOI_PVFS2_ReadStridedListIO(ADIO_File fd, void *buf, int count,
				  MPI_Datatype datatype, int file_ptr_type,
				  ADIO_Offset offset, ADIO_Status *status,
				  int *error_code)
{
    return ADIOI_PVFS2_StridedListIO(fd, buf, count,
				     datatype, file_ptr_type,
				     offset, status,
				     error_code, READ);
}

static int ADIOI_PVFS2_ReadStridedDtypeIO(ADIO_File fd, void *buf, int count,
				   MPI_Datatype datatype, int file_ptr_type,
				   ADIO_Offset offset, ADIO_Status *status,
				   int *error_code)
{
    return ADIOI_PVFS2_StridedDtypeIO(fd, buf, count,
				      datatype, file_ptr_type,
				      offset, status, error_code,
				      READ);
}

void ADIOI_PVFS2_ReadStrided(ADIO_File fd, void *buf, int count,
			     MPI_Datatype datatype, int file_ptr_type,
			     ADIO_Offset offset, ADIO_Status *status, int
			     *error_code)
{
    /* four ways (to date) that we can carry out strided i/o accesses:
     * - naive posix
     * - 'true' Datatype (from avery)
     * - new List I/O (from avery)
     * - classic List I/O  (the one that's always been in ROMIO)
     * I imagine we'll keep Datatype as an optional optimization, and afer a
     * release or two promote it to the default
     */
    int ret = -1;

    if (fd->hints->fs_hints.pvfs2.posix_read == ADIOI_HINT_ENABLE) {
	ADIOI_GEN_ReadStrided(fd, buf, count, datatype,
		file_ptr_type, offset, status, error_code);
	return;
    }
    if (fd->hints->fs_hints.pvfs2.dtype_read == ADIOI_HINT_ENABLE) {
        ret = ADIOI_PVFS2_ReadStridedDtypeIO(fd, buf, count,
                                             datatype, file_ptr_type,
                                             offset, status, error_code);

        /* Fall back to list I/O if datatype I/O didn't work */
        if (ret != 0)
        {
            fprintf(stderr,
                    "Falling back to list I/O since datatype I/O failed\n");
            ret = ADIOI_PVFS2_ReadStridedListIO(fd, buf, count,
                                                datatype, file_ptr_type,
                                                offset, status, error_code);
        }
        return;
    }
    if (fd->hints->fs_hints.pvfs2.listio_read == ADIOI_HINT_ENABLE) {
	ret = ADIOI_PVFS2_ReadStridedListIO(fd, buf, count, datatype,
		file_ptr_type, offset, status, error_code);
	return;
    }
    /* Use classic list I/O if no hints given base case */

    ADIOI_PVFS2_OldReadStrided(fd, buf, count, datatype,
	    file_ptr_type, offset, status, error_code);
    return;
}


/*
 * vim: ts=8 sts=4 sw=4 noexpandtab
 */
