#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <sys/time.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <sys/wait.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <assert.h>
#include "client.h"
#include "netutils.h"
#include "config.h"
#include "stats.h"

void client_request_loop(struct sockaddr_in their_addr, 
			 int request_size, int number_of_messages)
{
  int numbytes;
  char *dummy_message;
  char recv_buf[MAX_RECV_BUFFER_SIZE];
  int msg_count = 0;
  int total_bytes = 0;
  int sockfd;
  struct timeval tv;
  struct timeval stv, rtv;
  struct timeval now_tv;

  double elapsed_time;
  int recv_bytes = 0;
  double *send_times;
  double *recv_times;
  double *wait_times;
  double *req_resp_times;

  // allocate arrays for send and receive times
  if (number_of_messages > 0)
  {
  send_times = (double *)malloc(sizeof(double) * number_of_messages);
  assert(send_times);
  recv_times = (double *)malloc(sizeof(double) * number_of_messages);
  assert(recv_times);
  wait_times = (double *)malloc(sizeof(double) * number_of_messages);
  assert(wait_times);
  req_resp_times = (double *)malloc(sizeof(double) * number_of_messages);
  assert(req_resp_times);
  }
  else
  {
  send_times = (double *)malloc(sizeof(double) * 1);
  assert(send_times);
  recv_times = (double *)malloc(sizeof(double) * 1);
  assert(recv_times);
  wait_times = (double *)malloc(sizeof(double) * 1);
  assert(wait_times);
  req_resp_times = (double *)malloc(sizeof(double) * 1);
  assert(req_resp_times);
  }

  // allocate message for request
  dummy_message = form_dummy_message(request_size);

  // open connection
  sockfd = open_connection((struct sockaddr *)&their_addr);

  get_time(&tv);

  while(number_of_messages == 0 || msg_count < number_of_messages) {
  	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(sockfd, &rfds);

    // send 
    get_time(&stv);
    send_message(sockfd, dummy_message, request_size);
    get_time(&now_tv);
    send_times[msg_count] = get_time_elapsed(&now_tv, &stv);

	// wait
    get_time(&rtv);
    select (sockfd + 1, &rfds, NULL, NULL, NULL);
    get_time(&now_tv);
    wait_times[msg_count] = get_time_elapsed(&now_tv, &rtv);

    // receive 
    get_time(&rtv);
    recv_bytes = recv_message(sockfd, recv_buf, MAX_RECV_BUFFER_SIZE);
    get_time(&now_tv);
    recv_times[msg_count] = get_time_elapsed(&now_tv, &rtv);

    // request & response together
    req_resp_times[msg_count] = get_time_elapsed(&stv, &now_tv);
    
    // increment total bytes
    total_bytes += request_size + recv_bytes;

    // increment number of requests sent
	if (number_of_messages > 0)
	{
      msg_count++;
	}
  }

  // get current time
  get_time(&now_tv);

  elapsed_time = get_time_elapsed(&now_tv, &tv);

  // close socket
  shutdown(sockfd, 2);


  print_summary_stats(elapsed_time, total_bytes, number_of_messages);

  print_array_stats("Sending", send_times, number_of_messages, 
		    request_size, config.sending_verbose_stats);
  print_array_stats("Waiting", wait_times, number_of_messages, 
		    request_size, config.sending_verbose_stats);
  print_array_stats("Receiving", recv_times, number_of_messages, 
		    recv_bytes, config.receiving_verbose_stats);
  print_array_stats("Request->Response", req_resp_times, number_of_messages,
		    request_size+recv_bytes, config.req_resp_verbose_stats);
  printf("\n");
}















