/* client/server to demonstrate the vector time
   needs config-file called cliser.ini with
   <nr. of client> <ip of client> <port of client>
   in it */

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define INITFILE "cliser.ini"
#define MAX 10	/* max. nr. processes */

int n=0;	/* actual nr. of processes */

/* PROCESS-IDENTIFICATION */
struct process {
	char ip[30];
	unsigned int port;
}; 

typedef struct process Tp;

/* READ INIT FILE */
int read_init( Tp* p, char* my_port)
{
  FILE* init;
  char line[64], ip[30];
  int index, ret;
  unsigned int port;

  ret = -1;	/* default value */

  init = fopen(INITFILE, "r");
  if (init == NULL) {
	printf("Error fopen()");
	exit(1);
  }

  /* get IP and Port out of initfile */
  printf("Found:\n");
  while( fgets(line, sizeof(line), init) != NULL) {
	sscanf(line, "%d %s %d", &index, ip, &port);
	strcpy(p[index-1].ip, ip); 
	p[index-1].port = port;
	printf("NUMBER: %d IP: %s PORT: %d\n", index, ip, port);
	if ( atoi(my_port) == port) ret = index;
	n++; index++;
  }
  printf("\n%d Processes\n", n);
  return ret;
}
	
/* set time to 0 for each process */
void init_time(int* time )
{
	int i;
	for (i=0; i<n; i++)
		time[i] = 0;
}

/* converts array time to a string */
void time2string(int* time, char* str)
{
  	int index;
	char temp[50];
	str[0] = '\0';
	for(index=0;index<n; index++) {
		sprintf(temp, "|%d|", time[index]); 
		strcat(str, temp); 
	}
}

/* set time[index] to the maximum value */
void update_time( int* time, char* message)
{
   	int other_time[MAX], index;
	char rest[512];

	strcpy(rest, message);
	for(index=0;index<n; index++) {
		sscanf(rest, "|%d|%s", &other_time[index], rest); 
	}
	for(index=0;index<n; index++) {
		if ( time[index] < other_time[index] )
			time[index] = other_time[index];
	}
}

void print_time(int* time)
{
	int index;
        for(index=0;index<n; index++) 
		printf("|%d|", time[index]);
}

int main(int argc, char* argv[]){
	
	int sock;
	int ret;
	struct sockaddr_in myaddr;
	struct sockaddr_in otheraddr;
	char buffer[1024], what[20];
	int size, number, my_number;

	Tp p[MAX];		/* Processes   */
	int time[MAX];		/* time vector */
	char time_str[512];	/* time string */
	
	if (argc != 2) {
		printf("usage: %s my-port-nr \n",argv[0]);
		exit(1);
	}

	my_number = read_init(p, argv[1]);	/* read init file */
	init_time(time);			/* set time to 0  */
	
	sock = socket(AF_INET, SOCK_DGRAM, 0); 
	if (sock == -1) {
		perror("socket() error");
		exit(1);
	}
	
	/* My address specified by port */
	myaddr.sin_family 	= PF_INET;
	myaddr.sin_addr.s_addr 	= htonl(INADDR_ANY);
	myaddr.sin_port 	= htons(atoi(argv[1]));

	/* bind the socket to the port */
	ret = bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr));
	if (ret == -1) {
		perror("connect() error");
		exit(1);
	}


	while(1) {
		/* read from stdin */
	      	printf("\n(%d)Type: [send <number> | receive | local | time | end] RETURN\n",my_number) ;
      	    	gets(buffer); sscanf(buffer,  "%s %d", what, &number);

		/* what do we have to do? */
		if( strcmp(what,"send") == 0 ) {

			/* set the other address */
			size = sizeof(otheraddr);
			otheraddr.sin_family 		= PF_INET;
			otheraddr.sin_addr.s_addr 	= htonl(inet_addr(p[number-1].ip));
			otheraddr.sin_port 		= htons(p[number-1].port);

			/* increment my time */
			time[my_number-1]++;
			printf("      new time: "); print_time(time); printf("\n");  

			/* send my time vector */
			time2string(time, buffer); strcat(buffer, "\r\n");

			sendto(sock, &buffer[0], strlen(buffer)+1, 0, 
			(struct sockaddr *) &otheraddr, size);

			/* say what we did */ 
			printf("  send message: %sto IP %s PORT %d\r\n", 
			buffer, p[number-1].ip, p[number-1].port);

		} else if ( strcmp(what, "receive") == 0) {

			/* increment my time */
			time[my_number-1]++;

			/* get message (other time vector) */
			recvfrom(sock, &buffer[0], sizeof(buffer), 0,
		         (struct sockaddr *) &otheraddr, &size);

			/* what did we receive and whats my (old) time vector */
			printf(" message: %s my time: ",buffer); print_time(time); printf("\n");

			/* update my time vector */
			update_time(time, buffer);

			/* my new time vector */
			printf("new time: "); print_time(time); printf("\n");    	

		} else if ( strcmp(what, "local") == 0 ) {

                        /* increment my time */
			time[my_number-1]++;

                        /* my new time vector */
			printf("      new time: "); print_time(time); printf("\n");	

		} else if ( strcmp(what, "time") == 0) {
			printf("my time vector: "); print_time(time); printf("\n");	
		} else if ( strcmp(what, "end") == 0) {
			close(sock);
			return 0;
		}
	}
}
