#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  char valueToSend[256] = {'\0'};
  char valueToReceive[256] = {'\0'};
  char iterationsServer[256] = {'\0'};

  int iterations;

  struct timeval startTime, endTime;
  double timeServ;

  printf("Inserire il numero di iterazioni: ");
  scanf("%d", &iterations);
  if (!iterations) {
    exit(1);
  }
  snprintf(iterationsServer, sizeof(iterationsServer), "%d", iterations);

  int simpleSocket = 0;
  int simplePort = 0;
  int returnStatus = 0;
  char buffer[256] = "";
  struct sockaddr_in simpleServer;

  if (argc != 3) {
    fprintf(stderr, "Usage: %s <server> <port>\n", argv[0]);
    exit(1);
  }

  /* create a streaming socket      */
  simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  if (simpleSocket == -1) {
    fprintf(stderr, "Could not create a socket!\n");
    exit(1);
  } else {
    fprintf(stderr, "Socket created!\n");
  }

  /* retrieve the port number for connecting */
  simplePort = atoi(argv[2]);

  /* setup the address structure */
  /* use the IP address sent as an argument for the server address  */
  // bzero(&simpleServer, sizeof(simpleServer));
  memset(&simpleServer, '\0', sizeof(simpleServer));
  simpleServer.sin_family = AF_INET;
  // inet_addr(argv[2], &simpleServer.sin_addr.s_addr);
  simpleServer.sin_addr.s_addr = inet_addr(argv[1]);
  simpleServer.sin_port = htons(simplePort);

  /*  connect to the address and port with our socket  */
  returnStatus = connect(simpleSocket, (struct sockaddr *)&simpleServer,
                         sizeof(simpleServer));

  if (returnStatus == 0) {
    printf("Connect successful!\n");
  } else {
    fprintf(stderr, "Could not connect to address!\n");
    close(simpleSocket);
    exit(1);
  }

  // Inviando il numero di iterazioni al server
  write(simpleSocket, iterationsServer, strlen(iterationsServer));

  // Avvio il timer
  gettimeofday(&startTime, NULL);

  // Aspettando l'ACK
  read(simpleSocket, valueToReceive, sizeof(valueToReceive));
  if (strcmp(valueToReceive, "ACK") != 0) {
    fprintf(stderr, "Invalid ACK");
    exit(0);
  }
  printf("%s\n", valueToReceive);

  int i = 0;
  while (i < iterations) {
    int num1;
    int num2;
    char operator;

    // Pulisco i buffer
    memset(&valueToReceive, '\0', sizeof(valueToReceive));
    memset(&valueToSend, '\0', sizeof(valueToSend));

    printf("Inserire il valore da voler inviare al server con il formato num "
           "num operator: ");
    scanf("%d %d %c", &num1, &num2, &operator);
    if (num2 == 0 && operator== '/') {
      fprintf(stderr, "Impossibile dividere per zero!");
    } else {
      snprintf(valueToSend, sizeof(valueToSend), "%d %d %c", num1,
               num2, operator);
      write(simpleSocket, valueToSend, strlen(valueToSend));
      read(simpleSocket, valueToReceive, sizeof(valueToReceive));
      printf("\n\nEcho: %s\n", valueToReceive);
      ++i;
    }
  }

  // Invio il BYE
  memset(&valueToSend, '\0', sizeof(valueToSend));
  snprintf(valueToSend, sizeof(valueToSend), "BYE");
  write(simpleSocket, valueToSend, sizeof(valueToSend));

  // Aspettando l'ACK
  read(simpleSocket, valueToReceive, sizeof(valueToReceive));
  if (strcmp(valueToReceive, "ACK") != 0) {
    fprintf(stderr, "Invalid ACK");
    exit(0);
  }
  printf("%s\n", valueToReceive);

  close(simpleSocket);

  // Spengo il timer
  gettimeofday(&endTime, NULL);

  timeServ = (endTime.tv_sec + (endTime.tv_usec / 1000000.0)) -
             (startTime.tv_sec + (startTime.tv_usec / 1000000.0));

  printf("Service Time: %.2f", timeServ);

  return 0;
}