#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#if defined(__MINGW32__)
	#include <windows.h>
	#include <winbase.h>
#endif

#include "MPS_consts.h"

#define MAXCOLUMNS 14
#define DELIMITER ';'

FILE *logfile;
char logline[4096];
int loglinelength;
char emptystring = 0;
int endreading = 0;				/* non-zero = stop reading log file */
int serverstarted = 0;			/* non-zero = server is started */
char *loglinecolumns[MAXCOLUMNS];
int section_update[4] = {1, 0, 0, 0};	/* update statistics while in section ? */
int section_warn[4] = {1, 0, 0, 0};		/* check warnings while in section ? */
int initialization_type;		/* -1 = unknown, 0 = POSIX, 1 = MINGW */
int init_sync_status;

#if defined(__MINGW32__)
LARGE_INTEGER epoch_time;
#else
time_t local_time_shift;
#endif


/* common columns */
int eventid;				/* event id */
int resultid;				/* event result: 0 = unsuccesful */
long long eventtime;		/* event time in ms from epoch */
char *eventtimetext;		/* event time string */
long int pid;				/* client pid */
int opsync;					/* sync/async operation: -1 = NA, 0 = async, 1 = sync */
int errorid;				/* event error id */
char *eventtext;			/* event text description */

typedef struct _message_struct_
{
	long int mid;								/* message id */
	int isreserved;								/* 0 = message is created */
	long long delivery_start;					/* time of delivery start */
	long long delivery_finish;					/* time of delivery finish */
	int mlength;								/* message length */
	int opsync;									/* sync/async operation: -1 = NA, 0 = async, 1 = sync */
	int section_type;							/* 0 - normal communication, 1 - initialization, 2 - initial synchronization, 3 - final synchronization */

	struct _message_struct_ *next, *prev;
} message_struct;

typedef struct _client_connected_struct_
{
	long long connected;						/* time of connect */
	long long disconnected;						/* time of disconnect */

	struct _client_connected_struct_ *next, *prev;
} client_connected_struct;

typedef struct _client_struct_
{
	long int pid;								/* client pid */
	int connected;								/* is client connected */
	int started;								/* is client started */
	long long first_connect;					/* time of first connect */
	long long last_disconnect;					/* time of last disconnect */
	long long time_connected;					/* sum of connected time */
	client_connected_struct *connected_list;	/* list of connected periods */
	message_struct *message_list;				/* list of messages */
	int section_type;							/* 0 - normal communication, 1 - initialization, 2 - initial synchronization, 3 - final synchronization */
	long int section_mid;						/* message id identifying the section */

	int msg_recv_fail_num;						/* number of failed recv messages */
	int msg_recv_succ_num;						/* number of successful recv messages */
	int msg_recv_succ_len;						/* length of successful recv messages */
	int msg_recv_succ_min_len;					/* minimal length of successful recv messages */
	int msg_recv_succ_max_len;					/* maximal length of successful recv messages */

	int msg_recv_imm_num;						/* number of recv messages received immediatelly */
	int msg_recv_imm_len;						/* length of recv messages received immediatelly */
	int msg_recv_imm_min_len;					/* minimal length of recv messages received immediatelly */
	int msg_recv_imm_max_len;					/* maximal length of recv messages received immediatelly */
	int msg_recv_delay_num;						/* number of recv messages received delayed */
	int msg_recv_delay_len;						/* length of recv messages received delayed */
	int msg_recv_delay_min_len;					/* minimal length of recv messages received delayed */
	int msg_recv_delay_max_len;					/* maximal length of recv messages received delayed */
	long long msg_recv_delay_delay;				/* delay of recv messages received delayed */
	long long msg_recv_delay_min_delay;			/* minimal delay of recv messages received delayed */
	long long msg_recv_delay_max_delay;			/* maximal delay of recv messages received delayed */

	int msg_send_fail_num;						/* number of failed send messages */
	int msg_send_fail_len;						/* length of failed send messages */
	int msg_send_fail_min_len;					/* minimal length of failed send messages */
	int msg_send_fail_max_len;					/* maximal length of failed send messages */
	int msg_send_succ_num;						/* number of successful send messages */
	int msg_send_succ_len;						/* length of successful send messages */
	int msg_send_succ_min_len;					/* minimal length of successful send messages */
	int msg_send_succ_max_len;					/* maximal length of successful send messages */

	int msg_send_async_num;						/* number of asynchronous send messages */
	int msg_send_async_len;						/* length of asynchronous send messages */
	int msg_send_async_min_len;					/* minimal length of asynchronous send messages */
	int msg_send_async_max_len;					/* maximal length of asynchronous send messages */
	int msg_send_sync_num;						/* number of synchronous send messages */
	int msg_send_sync_len;						/* length of synchronous send messages */
	int msg_send_sync_min_len;					/* minimal length of synchronous send messages */
	int msg_send_sync_max_len;					/* maximal length of synchronous send messages */

	int msg_send_imm_num;						/* number of send messages sent immediatelly */
	int msg_send_imm_len;						/* length of send messages sent immediatelly */
	int msg_send_imm_min_len;					/* minimal length of send messages sent immediatelly */
	int msg_send_imm_max_len;					/* maximal length of send messages sent immediatelly */
	int msg_send_delay_num;						/* number of send messages sent delayed */
	int msg_send_delay_len;						/* length of send messages sent delayed */
	int msg_send_delay_min_len;					/* minimal length of send messages sent delayed */
	int msg_send_delay_max_len;					/* maximal length of send messages sent delayed */
	long long msg_send_delay_delay;				/* delay of send messages sent delayed */
	long long msg_send_delay_min_delay;			/* minimal delay of send messages sent delayed */
	long long msg_send_delay_max_delay;			/* maximal delay of send messages sent delayed */

	struct _client_struct_ *next, *prev;
} client_struct;


client_struct *client_list = NULL;				/* list of clients */
client_struct *current_client;					/* current client */

#define UPDATE_MIN_VAL(x,y) if (x == -1 || x > y) x = y
#define UPDATE_MAX_VAL(x,y) if (x == -1 || x < y) x = y
#define UPDATE_MIN_VAL_LL(x,y) if (x == -1LL || x > y) x = y
#define UPDATE_MAX_VAL_LL(x,y) if (x == -1LL || x < y) x = y

message_struct *addmessage(message_struct **list, int newmid, int isreserved, int mlength, int opsync, int section_type)
{
	message_struct *message;

	if ( list == NULL ) return NULL;

	message = (message_struct *) malloc(sizeof(message_struct));

	message->mid = newmid;
	message->isreserved = isreserved;
	message->delivery_start = 0LL;
	message->delivery_finish = 0LL;
	message->mlength = mlength;
	message->opsync = opsync;
	message->section_type = section_type;

	if (*list == NULL)
	{
		message->next = message;
		message->prev = message;
		*list = message;
	}
	else
	{
		message->next = *list;
		message->prev = (*list)->prev;

		(*list)->prev->next = message;
		(*list)->prev = message;
	}

	return message;
}

void deletemessage(message_struct **list, message_struct *message)
{
	if (message == message->next)
	{
		free(message);
		*list = NULL;
	}
	else
	{
		if (*list == message)
		{
			*list = (*list)->next;
		}

		message->next->prev = message->prev;
		message->prev->next = message->next;

		free(message);
	}
}

void deletemessage_id(message_struct **list, int oldmid)
{
	message_struct *message;

	if (list == NULL) return;
	if (*list == NULL) return;

	message = *list;

	do
	{
		if (message->mid == oldmid) deletemessage(list, message);

		message = message->next;
	} while (message != *list);
}

void deletemessages(message_struct **list)
{
	message_struct *message, *del_message;

	if (list == NULL) return;
	if (*list == NULL) return;

	message = *list;

	/* delete messages */
	do
	{
		del_message = message;
		message = message->next;


		free(del_message);
	} while (message != *list);

	*list = NULL;
}

message_struct *findmessage(message_struct **list, int mid)
{
	message_struct *message;

	if (list == NULL) return NULL;
	if (*list == NULL) return NULL;

	message = *list;

	do
	{
		if (message->mid == mid) return message;

		message = message->next;
	} while (message != *list);

	return NULL;
}

void addclient(int newpid)
{
	client_struct *client;

	client = (client_struct *) malloc(sizeof(client_struct));
	memset(client, 0, sizeof(client_struct));

	client->pid = newpid;
	client->started = 1;
/*	client->connected = 0;
	client->first_connect = 0LL;
	client->last_disconnect = 0LL;
	client->time_connected = 0LL;
	client->connected_list = NULL;
	client->message_list = NULL;*/
	client->msg_recv_succ_min_len = -1;
	client->msg_recv_succ_max_len = -1;

	client->msg_recv_imm_min_len = -1;
	client->msg_recv_imm_max_len = -1;
	client->msg_recv_delay_min_len = -1;
	client->msg_recv_delay_max_len = -1;
	client->msg_recv_delay_min_delay = -1LL;
	client->msg_recv_delay_max_delay = -1LL;

	client->msg_send_fail_min_len = -1;
	client->msg_send_fail_max_len = -1;
	client->msg_send_succ_min_len = -1;
	client->msg_send_succ_max_len = -1;

	client->msg_send_async_min_len = -1;
	client->msg_send_async_max_len = -1;
	client->msg_send_sync_min_len = -1;
	client->msg_send_sync_max_len = -1;

	client->msg_send_imm_min_len = -1;
	client->msg_send_imm_max_len = -1;
	client->msg_send_delay_min_len = -1;
	client->msg_send_delay_max_len = -1;
	client->msg_send_delay_min_delay = -1LL;
	client->msg_send_delay_max_delay = -1LL;

	if (client_list == NULL)
	{
		client->next = client;
		client->prev = client;
		client_list = client;
	}
	else
	{
		client->next = client_list;
		client->prev = client_list->prev;

		client_list->prev->next = client;
		client_list->prev = client;
	}
}

void connectcurrentclient()
{
	client_connected_struct *connected_list;

	current_client->connected = 1;
	if (current_client->first_connect == 0LL) current_client->first_connect = eventtime;


	connected_list = (client_connected_struct *) malloc(sizeof(client_connected_struct));

	connected_list->connected = eventtime;
	connected_list->disconnected = 0LL;

	if (current_client->connected_list == NULL)
	{
		connected_list->next = connected_list;
		connected_list->prev = connected_list;
		current_client->connected_list = connected_list;
	}
	else
	{
		connected_list->next = current_client->connected_list;
		connected_list->prev = current_client->connected_list->prev;

		connected_list->prev->next = connected_list;
		current_client->connected_list->prev = connected_list;
	}
}

void disconnectcurrentclient()
{
	message_struct *message;

	current_client->connected = 0;
	current_client->last_disconnect = eventtime;

	current_client->connected_list->prev->disconnected = eventtime;
	current_client->time_connected += ( current_client->connected_list->prev->disconnected - current_client->connected_list->prev->connected );


	/* print unsent/undeleteted messages */
	if (current_client->message_list == NULL) return;

	message = current_client->message_list;

	do
	{
		fprintf(stderr, "Error: message not sent/deleted: %li - %li - %s - %s\n", pid, message->mid, eventtimetext, eventtext);

		message = message->next;
	} while (message != current_client->message_list);
}

void deleteclients()
{
	client_struct *client, *del_client;
	client_connected_struct *connected_list, *del_connected_list;

	if (client_list == NULL) return;

	client = client_list;

	/* delete clients */
	do
	{
		del_client = client;
		client = client->next;

		if (del_client->connected != 0)
		{
			current_client = del_client;
			disconnectcurrentclient();
		}

		/* delete connected list */
		if (del_client->connected_list != NULL)
		{
			connected_list = del_client->connected_list;

			do
			{
				del_connected_list = connected_list;
				connected_list = connected_list->next;

				free(del_connected_list);
			} while (connected_list != del_client->connected_list);
		}

		/* delete message list */
		deletemessages(&(del_client->message_list));

		free(del_client);
	} while (client != client_list);

	client_list = NULL;
}

client_struct *findclient(long int pid)
{
	client_struct *client;

	if (client_list == NULL) return NULL;

	client = client_list;

	do
	{
		if (client->pid == pid) return client;
		client = client->next;
	} while (client != client_list);

	return NULL;
}

void decodelogline()
{
	int pos;
	char *delim;

	for (pos = 1; pos < MAXCOLUMNS; pos++ ) loglinecolumns[pos] = NULL;

	loglinecolumns[0] = (char *) &logline;

	delim = strchr(loglinecolumns[0], DELIMITER);

	pos = 1;

	while (delim != NULL && pos < MAXCOLUMNS)
	{
		*delim = 0;
		loglinecolumns[pos] = delim + 1;

		delim = strchr(loglinecolumns[pos], DELIMITER);
		pos++;
	}

	if (delim != NULL) *delim = 0;

	for (pos = 1; pos < MAXCOLUMNS; pos++ )
	{
		if ( loglinecolumns[pos] == NULL ) loglinecolumns[pos] = (char *) &emptystring;
	}

}

void decodeloglinecolumns_common()
{
#if defined(__MINGW32__)
	SYSTEMTIME system_time;
	FILETIME file_time;
	LARGE_INTEGER li_time;
	unsigned int year, month, day, hours, minutes, seconds, miliseconds;
#else
	struct tm tm;
	time_t timesec;
	int timemsec;
#endif
/*long long eventtime;*/

	eventid = ( *(loglinecolumns[0]) == 0 ) ? 0 : atoi(loglinecolumns[0]);
	resultid = ( *(loglinecolumns[1]) == 0 ) ? 0 : atoi(loglinecolumns[1]);


	eventtimetext = loglinecolumns[2];
	if ( *(loglinecolumns[2]) != 0 )
	{
#if defined(__MINGW32__)
		sscanf(loglinecolumns[2], "%u-%u-%u %u:%u:%u.%u", &year, &month, &day, &hours, &minutes, &seconds, &miliseconds);
		system_time.wYear = year;
		system_time.wMonth = month;
		system_time.wDay = day;
		system_time.wHour = hours;
		system_time.wMinute = minutes;
		system_time.wSecond = seconds;
		system_time.wMilliseconds = miliseconds;

		SystemTimeToFileTime(&system_time, &file_time);

		li_time.LowPart = file_time.dwLowDateTime;
		li_time.HighPart = file_time.dwHighDateTime;

		eventtime = (li_time.QuadPart - epoch_time.QuadPart) / 10000;
#else
		tm.tm_isdst = -1;
		strptime(loglinecolumns[2], "%Y-%m-%d %H:%M:%S.", &tm);

		timesec = mktime(&tm);

		if ( timesec != -1)
		{
			timemsec = atoi(&(loglinecolumns[2][20]));

			eventtime = (long long) (timesec + local_time_shift) * 1000 + timemsec;
		}
		else eventtime = 0;
#endif
	}
	else eventtime = 0;


	pid = ( *(loglinecolumns[3]) == 0 ) ? 0 : atol(loglinecolumns[3]);

	if ( *(loglinecolumns[4]) != 0 )
	{
		if ( strcmp(loglinecolumns[4], "async") == 0 ) opsync = 0;
		else opsync = 1;
	}
	else opsync = -1;

	errorid = ( *(loglinecolumns[12]) == 0 ) ? 0 : atoi(loglinecolumns[12]);

	eventtext = loglinecolumns[13];
}

void initialize()
{
#if defined(__MINGW32__)
	SYSTEMTIME system_time;
	FILETIME file_time;

	system_time.wYear = 1970;
	system_time.wMonth = 1;
	system_time.wDay = 1;
	system_time.wHour = 0;
	system_time.wMinute = 0;
	system_time.wSecond = 0;
	system_time.wMilliseconds = 0;

	SystemTimeToFileTime(&system_time, &file_time);

	epoch_time.LowPart = file_time.dwLowDateTime;
	epoch_time.HighPart = file_time.dwHighDateTime;
#else
	time_t timen, timeg, timel;

	timen = 86400;
	timeg = mktime(gmtime(&timen));
	timel = mktime(localtime(&timen));

	local_time_shift = timel - timeg;
#endif
}

void time2string(long long timems, char *str, int maxlen)
{
	struct tm *newtime;
	time_t timesec;

	timesec = timems / 1000;
	newtime = gmtime( &timesec );
	strftime (str, maxlen, "%Y-%m-%d %H:%M:%S", newtime);
	if ( maxlen >= 24 )
	{
		/* Write miliseconds to string */
		sprintf(&(str[19]), ".%03i", (int) (timems % 1000));
	}
}


void printresults()
{
	long long total_time;
	client_struct *client;
	char timestr[64];
	double avglen, avgdelay;

	printf("\n");

	if (client_list == NULL)
	{
		printf("no clients\n");
		return;
	}

	printf("normal communication:    %sincluded in statistics ; warnings %schecked\n", (section_update[0])?"":"not ", (section_warn[0])?"":"not ");
	printf("initialization:          %sincluded in statistics ; warnings %schecked\n", (section_update[1])?"":"not ", (section_warn[1])?"":"not ");
	printf("initial synchronization: %sincluded in statistics ; warnings %schecked\n", (section_update[2])?"":"not ", (section_warn[2])?"":"not ");
	printf("final synchronization:   %sincluded in statistics ; warnings %schecked\n", (section_update[3])?"":"not ", (section_warn[3])?"":"not ");
	printf("\n");

	client = client_list;

	do
	{
		printf("client %li:\n", client->pid);
		time2string(client->first_connect, (char *) &timestr, 64);
		printf("first connect:         %s\n", timestr);
		time2string(client->last_disconnect, (char *) &timestr, 64);
		printf("last disconnect:       %s\n", timestr);

		total_time = client->last_disconnect - client->first_connect;
		printf("total time:            %li.%.3i seconds\n", (long int) (total_time / 1000LL), (int) (total_time % 1000LL));
		printf("total time connected:  %li.%.3i seconds\n", (long int) (client->time_connected / 1000LL), (int) (client->time_connected % 1000LL));

		printf("\n");

		printf("recv messages - fail:  num = %-10i\n", client->msg_recv_fail_num);

		avglen = (client->msg_recv_succ_num == 0) ? 0.0 : (double) client->msg_recv_succ_len / client->msg_recv_succ_num;
		printf("recv messages - succ:  num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_recv_succ_num, client->msg_recv_succ_len, client->msg_recv_succ_min_len, client->msg_recv_succ_max_len, avglen);
		printf("recv messages - succ  = imm + delay\n");

		avglen = (client->msg_recv_imm_num == 0) ? 0.0 : (double) client->msg_recv_imm_len / client->msg_recv_imm_num;
		printf("recv messages - imm:   num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_recv_imm_num, client->msg_recv_imm_len, client->msg_recv_imm_min_len, client->msg_recv_imm_max_len, avglen);

		avglen = (client->msg_recv_delay_num == 0) ? 0.0 : (double) client->msg_recv_delay_len / client->msg_recv_delay_num;
		printf("recv messages - delay: num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_recv_delay_num, client->msg_recv_delay_len, client->msg_recv_delay_min_len, client->msg_recv_delay_max_len, avglen);
		avgdelay = (client->msg_recv_delay_num == 0) ? 0.0 : (double) client->msg_recv_delay_delay / 1000 / client->msg_recv_delay_num;
		printf("                       delay = %li.%.3is  min delay = %li.%.3is  max delay = %li.%.3is  avg delay = %.3fs\n", (long int) (client->msg_recv_delay_delay / 1000LL), (int) (client->msg_recv_delay_delay % 1000LL), (long int) (client->msg_recv_delay_min_delay / 1000LL), (int) (client->msg_recv_delay_min_delay % 1000LL), (long int) (client->msg_recv_delay_max_delay / 1000LL), (int) (client->msg_recv_delay_max_delay % 1000LL), avgdelay);

		printf("\n");

		avglen = (client->msg_send_fail_num == 0) ? 0.0 : (double) client->msg_send_fail_len / client->msg_send_fail_num;
		printf("send messages - fail:  num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_send_fail_num, client->msg_send_fail_len, client->msg_send_fail_min_len, client->msg_send_fail_max_len, avglen);

		avglen = (client->msg_send_succ_num == 0) ? 0.0 : (double) client->msg_send_succ_len / client->msg_send_succ_num;
		printf("send messages - succ:  num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_send_succ_num, client->msg_send_succ_len, client->msg_send_succ_min_len, client->msg_send_succ_max_len, avglen);
		printf("send messages - succ  = async + sync\n");

		avglen = (client->msg_send_async_num == 0) ? 0.0 : (double) client->msg_send_async_len / client->msg_send_async_num;
		printf("send messages - async: num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_send_async_num, client->msg_send_async_len, client->msg_send_async_min_len, client->msg_send_async_max_len, avglen);

		avglen = (client->msg_send_sync_num == 0) ? 0.0 : (double) client->msg_send_sync_len / client->msg_send_sync_num;
		printf("send messages - sync:  num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_send_sync_num, client->msg_send_sync_len, client->msg_send_sync_min_len, client->msg_send_sync_max_len, avglen);
		printf("send messages - sync  = imm + delay\n");

		avglen = (client->msg_send_imm_num == 0) ? 0.0 : (double) client->msg_send_imm_len / client->msg_send_imm_num;
		printf("send messages - imm:   num = %-10i len = %-10i min len = %-10i max len = %-10i avg len = %.3f\n", client->msg_send_imm_num, client->msg_send_imm_len, client->msg_send_imm_min_len, client->msg_send_imm_max_len, avglen);

		avglen = (client->msg_send_delay_num == 0) ? 0.0 : (double) client->msg_send_delay_len / client->msg_send_delay_num;
		printf("send messages - delay: num = %-10i  len = %-10i  avg len = %.3f\n", client->msg_send_delay_num, client->msg_send_delay_len, avglen);
		avgdelay = (client->msg_send_delay_num == 0) ? 0.0 : (double) client->msg_send_delay_delay / 1000 / client->msg_send_delay_num;
		printf("                       delay = %li.%.3is  min delay = %li.%.3is  max delay = %li.%.3is  avg delay = %.3fs\n", (long int) (client->msg_send_delay_delay / 1000LL), (int) (client->msg_send_delay_delay % 1000LL), (long int) (client->msg_send_delay_min_delay / 1000LL), (int) (client->msg_send_delay_min_delay % 1000LL), (long int) (client->msg_send_delay_max_delay / 1000LL), (int) (client->msg_send_delay_max_delay % 1000LL), avgdelay);

		printf("\n");
		client = client->next;
	} while (client != client_list);
}

int main (int argc, char *argv[])
{
	/* print copyright notice */
	printf("MPSLogAnalyzer v0.5.0\nCopyright (C) 2007 Roman Pauer\n");

	/* check number of arguments */
	if (argc < 2)
	{
		fprintf(stderr, "error: not enough parameters\nusage: MPSLogAnalyzer filename\nexample: MPSLogAnalyzer MPSServer.log >output 2>error-output\n");
		return 1;
	}

	initialize();

	/* open log file */
	logfile = fopen(argv[1], "rt");
	if (logfile == NULL)
	{
		fprintf(stderr, "error: unable to open file: %s\n", argv[1]);
		return 2;
	}

	/* read log file */
	while (!feof(logfile) && !endreading)
	{
		/* skip empty lines */
		fscanf(logfile, "%4096[\n]", logline);
		*logline = 0;
		/* read one line */
		fscanf(logfile, "%4096[^\n]", logline);
		loglinelength = strlen(logline);

		/* check if line is empty (just to be sure) */
		if (loglinelength == 0) continue;
		/* check if line is header line */
		if (strncmp(logline, "eventid;", 8) == 0) continue;

		/* decode logline into columns */
		decodelogline();
		/* decode common columns into values */
		decodeloglinecolumns_common();

		/* check eventid */
		if (eventid < 1 || eventid > 11)
		{
			fprintf(stderr, "Error: unknown event: %i - %s - %s\n", eventid, eventtimetext, eventtext);
			continue;
		}
		/* from here eventid is valid */

		/* check event result */
		if (resultid == 0)
		{
			if (eventid == LEID_CLIENT_CONNECT &&
				initialization_type == 1 &&
				init_sync_status < 2 &&
				pid == 1
			)
			{
				/* this is part of MINGW initialization */
			}
			else
			{
				fprintf(stderr, "Error: event error: %i - %s - %s\n", errorid, eventtimetext, eventtext);
			}
			continue;
		}
		/* from here resultid != 0 */


		if (serverstarted == 0)
		{
			if (eventid == LEID_SERVER_STARTUP)
			{
				serverstarted = 1;
				initialization_type = -1;
				addclient(1);
			}
			else
			{
				fprintf(stderr, "Error: server not started: %s - %s\n", eventtimetext, eventtext);
			}
			continue;
		}
		else if (eventid == LEID_SERVER_STARTUP)
		{
			fprintf(stderr, "Error: server already started: %s - %s\n", eventtimetext, eventtext);
			continue;
		}
		/* from here serverstarted != 0 */
		/* from here eventid != LEID_SERVER_STARTUP */

		if (eventid == LEID_SERVER_SHUTDOWN)
		{
			serverstarted = 0;
			printresults();
			deleteclients();

			continue;
		} /* LEID_SERVER_SHUTDOWN */

		if (eventid == LEID_SENDRECV_EXEC)
		{
			long int send_mid, recv_mid, send_pid;
			int mlength;
			message_struct *recv_message, *send_message;
			client_struct *send_client;

			send_pid = atol(loglinecolumns[5]);
			recv_mid = atol(loglinecolumns[6]);
			send_mid = atol(loglinecolumns[7]);
			mlength = atoi(loglinecolumns[8]);

			if (resultid == 2)
			{
				/* message was not sent */
				send_client = findclient(send_pid);

				send_message = findmessage(&(send_client->message_list), send_mid);

				if (send_message == NULL)
				{
					if (section_warn[send_client->section_type])
					{
						fprintf(stderr, "Warning: message not sent: %li - %li - %li - %s - %s\n", send_pid, pid, send_mid, eventtimetext, eventtext);
					}

					fprintf(stderr, "Error: message not found: %li - %li - %s - %s\n", send_pid, send_mid, eventtimetext, eventtext);
				}
				else
				{
					if (section_warn[send_client->section_type] ||
						section_warn[send_message->section_type])
					{
						fprintf(stderr, "Warning: message not sent: %li - %li - %li - %s - %s\n", send_pid, pid, send_mid, eventtimetext, eventtext);
					}
					/* update statistics (send_message) */
					if (section_update[send_client->section_type])
					{
						send_client->msg_send_fail_num++;
						send_client->msg_send_fail_len+=send_message->mlength;
						UPDATE_MIN_VAL(send_client->msg_send_fail_min_len, send_message->mlength);
						UPDATE_MAX_VAL(send_client->msg_send_fail_max_len, send_message->mlength);
					}

					deletemessage(&(send_client->message_list), send_message);
				}
			}
			else if (resultid == 4)
			{
				/* message was not received */
				current_client = findclient(pid);

				recv_message = findmessage(&(current_client->message_list), recv_mid);

				if (recv_message == NULL)
				{
					/* should not happen */
					recv_message = addmessage(&(current_client->message_list), recv_mid, 0, mlength, -1, current_client->section_type);
					recv_message->delivery_start = eventtime;
				}
				else
				{
					recv_message->isreserved = 0;
					recv_message->mlength = mlength;
				}
				recv_message->delivery_finish = eventtime;

				if (section_warn[current_client->section_type] ||
					section_warn[recv_message->section_type]
					)
				{
					fprintf(stderr, "Warning: message not received: %li - %li - %li - %s - %s\n", pid, send_pid, recv_mid, eventtimetext, eventtext);
				}

				/* update statistics (recv_message) */
				if (section_update[current_client->section_type])
				{
					current_client->msg_recv_fail_num++;
				}
			}
			else if (resultid == 1)
			{
				/* message was delivered imediately */
				current_client = findclient(pid);
				send_client = findclient(send_pid);

				send_message = findmessage(&(send_client->message_list), send_mid);

				if (send_message == NULL)
				{
					fprintf(stderr, "Error: message not found: %li - %li - %s - %s\n", send_pid, send_mid, eventtimetext, eventtext);
				}
				else
				{
					if (current_client->section_type != send_message->section_type)
					{
						fprintf(stderr, "Error: send/recv section type mismatch: %li - %i - %i - %s - %s\n", pid, send_message->section_type, current_client->section_type, eventtimetext, eventtext);
					}

					recv_message = findmessage(&(current_client->message_list), recv_mid);

					if (recv_message == NULL)
					{
						/* should not happen */
						recv_message = addmessage(&(current_client->message_list), recv_mid, 0, send_message->mlength, -1, current_client->section_type);
						recv_message->delivery_start = eventtime;
					}
					else
					{
						recv_message->isreserved = 0;
						recv_message->mlength = send_message->mlength;
					}
					recv_message->delivery_finish = eventtime;
					send_message->delivery_finish = eventtime;

					/* update statistics (recv_message, send_message) */
					if (section_update[current_client->section_type])
					{
						current_client->msg_recv_succ_num++;
						current_client->msg_recv_succ_len+=recv_message->mlength;
						UPDATE_MIN_VAL(current_client->msg_recv_succ_min_len, recv_message->mlength);
						UPDATE_MAX_VAL(current_client->msg_recv_succ_max_len, recv_message->mlength);
						current_client->msg_recv_delay_num++;
						current_client->msg_recv_delay_len+=recv_message->mlength;
						UPDATE_MIN_VAL(current_client->msg_recv_delay_min_len, recv_message->mlength);
						UPDATE_MAX_VAL(current_client->msg_recv_delay_max_len, recv_message->mlength);
						current_client->msg_recv_delay_delay+=(recv_message->delivery_finish - recv_message->delivery_start);
						UPDATE_MIN_VAL_LL(current_client->msg_recv_delay_min_delay, (recv_message->delivery_finish - recv_message->delivery_start));
						UPDATE_MAX_VAL_LL(current_client->msg_recv_delay_max_delay, (recv_message->delivery_finish - recv_message->delivery_start));
					}

					if (section_update[send_client->section_type])
					{
						send_client->msg_send_succ_num++;
						send_client->msg_send_succ_len+=send_message->mlength;
						UPDATE_MIN_VAL(send_client->msg_send_succ_min_len, send_message->mlength);
						UPDATE_MAX_VAL(send_client->msg_send_succ_max_len, send_message->mlength);

						if (send_message->opsync == 0)
						{
							send_client->msg_send_async_num++;
							send_client->msg_send_async_len+=send_message->mlength;
							UPDATE_MIN_VAL(send_client->msg_send_async_min_len, send_message->mlength);
							UPDATE_MAX_VAL(send_client->msg_send_async_max_len, send_message->mlength);
						}
						else
						{
							send_client->msg_send_sync_num++;
							send_client->msg_send_sync_len+=send_message->mlength;
							UPDATE_MIN_VAL(send_client->msg_send_sync_min_len, send_message->mlength);
							UPDATE_MAX_VAL(send_client->msg_send_sync_max_len, send_message->mlength);

							send_client->msg_send_delay_num++;
							send_client->msg_send_delay_len+=send_message->mlength;
							UPDATE_MIN_VAL(send_client->msg_send_delay_min_len, send_message->mlength);
							UPDATE_MAX_VAL(send_client->msg_send_delay_max_len, send_message->mlength);
							send_client->msg_send_delay_delay+=(send_message->delivery_finish - send_message->delivery_start);
							UPDATE_MIN_VAL_LL(send_client->msg_send_delay_min_delay, (send_message->delivery_finish - send_message->delivery_start));
							UPDATE_MAX_VAL_LL(send_client->msg_send_delay_max_delay, (send_message->delivery_finish - send_message->delivery_start));
						}
					}

					deletemessage(&(send_client->message_list), send_message);
				}
			}

			continue;
		} /* LEID_SENDRECV_EXEC */

		current_client = findclient(pid);

		if (current_client == NULL)
		{
			fprintf(stderr, "Error: client not started: %li - %s - %s\n", pid, eventtimetext, eventtext);
			continue;
		}

		if (eventid == LEID_CLIENT_DISCONNECT)
		{
			if (current_client->section_type != 0)
			{
				fprintf(stderr, "Error: client disconnected in the middle of special section: %li - %i - %s - %s\n", pid, current_client->section_type, eventtimetext, eventtext);
				current_client->section_type = 0;
				current_client->section_mid = 0;
			}
			if (current_client->connected != 0)
			{
				disconnectcurrentclient();
			}
			else
			{
				fprintf(stderr, "Error: client already disconnected: %li - %s - %s\n", pid, eventtimetext, eventtext);
			}
			continue;
		} /* LEID_CLIENT_DISCONNECT */

		if (current_client->started == 0)
		{
			fprintf(stderr, "Error: client already ended: %li - %s - %s\n", pid, eventtimetext, eventtext);
			continue;
		}

		if (eventid == LEID_CLIENT_CONNECT)
		{
			if (current_client->connected == 0)
			{
				connectcurrentclient();
				if (pid == 1)
				{
					init_sync_status = 2;
				}
			}
			else
			{
				fprintf(stderr, "Error: client already connected: %li - %s - %s\n", pid, eventtimetext, eventtext);
			}
			continue;
		} /* LEID_CLIENT_CONNECT */

		if (current_client->connected == 0)
		{
			fprintf(stderr, "Error: client not connected: %li - %s - %s\n", pid, eventtimetext, eventtext);
			continue;
		}

		if (eventid == LEID_OPERATION_START)
		{
			long int newpid, newmid;
			int mlength;
			client_struct *new_client;

			newpid = atol(loglinecolumns[5]);
			newmid = atol(loglinecolumns[6]);
			mlength = atoi(loglinecolumns[7]);

			new_client = findclient(newpid);

			if (new_client == NULL)
			{
				addclient(newpid);
			}
			else
			{
				if (new_client->started == 0)
				{
					new_client->started = 1;
				}
				else
				{
					fprintf(stderr, "Error: client already started: %li - %s - %s\n", newpid, eventtimetext, eventtext);
				}
			}

			addmessage(&(current_client->message_list), newmid, 0, mlength, -1, current_client->section_type);

			continue;
		} /* LEID_OPERATION_START */

		if (eventid == LEID_OPERATION_END)
		{
			current_client->started = 0;

			continue;
		} /* LEID_OPERATION_END */

		if (eventid == LEID_OPERATION_CREATE)
		{
			long int newmid;
			int mlength;

			mlength = atoi(loglinecolumns[5]);
			newmid = atol(loglinecolumns[7]);

			if (current_client->section_type == 0)
			{
				if (mlength == 11)
				{
					if (strcasecmp(loglinecolumns[6], "0x49,0x4e,0x49,0x54,0x2d,0x50,0x4f,0x53,0x49,0x58,0x00") == 0) /* "INIT-POSIX" */
					{
						current_client->section_type = 1;
						current_client->section_mid = newmid;
						if (pid == 1)
						{
							init_sync_status = 0;
							if (initialization_type < 0) initialization_type = 0;
						}
					}
					else if (strcasecmp(loglinecolumns[6], "0x49,0x4e,0x49,0x54,0x2d,0x4d,0x49,0x4e,0x47,0x57,0x00") == 0) /* "INIT-MINGW" */
					{
						current_client->section_type = 1;
						current_client->section_mid = newmid;
						if (pid == 1)
						{
							init_sync_status = 0;
							if (initialization_type < 0) initialization_type = 1;
						}
					}
				}
				else if (mlength == 10)
				{
					if (strcasecmp(loglinecolumns[6], "0x53,0x59,0x4e,0x43,0x2d,0x49,0x4e,0x49,0x54,0x00") == 0) /* "SYNC-INIT" */
					{
						current_client->section_type = 2;
						current_client->section_mid = newmid;

						if (pid == 1)
						{
							init_sync_status = 1;
						}
					}
				}
				else if (mlength == 9)
				{
					if (strcasecmp(loglinecolumns[6], "0x53,0x59,0x4e,0x43,0x2d,0x45,0x4e,0x44,0x00") == 0) /* "SYNC-END" */
					{
						current_client->section_type = 3;
						current_client->section_mid = newmid;
					}
				}
			}

			addmessage(&(current_client->message_list), newmid, 0, mlength, -1, current_client->section_type);

			continue;
		} /* LEID_OPERATION_CREATE */

		if (eventid == LEID_OPERATION_DESTROY)
		{
			long int mid;
			message_struct *message;

			mid = atol(loglinecolumns[5]);

			if (current_client->section_type != 0 &&
				current_client->section_mid == mid)
			{
				if (pid == 1 &&
					current_client->section_type == 2
				)
				{
					init_sync_status = 2;
				}

				current_client->section_type = 0;
				current_client->section_mid = 0;
			}

			message = findmessage(&(current_client->message_list), mid);

			if (message == NULL)
			{
				fprintf(stderr, "Error: message not found: %li - %li - %s - %s\n", pid, mid, eventtimetext, eventtext);
			}
			else
			{
				deletemessage(&(current_client->message_list), message);
			}

			continue;
		} /* LEID_OPERATION_DESTROY */

		if (eventid == LEID_OPERATION_SEND)
		{
			long int send_mid, recv_mid, recv_pid;
			message_struct *send_message, *recv_message;
			client_struct *recv_client;

			send_mid = atol(loglinecolumns[5]);
			recv_pid = atol(loglinecolumns[8]);
			recv_mid = atol(loglinecolumns[9]);

			send_message = findmessage(&(current_client->message_list), send_mid);

			if (send_message == NULL)
			{
				fprintf(stderr, "Error: message not found: %li - %li - %s - %s\n", pid, send_mid, eventtimetext, eventtext);
			}
			else
			{
				send_message->delivery_start = eventtime;
				send_message->opsync = opsync;

				if (resultid == 2)
				{
					/* message was not sent */
					if (section_warn[current_client->section_type])
					{
						fprintf(stderr, "Warning: message not sent: %li - %li - %li - %s - %s\n", pid, recv_pid, send_mid, eventtimetext, eventtext);
					}

					/* update statistics (send_message) */
					if (section_update[current_client->section_type])
					{
						current_client->msg_send_fail_num++;
						current_client->msg_send_fail_len+=send_message->mlength;
						UPDATE_MIN_VAL(current_client->msg_send_fail_min_len, send_message->mlength);
						UPDATE_MAX_VAL(current_client->msg_send_fail_max_len, send_message->mlength);
					}

					deletemessage(&(current_client->message_list), send_message);
				}
				else if (resultid == 1)
				{
					/* message was delivered imediately */
					recv_client = findclient(recv_pid);

					if (recv_client->section_type != send_message->section_type)
					{
						fprintf(stderr, "Error: send/recv section type mismatch: %li - %i - %i - %s - %s\n", pid, send_message->section_type, recv_client->section_type, eventtimetext, eventtext);
					}

					recv_message = findmessage(&(recv_client->message_list), recv_mid);

					if (recv_message == NULL)
					{
						/* should not happen */
						recv_message = addmessage(&(recv_client->message_list), recv_mid, 0, send_message->mlength, -1, recv_client->section_type);
						recv_message->delivery_start = eventtime;
					}
					else
					{
						recv_message->isreserved = 0;
						recv_message->mlength = send_message->mlength;
					}
					recv_message->delivery_finish = eventtime;

					/* update statistics (recv_message) */
					if (section_update[recv_client->section_type])
					{
						recv_client->msg_recv_succ_num++;
						recv_client->msg_recv_succ_len+=recv_message->mlength;
						UPDATE_MIN_VAL(recv_client->msg_recv_succ_min_len, recv_message->mlength);
						UPDATE_MAX_VAL(recv_client->msg_recv_succ_max_len, recv_message->mlength);
						recv_client->msg_recv_delay_num++;
						recv_client->msg_recv_delay_len+=recv_message->mlength;
						UPDATE_MIN_VAL(recv_client->msg_recv_delay_min_len, recv_message->mlength);
						UPDATE_MAX_VAL(recv_client->msg_recv_delay_max_len, recv_message->mlength);
						recv_client->msg_recv_delay_delay+=(recv_message->delivery_finish - recv_message->delivery_start);
						UPDATE_MIN_VAL_LL(recv_client->msg_recv_delay_min_delay, (recv_message->delivery_finish - recv_message->delivery_start));
						UPDATE_MAX_VAL_LL(recv_client->msg_recv_delay_max_delay, (recv_message->delivery_finish - recv_message->delivery_start));
					}

					if (section_update[current_client->section_type])
					{
						current_client->msg_send_succ_num++;
						current_client->msg_send_succ_len+=recv_message->mlength;
						UPDATE_MIN_VAL(current_client->msg_send_succ_min_len, recv_message->mlength);
						UPDATE_MAX_VAL(current_client->msg_send_succ_max_len, recv_message->mlength);

						if (opsync == 0)
						{
							current_client->msg_send_async_num++;
							current_client->msg_send_async_len+=recv_message->mlength;
							UPDATE_MIN_VAL(current_client->msg_send_async_min_len, recv_message->mlength);
							UPDATE_MAX_VAL(current_client->msg_send_async_max_len, recv_message->mlength);
						}
						else
						{
							current_client->msg_send_sync_num++;
							current_client->msg_send_sync_len+=recv_message->mlength;
							UPDATE_MIN_VAL(current_client->msg_send_sync_min_len, recv_message->mlength);
							UPDATE_MAX_VAL(current_client->msg_send_sync_max_len, recv_message->mlength);

							current_client->msg_send_imm_num++;
							current_client->msg_send_imm_len+=recv_message->mlength;
							UPDATE_MIN_VAL(current_client->msg_send_imm_min_len, recv_message->mlength);
							UPDATE_MAX_VAL(current_client->msg_send_imm_max_len, recv_message->mlength);
						}
					}

					deletemessage(&(current_client->message_list), send_message);
				}

			}

			continue;
		} /* LEID_OPERATION_SEND */

		if (eventid == LEID_OPERATION_RECV)
		{
			long int send_mid, recv_mid, send_pid;
			int mlength;
			message_struct *recv_message, *send_message;
			client_struct *send_client;

			send_pid = atol(loglinecolumns[8]);
			recv_mid = atol(loglinecolumns[9]);
			send_mid = atol(loglinecolumns[10]);
			mlength = atoi(loglinecolumns[11]);

			if (resultid == 4)
			{
				/* message was not received */
				recv_message = addmessage(&(current_client->message_list), recv_mid, 0, mlength, -1, current_client->section_type);

				if (section_warn[current_client->section_type])
				{
					fprintf(stderr, "Warning: message not received: %li - %li - %li - %s - %s\n", pid, send_pid, recv_mid, eventtimetext, eventtext);
				}

				/* update statistics (recv_message) */
				if (section_update[current_client->section_type])
				{
					current_client->msg_recv_fail_num++;
				}
							}
			else if (resultid == 5)
			{
				/* delivery was delayed */
				recv_message = addmessage(&(current_client->message_list), recv_mid, 1, 0, opsync, current_client->section_type);
				recv_message->delivery_start = eventtime;
			}
			else if (resultid == 1)
			{
				/* message was delivered imediately */
				send_client = findclient(send_pid);


				send_message = findmessage(&(send_client->message_list), send_mid);

				if (send_message == NULL)
				{
					fprintf(stderr, "Error: message not found: %li - %li - %s - %s\n", send_pid, send_mid, eventtimetext, eventtext);
				}
				else
				{
					if (current_client->section_type != send_message->section_type)
					{
						fprintf(stderr, "Error: send/recv section type mismatch: %li - %i - %i - %s - %s\n", pid, send_message->section_type, current_client->section_type, eventtimetext, eventtext);
					}

					recv_message = addmessage(&(current_client->message_list), recv_mid, 0, send_message->mlength, opsync, current_client->section_type);
					send_message->delivery_finish = eventtime;

					/* update statistics (send_message) */
					if (section_update[current_client->section_type])
					{
						current_client->msg_recv_succ_num++;
						current_client->msg_recv_succ_len+=send_message->mlength;
						UPDATE_MIN_VAL(current_client->msg_recv_succ_min_len, send_message->mlength);
						UPDATE_MAX_VAL(current_client->msg_recv_succ_max_len, send_message->mlength);
						current_client->msg_recv_imm_num++;
						current_client->msg_recv_imm_len+=send_message->mlength;
						UPDATE_MIN_VAL(current_client->msg_recv_imm_min_len, send_message->mlength);
						UPDATE_MAX_VAL(current_client->msg_recv_imm_max_len, send_message->mlength);
					}

					if (section_update[send_client->section_type])
					{
						send_client->msg_send_succ_num++;
						send_client->msg_send_succ_len+=send_message->mlength;
						UPDATE_MIN_VAL(send_client->msg_send_succ_min_len, send_message->mlength);
						UPDATE_MAX_VAL(send_client->msg_send_succ_max_len, send_message->mlength);

						if (send_message->opsync == 0)
						{
							send_client->msg_send_async_num++;
							send_client->msg_send_async_len+=send_message->mlength;
							UPDATE_MIN_VAL(send_client->msg_send_async_min_len, send_message->mlength);
							UPDATE_MAX_VAL(send_client->msg_send_async_max_len, send_message->mlength);
						}
						else
						{
							send_client->msg_send_sync_num++;
							send_client->msg_send_sync_len+=send_message->mlength;
							UPDATE_MIN_VAL(send_client->msg_send_sync_min_len, send_message->mlength);
							UPDATE_MAX_VAL(send_client->msg_send_sync_max_len, send_message->mlength);

							send_client->msg_send_delay_num++;
							send_client->msg_send_delay_len+=send_message->mlength;
							UPDATE_MIN_VAL(send_client->msg_send_delay_min_len, send_message->mlength);
							UPDATE_MAX_VAL(send_client->msg_send_delay_max_len, send_message->mlength);
							send_client->msg_send_delay_delay+=(send_message->delivery_finish - send_message->delivery_start);
							UPDATE_MIN_VAL_LL(send_client->msg_send_delay_min_delay, (send_message->delivery_finish - send_message->delivery_start));
							UPDATE_MAX_VAL_LL(send_client->msg_send_delay_max_delay, (send_message->delivery_finish - send_message->delivery_start));
						}
					}

					deletemessage(&(send_client->message_list), send_message);
				}
			}
		} /* LEID_OPERATION_RECV */
	}
	fclose(logfile);

	return 0;
}
