/*
** Simple test program 02 for the MIAMI protocol
** Rolf Riesen, December 2009
**
** Usage: test_08 local_host local_port remote_host remote_port rank
** rank should be 0 in one process, and 1 in the other.
**
** Test large messages
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#if defined (_MPI_)
#include <mpi.h>
#endif
#include "miami.h"

#define RMSG_SIZE_1	((25 * 1024) / (int)sizeof(int))
#define RMSG_SIZE_2	((50 * 1024) / (int)sizeof(int))
#define RMSG_SIZE_3	((50 * 1024) / (int)sizeof(int))



int
main(int argc, char *argv[])
{

char *host1;
char *host2;
int *sbuf;
int *rbuf1, *rbuf2, *rbuf3;
int port1, port2;
int rank;
int tag;
int shandle;
int rhandle1;
int rhandle2;
int rhandle3;
int bytes;
int i, rc;
int flag, ack;


    if (argc != 6)   {
	fprintf(stderr, "Usage: %s local_host local_port remote_host remote_port rank\n", argv[0]);
	return -1;
    }

    host1= argv[1];
    host2= argv[3];
    port1= strtol(argv[2], NULL, 10);
    port2= strtol(argv[4], NULL, 10);
    rank= strtol(argv[5], NULL, 10);

    miami_init(host1, port1, host2, port2);
#if defined (_MPI_)
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
#endif

    tag= 12;
    flag= 0;
    rc= 0;

    sbuf= (int *)malloc(RMSG_SIZE_3 * sizeof(int));
    if (sbuf == NULL)   {
	fprintf(stderr, "Out of memory\n");
	exit(-1);
    }


    /* Fill the send buffer */
    for (i= 0; i < RMSG_SIZE_3; i++)   {
	sbuf[i]= i;
    }

    rc= 0;
    if (rank == 0)   {
	/* I'm the sender */
	/* Wait for the ack from the receiver */
	rhandle1= miami_rx_start(&ack, sizeof(int), tag);
	while (!miami_rx_done(rhandle1, &bytes))   {
	}

	/* Send a long message longer than the receiver buffer */
	printf("Test Starting send 1 of %ld bytes\n", sizeof(int) * RMSG_SIZE_3);
	shandle= miami_tx_start(sbuf, sizeof(int) * RMSG_SIZE_3, tag);
	while (!miami_tx_done(shandle))   {
	}

	/* Send a long message that is the size of the receiver buffer */
	printf("Test Starting send 2 of %ld bytes\n", sizeof(int) * RMSG_SIZE_2);
	shandle= miami_tx_start(sbuf, sizeof(int) * RMSG_SIZE_2, tag);
	while (!miami_tx_done(shandle))   {
	}

	/* Send a long message that is shorter than the receiver buffer */
	printf("Test Starting send 3 of %ld bytes\n", sizeof(int) * RMSG_SIZE_1);
	shandle= miami_tx_start(sbuf, sizeof(int) * RMSG_SIZE_1, tag);
	while (!miami_tx_done(shandle))   {
	}
	printf("Test Done\n");

    } else   {

	/* I'm the receiver */
	rbuf1= (int *)malloc(RMSG_SIZE_3 * sizeof(int));
	if (rbuf1 == NULL)   {
	    fprintf(stderr, "Out of memory\n");
	    exit(-1);
	}

	rbuf2= (int *)malloc(RMSG_SIZE_2 * sizeof(int));
	if (rbuf2 == NULL)   {
	    fprintf(stderr, "Out of memory\n");
	    exit(-1);
	}

	rbuf3= (int *)malloc(RMSG_SIZE_3 * sizeof(int));
	if (rbuf3 == NULL)   {
	    fprintf(stderr, "Out of memory\n");
	    exit(-1);
	}

	/* Clear the receive buffers */
	memset(rbuf1, 0, sizeof(int) * RMSG_SIZE_3);
	memset(rbuf2, 0, sizeof(int) * RMSG_SIZE_2);
	memset(rbuf3, 0, sizeof(int) * RMSG_SIZE_3);

	/* Post the receives */
	rhandle1= miami_rx_start(rbuf1, sizeof(int) * RMSG_SIZE_1, tag);
	rhandle2= miami_rx_start(rbuf2, sizeof(int) * RMSG_SIZE_2, tag);
	rhandle3= miami_rx_start(rbuf3, sizeof(int) * RMSG_SIZE_3, tag);

	/* Tell the sender we are ready */
	ack= 1;
	shandle= miami_tx_start(&ack, sizeof(int), tag);
	while (!miami_tx_done(shandle))   {
	}
	printf("Test Sent ACK\n");

	/* Wit for the receives */
	while (!miami_rx_done(rhandle1, &bytes))   {
	}
	printf("Test Received %d bytes\n", bytes);
	if (bytes != RMSG_SIZE_1 * (int)sizeof(int))   {
	    printf("ERROR: Received %d bytes instead of %d\n", bytes, RMSG_SIZE_1 * (int)sizeof(int));
	    flag= 1;
	    rc= 1;
	}

	/* Wit for the receives */
	while (!miami_rx_done(rhandle2, &bytes))   {
	}
	printf("Test Received %d bytes\n", bytes);
	if (bytes != RMSG_SIZE_2 * (int)sizeof(int))   {
	    printf("ERROR: Received %d bytes instead of %d\n", bytes, RMSG_SIZE_2 * (int)sizeof(int));
	    flag= 1;
	    rc= 1;
	}


	/* Wit for the receives */
	while (!miami_rx_done(rhandle3, &bytes))   {
	}
	printf("Test Received %d bytes\n", bytes);
	if (bytes != RMSG_SIZE_1 * (int)sizeof(int))   {
	    printf("ERROR: Received %d bytes instead of %d\n", bytes, RMSG_SIZE_1 * (int)sizeof(int));
	    flag= 1;
	    rc= 1;
	}


	/* Check the data */

	/* We only wanted 50k in this 2M buffer */
	for (i= 0; i < RMSG_SIZE_1; i++)   {
	    if (rbuf1[i] != sbuf[i])   {
		fprintf(stderr, "Test Send and recv1 buf differ at pos %d: %d != %d\n", i, sbuf[i], rbuf1[i]);
		flag= 1;
		rc= 1;
		break;
	    }
	}
	/* The rest should be still zero */
	for (i= RMSG_SIZE_1 + 1; i < RMSG_SIZE_3; i++)   {
	    if (rbuf1[i] != 0)   {
		fprintf(stderr, "Test Recv1 buf not 0 at pos %d: %d\n", i, rbuf1[i]);
		flag= 1;
		rc= 1;
		break;
	    }
	}

	/* We wanted 2M in this 2M buffer */
	for (i= 0; i < RMSG_SIZE_2; i++)   {
	    if (rbuf2[i] != sbuf[i])   {
		fprintf(stderr, "Test Send and recv2 buf differ at pos %d: %d != %d\n", i, sbuf[i], rbuf2[i]);
		flag= 1;
		rc= 1;
		break;
	    }
	}


	/* Sender only sent 50k into this 2M buffer */
	for (i= 0; i < RMSG_SIZE_1; i++)   {
	    if (rbuf3[i] != sbuf[i])   {
		fprintf(stderr, "Test Send and recv3 buf differ at pos %d: %d != %d\n", i, sbuf[i], rbuf3[i]);
		flag= 1;
		rc= 1;
		break;
	    }
	}
	/* The rest should be still zero */
	for (i= RMSG_SIZE_1 + 1; i < RMSG_SIZE_3; i++)   {
	    if (rbuf3[i] != 0)   {
		fprintf(stderr, "Test Recv3 buf not 0 at pos %d: %d\n", i, rbuf3[i]);
		flag= 1;
		rc= 1;
		break;
	    }
	}

	if (flag)   {
	    printf("Test ERROR: Long message test FAILED\n");
	} else   {
	    printf("Test All three long message tests OK\n");
	}
    }

    miami_finalize();

    return rc;

}  /* end of main() */
