/*
 * agenda_server.cpp: Main function and some auxiliary functions
 * 
 * @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 "agenda_server.h"

#define FIND_ENTRY '1'
#define NEXT_ENTRY '2'
#define PREVIOUS_ENTRY '3'
#define EDIT_ENTRY '4'
#define ADD_ENTRY '5'
#define DELETE_ENTRY '6'
#define SAVE_ENTRIES '7'
#define LOAD_ENTRIES '8'

int search4entry(void);
int next_entry(void);
int previous_entry(void);
int edit_entry(void);
int add_entry(void);
int delete_entry(void);
int save_entries(void);
int load_entries(void);
entry_pointer blank_entry(void);
void connection_error_handler(void);

entry_pointer find_entry(entry_pointer ptr, char *pattern);
entry_pointer insert_entry(entry_pointer &headPtr, diary_entry new_entry);
entry_pointer remove_entry(entry_pointer &headPtr, entry_pointer ptr);
int save_list(entry_pointer ptr, char *filename);
int load_list(entry_pointer &headPtr, char *filename);
entry_pointer find_last(entry_pointer ptr);

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);
void close_connection(void);

entry_pointer headPtr=NULL, currentPtr=NULL;
int error_type=0;


void main(void){

	char packet_header[3];
	int result;

	if(create_connection()==-1)
		connection_error_handler();

	while(get_packet_header(packet_header)!=-1){
		switch(packet_header[1]){
		case FIND_ENTRY:
			result=search4entry();
			break;

		case NEXT_ENTRY:
			result=next_entry();
			break;

		case PREVIOUS_ENTRY:
			result=previous_entry();
			break;

		case EDIT_ENTRY:
			result=edit_entry();
			break;

		case ADD_ENTRY:
			result=add_entry();
			break;

		case DELETE_ENTRY:
			result=delete_entry();
			break;

		case SAVE_ENTRIES:
			result=save_entries();
			break;

		case LOAD_ENTRIES:
			result=load_entries();
			break;

		default:
			result=err_respond("Unknown command");
			break;
		}

		if(result==-1)
			connection_error_handler();
	}

	printf("\nClient disconnected.\n");
	close_connection();
}


int search4entry(void){

	char pattern[20];
	entry_pointer tempPtr;

	if(get_string(pattern)==-1) return -1;
	if(currentPtr!=NULL){
		if((tempPtr=find_entry(headPtr, pattern))==NULL){
			if(err_respond(strcat(pattern, " was not found"))==-1) return -1;
		}
		else{
			currentPtr=tempPtr;
			if(ok_respond(currentPtr)==-1) return -1;
		}
	}
	else
		if(err_respond("There is no registration in memory")==-1) return -1;

	return 0;
}


int next_entry(void){

	char string[2];

	if(currentPtr!=NULL){
		currentPtr=currentPtr->next;
		if(currentPtr==NULL) currentPtr=headPtr;
		if(ok_respond(currentPtr)==-1) return -1;
		}
	else
		if(err_respond("There is no registration in memory")==-1) return -1;
	if(get_string(string)==-1) return -1; // gets the two \n\n the client sends

	return 0;
}



int previous_entry(void){

	char string[2];

	if(currentPtr!=NULL){
		currentPtr=currentPtr->previous;
		if(currentPtr==NULL) currentPtr=find_last(headPtr);
		if(ok_respond(currentPtr)==-1) return -1;
		}
	else
		if(err_respond("There is no registration in memory")==-1) return -1;
	if(get_string(string)==-1) return -1; // gets the two \n\n the client sends

	return 0;
}


int edit_entry(void){

	entry_pointer tempPtr;
	diary_entry edited_entry;

	if(get_entry(edited_entry)==-1) return -1;
	if(currentPtr!=NULL){
		currentPtr=remove_entry(headPtr, currentPtr);
		if((tempPtr=insert_entry(headPtr, edited_entry))==NULL){
			if(err_respond("Error in editting the registration")==-1) return -1;
		}
		else{
			currentPtr=tempPtr;
			if(ok_respond(currentPtr)==-1) return -1;
		}
	}
	else
		if(err_respond("There is no registration in memory")==-1) return -1;

	return 0;
}


int add_entry(void){

	entry_pointer tempPtr;
	diary_entry new_entry;

	if(get_entry(new_entry)==-1) return -1;
	if((tempPtr=insert_entry(headPtr, new_entry))==NULL){
		if(err_respond("Error in adding the registration")==-1) return -1;
	}
	else{
		currentPtr=tempPtr;
		if(ok_respond(currentPtr)==-1) return -1;
	}

	return 0;
}


int delete_entry(void){

	char string[2];

	if(currentPtr!=NULL){
		currentPtr=remove_entry(headPtr, currentPtr);
		if(currentPtr!=NULL){
			if(ok_respond(currentPtr)==-1) return -1;
		}
		else 
			if(ok_respond(blank_entry())==-1) return -1;
	}
	else
		if(err_respond("There is no registration in memory")==-1) return -1;
	if(get_string(string)==-1) return -1; // gets the two \n\n the client sends

	return 0;
}


int save_entries(void){

	char filename[60];

	if(get_string(filename)==-1) return -1;
	if(currentPtr!=NULL){
		if(save_list(headPtr, filename)==-1){
			if(err_respond(strcat(filename, " could not be created"))==-1) return -1;
		}
		else
			if(ok_respond(currentPtr)==-1) return -1;
	}
	else
		if(err_respond("There is no registration in memory")==-1) return -1;

	return 0;
}


int load_entries(void){

	char filename[60];

	if(get_string(filename)==-1) return -1;
	if(load_list(headPtr, filename)==-1){
		switch(error_type){
		case OPEN_FILE_ERR:
			if(err_respond(strcat(filename, " could not be opened"))==-1) return -1;
			break;

		case READ_FILE_ERR:
			if(err_respond(strcat(filename, ": error in reading"))==-1) return -1;
			break;

		case INSERT_ENTRY_ERR:
			if(err_respond("Error in loading the list into memory")==-1) return -1;
			break;

		default:
			if(err_respond("Unknown error code")==-1) return -1;
			break;
		}
	}
	else{
		currentPtr=headPtr;
		if(ok_respond(currentPtr)==-1) return -1;
	}

	return 0;
}


entry_pointer blank_entry(void){
	
	static entry_pointer ptr;
	static bool exist=false;

	if(!exist){
		ptr=(entry_pointer)malloc(sizeof(diary_entry));
		strcpy(ptr->first_name, "");
		strcpy(ptr->last_name, "");
		strcpy(ptr->email, "");
		strcpy(ptr->phone, "");
		ptr->next=NULL;
		ptr->previous=NULL;
		exist=true;
	}

	return ptr;
}


void connection_error_handler(void){
		switch(error_type){
		case WSA_ERR:
			printf("\nWSAStartup failed\n");
			break;

		case SOCKET_ERR:
			printf("\nError in creating the socket\n");
			break;

		case BIND_ERR:
			printf("\nError in binding the socket to the port\n");
			break;

		case LISTEN_ERR:
			printf("\nError in listening to the socket's port\n");
			break;

		case ACCEPT_ERR:
			printf("\nError in accepting the client's request\n");
			break;

		case RECV_ERR:
			printf("\nError in receiving the packets from the client\n");
			break;

		case SEND_ERR:
			printf("\nError in sending the packets to the client\n");
			break;

		case CLIENT_DISCONNECTED:
			printf("\nClient disconnected unexpectedly\n");
			break;

		default:
			printf("\nUnknown error code\n");
			break;
		}
		close_connection();
		exit(1);
}




