/* (c) 2005 Tomas Plachetka */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>

#include "tpl.h"

#if defined(__MINGW32__)
	#include <sys/timeb.h>

	int get_time(struct timeval *tp)
	{
		struct timeb tb;

		ftime(&tb);

		tp->tv_sec = tb.time;
		tp->tv_usec = tb.millitm * 1000;

		return 0;
	}
#else
	#define get_time(x) gettimeofday(x, NULL)
#endif

/*****************************************************************************
* Local preprocessor defines
******************************************************************************/

#define DEBUG(x)

/*****************************************************************************
* Local typedefs
******************************************************************************/

enum 
{
  MSG_INIT = 0,
  MSG_PING,
  MSG_PONG,
  MSG_QUIT
};

enum
{
  RANK_PONG = 0,
  RANK_PING
};

/*****************************************************************************
* Local variables
******************************************************************************/

static int nr_msgs;
static int msg_size;

static char *databuf;

static int rank_ping = RANK_PING;
static int rank_pong = RANK_PONG;
static  int my_rank;

static struct timeval tv1, tv2;
static float elapsed_time, mbytes;

/*****************************************************************************
* Static functions
******************************************************************************/

static int match_all(int sender, int tag, void *message);
static void ping();
static void pong();

static int match_all(int sender, int tag, void *message)
{
  return(1);
}

static void ping(void)
{
  int counter;
  void *sendbuf;

  for (counter = 0; counter < nr_msgs; counter++)
  {
    tpl_create(&sendbuf);
    DEBUG(printf("Sending %d\n", my_rank);fflush(stdout);)
    tpl_pkchar(sendbuf, databuf, msg_size);
    tpl_send(&rank_pong, 1, MSG_PING, sendbuf);
    DEBUG(printf("Sent %d\n", my_rank);fflush(stdout);)
  }

}

static void pong(void)
{
  int counter, i;
  void *message;
  int tag;
  int sender;

  char *buf;

  /* Start timer. */
  get_time(&tv1);

  buf = (char *) malloc(msg_size);
  for (counter = 0; counter < nr_msgs; counter++)
  {
    DEBUG(printf("Receiving %d\n", my_rank);fflush(stdout);)
    tpl_recv(match_all, &sender, &tag, &message);
    tpl_upkchar(message, buf, msg_size);
    tpl_destroy(message);
    DEBUG(
    for (i = 0; i < msg_size; i++)
      printf("%c", buf[i]);
    printf("\n");
    printf("Received %d\n", my_rank);fflush(stdout);
    )
  }
  
  /* Stop timer. */
  get_time(&tv2);

  elapsed_time = tv2.tv_sec - tv1.tv_sec +
   (tv2.tv_usec - tv1.tv_usec) / 1e6;
        
  mbytes = 1.0 * (float) nr_msgs * (float) msg_size / 1048576.0;
  printf("%d x %d Bytes x 1 = %f MBytes, %f s, %f MB/s, %f msg/s, %f s/msg\n", 
   nr_msgs, msg_size, mbytes, elapsed_time, mbytes / elapsed_time, 
   nr_msgs / elapsed_time, elapsed_time / nr_msgs);
}

int main(int argc, char **argv)
{
  int counter;
  int nr_procs = 2;

  if (argc != 3)
  {
    printf("Usage: sendrecv <nr_msgs> <msg_size>\n");
    exit(1);
  }

  tpl_initialize(&nr_procs, &my_rank, &argc, &argv);

  tpl_register_function(match_all, "match_all");

  nr_msgs = atoi(argv[1]);
  msg_size = atoi(argv[2]);

  if (msg_size > 0)
  {
    databuf = (char *) malloc(msg_size * sizeof(char));
    for (counter = 0; counter < msg_size; counter++)
      *(databuf + counter) = '0' + counter % 10;
  }

  switch(my_rank)
  {
    case RANK_PING:
      ping();
      break;
    
    case RANK_PONG:
      pong();
      break;
    
    default:
      printf("Unknown role\n");
      exit(1);
      break;
  }

  /* Terminate the program. */
  tpl_deinitialize();

  if (msg_size > 0)
  {
    free(databuf);
  }

  return(0);
}
