/*
 * connection.cpp: Functions that handle the connection with the client
 * 
 * @author: Alexander Mikroyannidis
 * web site: http://www.geocities.com/alexmikro
 * e-mail: alexmikro@hotmail.com
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <winsock.h>
#include "agenda_server.h"

#define MYPORT 2411 // the port users will be connecting to
#define BACKLOG 1 // how many pending connections queue will hold

int create_connection(void);
int get_packet_header(char *packet_header);
int get_string(char *string);
int get_entry(diary_entry &new_entry);
int ok_respond(entry_pointer ptr);
int err_respond(char *message);
int check_connection(int numbytes);
void close_connection(void);

extern int error_type;
int client_fd; // the identifier of the client


int create_connection(void){

	int sock_fd, sin_size; // sock_fd is the identifier of the socket
	struct sockaddr_in my_addr; // my address information
	struct sockaddr_in their_addr; // connector’s address information

	WSADATA wsaData;									// necessary
	if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {	// for windows connections
		error_type=WSA_ERR;
		return -1;
	}

	if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		error_type=SOCKET_ERR;
		return -1;
	}

	my_addr.sin_family = AF_INET; // host byte order
	my_addr.sin_port = htons(MYPORT); // short, network byte order
	my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
	memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

	if (bind(sock_fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1) {
		error_type=BIND_ERR;
		return -1;
	}

	if (listen(sock_fd, BACKLOG) == -1) {
		error_type=LISTEN_ERR;
		return -1;
	}

	printf("Listening for incoming requests...\n");
	sin_size = sizeof(struct sockaddr_in);
	if ((client_fd = accept(sock_fd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
		error_type=ACCEPT_ERR;
		return -1;
	}

	closesocket(sock_fd); // disallowing more clients to be connected

	printf("Got connection from %s\n", inet_ntoa(their_addr.sin_addr));
	return 0;
}


int get_packet_header(char *packet_header){

	int numbytes;

	numbytes=recv(client_fd, packet_header, 2, 0);
	if(check_connection(numbytes)==-1) return -1;
	packet_header[2]='\0';
	printf("\nReceived header: %s\n", packet_header);
	return 0;
}



int get_string(char *string){

	int numbytes;

	numbytes=recv(client_fd, string, 60, 0);
	if(check_connection(numbytes)==-1) return -1;
	string[numbytes-2]='\0';
	if(strcmp(string, "")!=0) // checks if the string contained just the two \n\n
		printf("Received: %s\n", string);
	return 0;
}



int get_entry(diary_entry &new_entry){

	int numbytes;
	char string[2];

	numbytes=recv(client_fd, new_entry.first_name, 20, 0);
	if(check_connection(numbytes)==-1) return -1;
	new_entry.first_name[20]='\0';
	printf("Received: %s\n", new_entry.first_name);

	numbytes=recv(client_fd, new_entry.last_name, 20, 0);
	if(check_connection(numbytes)==-1) return -1;
	new_entry.last_name[20]='\0';
	printf("Received: %s\n", new_entry.last_name);
	
	numbytes=recv(client_fd, new_entry.email, 40, 0);
	if(check_connection(numbytes)==-1) return -1;
	new_entry.email[40]='\0';
	printf("Received: %s\n", new_entry.email);
	
	numbytes=recv(client_fd, new_entry.phone, 15, 0);
	if(check_connection(numbytes)==-1) return -1;
	new_entry.phone[15]='\0';
	printf("Received: %s\n", new_entry.phone);

	numbytes=recv(client_fd, string, 2, 0); // gets the two \n\n the client sends
	if(check_connection(numbytes)==-1) return -1;

	return 0;
}



int ok_respond(entry_pointer ptr){

	if (send(client_fd, "0", 1, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}
	if (send(client_fd, ptr->first_name, 20, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}
	if (send(client_fd, ptr->last_name, 20, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}
	if (send(client_fd, ptr->email, 40, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}
	if (send(client_fd, ptr->phone, 15, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}
	if (send(client_fd, "\n", 1, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}

	return 0;
}


int err_respond(char *message){

	if (send(client_fd, " ", 1, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}
	if (send(client_fd, message, strlen(message), 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}
	if (send(client_fd, "\n", 1, 0) == -1){
		error_type=SEND_ERR;
		return -1;
	}

	return 0;
}



int check_connection(int numbytes){

	if (numbytes == -1) {
		error_type=RECV_ERR;
		return -1;
	}

	if (numbytes == 0) {
		error_type=CLIENT_DISCONNECTED;
		return -1;
	}

	return 0;
}



void close_connection(void){

	closesocket(client_fd);
	printf("Server disconnected.\n");

}
