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

// stores options
config_type config;


/* Sends message 'msg' of size 'size' using file descriptor 'new_fd'. */
void send_message(int new_fd, char *msg, int size)
{
  int num_bytes = 0, total_bytes = 0;
  
  // "send" is not guaranteed to send entire message on one call.
  while(1) {
    // send message
    num_bytes = send(new_fd, msg, size, 0);

    // check for error
    if ( num_bytes == -1) {
      perror("send");
    }

    // debug
    if (config.terse_debug) {
      fprintf(stderr, "Bytes sent: %d \n", num_bytes);
    }

    // check if all of response has been sent
    total_bytes += num_bytes;
    if (total_bytes == size) 
      break;

  }

}

/* Receives message into 'buf' (whose size is 'bufsize') using file
   descriptor 'sockfd'. Returns number of bytes received    */
int recv_message(int sockfd, char *buf, int bufsize)
{
  int numbytes;
  int totalBytes = 0;

  // recv may not get message in one call if 'bufsize' is not large enough
  while (1) {
    
    // debug
    if (config.terse_debug) {
      fprintf(stderr, "Waiting for message\n");
    }

    // receive message (may require more than one call.)
    if ((numbytes=recv(sockfd, buf, bufsize-1, 0)) == -1) {
      perror("recv");
      exit(1);
    }

    // debug
    if (config.verbose_debug) {
      buf[numbytes] = '\0';
      fprintf(stderr, "Received: (%d) %s\n", numbytes, buf);
    }

    // add up total number of bytes received for this message
    totalBytes += numbytes;

    // check if at end of message
    if (buf[numbytes-1] == 'Z') {
      // debug
      if (config.terse_debug) {
	fprintf(stderr, "End of message received: %d bytes\n", numbytes);
      }
      break;
    }
  } // while

  return totalBytes;
}


// Create and return dummy message of size 'size'
char *form_dummy_message(int size)
{
  char *dummy_message;
  int i;
  static int msg_id = 1;

  // create dummy message
  dummy_message = (char *)malloc(sizeof(char) * size);
  assert(dummy_message);

  // the end of a message is designated with a 'Z'
  for (i = 0; i < size; i++) {
    dummy_message[i] = 'X';
  }
  dummy_message[0] = 'B';
  memcpy(&dummy_message[1], &msg_id, 4);  
  dummy_message[i-1] = 'Z';

  return dummy_message;
}


// Get time
void get_time(struct timeval *t) 
{
  if (gettimeofday(t, NULL) != 0) {
    perror("gettimeofday");
  }
}

// Compute time difference; return value in milliseconds
double get_time_difference(struct timeval *big_tv, struct timeval *small_tv) 
{
  unsigned long total_microseconds;
  double total_milliseconds;

  total_microseconds  = abs (1000000*(big_tv->tv_sec  - small_tv->tv_sec));
  total_microseconds += abs (big_tv->tv_usec - small_tv->tv_usec);

  total_milliseconds = ( ( (double) total_microseconds) / ( (double) 1000) ); 

  return total_milliseconds;
}

// Compute time difference from now, return in milliseconds
double get_time_elapsed(struct timeval *past_tv, struct timeval * now_tv)
{
  // compare to past
  return (get_time_difference(now_tv, past_tv));
}

