#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "ctype.h"
#include "stats_a.h"
#include "stats_f.h"
#include "stats_h.h"
#include "stats_m.h"
#include "stats_t.h"
#include "stats_u.h"


static struct area_stats areastats;
static struct fwd_stats fwdstats;
static struct msg_stats msgstats;
static struct tfc_stats tfcstats;
static struct use_stats usestats;
static struct http_stats httpstats;


#define NULLFILE ((FILE *)0)
#define NULLCHAR ((char *)0)

#define stricmp strcasecmp
#define strnicmp strncasecmp

char *strupr(char *s);
void rip (register char *s);
void usage_exit (void);
void saveastat (int num, long *data, const char *str);
void finishSavingStat (time_t *data);
void loadstats (void *beginning, void *ending);
void area_import (void);
void area_export (void);
void forward_import (void);
void forward_export (void);
void http_import (void);
void http_export (void);
void message_import (void);
void message_export (void);
void traffic_import (void);
void traffic_export (void);
void usage_import (void);
void usage_export (void);
static struct fwd_data *create_f_entry (char *name, int add);
static struct fwd_data *find_f_entry (char *name);
static struct area_data *find_a_entry (char *name);
static struct area_data *create_a_entry (char *name, int add);


FILE *infp, *outfp;


char *
strupr (char *s)
{
register char *p = s;

	while (*p)
		*p = (char) toupper (*p), p++;
	return s;
}



void
rip (register char *s)
{
register char *cp;

	while ((cp = strchr (s, '\n')) != NULLCHAR || (cp = strchr (s, '\r')) != NULLCHAR)
		*cp = '\0';
}



void
usage_exit (void)
{
	fprintf (stderr, "\nUsage: statconv <import | export> <type> <infile> [<outfile>]\n");
	fprintf (stderr, "\twhere 'type' is area, forward, http, message, traffic, or usage\n");
	exit (1);
}



void
saveastat (int num, long *data, const char *str)
{
int k;

	for (k = 0; k < num; k++)	{
		fprintf (outfp, "%s[%d]: %ld", str, k, *data++);
		fprintf (outfp, " %ld\n", *data++);
	}

}


void
finishSavingStat (time_t *data)
{
	fprintf (outfp, "Start: %ld\n", (long) data[0]);
	fprintf (outfp, "Last: %ld\n", (long) data[1]);
}



void
loadstats (void *beginning, void *ending)
{
char buffer[256], *cp;
long *lp;

	lp = (long *)beginning;
	while (!feof(infp))	{
		(void) fgets (buffer, 79, infp);
		if (feof(infp))
			continue;
		rip (buffer);
		cp = strchr (buffer, ' ');
		if (!cp)	{
			fprintf (stderr, "Error in reading input file\n");
			exit (1);
		}
		*lp++ = atol (++cp);
		if (lp > (long *)ending)
			break;
		cp = strchr (cp, ' ');
		if (cp)	{
			*lp++ = atol (++cp);
			if (lp > (long *)ending)
				break;
		}
	}
}



static struct area_data *
find_a_entry (char *name)
{
struct area_data *fd;

	fd = areastats.head;
	while (fd)	{
		if (!stricmp (name, fd->name))
			return (fd);
		fd = fd->next;
	}
	return ((struct area_data *)-1);
}


static struct area_data *
create_a_entry (char *name, int add)
{
struct area_data *fd;

	fd = find_a_entry (name);
	if (fd == (struct area_data *)-1)	{
		fd = calloc (1, sizeof (struct area_data)); /* no error checking, yet */
		if (fd != (struct area_data *)0)	{
			fd->name = strdup (name);
			(void) strupr (fd->name);
			fd->next = areastats.head;
			areastats.head = fd;
			if (add)
				areastats.count++;
		}
	}
	return (fd);
}


void
area_import (void)
{
int count;
struct area_data *fd;
char buffer[256], *cp;
long *lp;

	/* read in the ascii version */
	(void) fgets (buffer, 79, infp);
	if (feof(infp))
		goto done;
	rip (buffer);
	cp = strchr (buffer, ' ');
	if (!cp)	{
		fprintf (stderr, "Error in loading stats file\n");
		exit (1);
	}
	areastats.days = atol (++cp);
	while (!feof(infp))	{
		(void) fgets (buffer, 79, infp);
		if (feof(infp))
			continue;
		rip (buffer);
		if (strnicmp (buffer, "Name:", 5))
			break;
		fd = create_a_entry (&buffer[6], 1);
		lp = (long *)&fd->usage;	/*lint !e545 */
		while (!feof(infp))	{
			(void) fgets (buffer, 79, infp);
			if (feof(infp))
				continue;
			rip (buffer);
			cp = strchr (buffer, ' ');
			if (!cp)	{
				fprintf (stderr, "Error in loading stats file\n");
				exit (1);
			}
			*lp++ = atol (++cp);
			if (lp > (long *)&fd->month2[1])
				break;
			cp = strchr (cp, ' ');
			if (cp)	{
				*lp++ = atol (++cp);
				if (lp > (long *)&fd->month2[1])
					break;
			}
		}
	}
	if (!feof(infp))	{
		cp = strchr (buffer, ' ');
		if (!cp)	{
			fprintf (stderr, "Error in loading stats file\n");
			exit (1);
		}
		areastats.start = atol (++cp);

		(void) fgets (buffer, 79, infp);
		if (feof(infp))
			goto done;
		rip (buffer);
		cp = strchr (buffer, ' ');
		if (!cp)	{
			fprintf (stderr, "Error in loading stats file\n");
			exit (1);
		}
		areastats.last = atol (++cp);
	}
done:	

	/* and output the binary version */
	fwrite (&areastats, sizeof (struct area_stats) - sizeof(struct area_data *), 1, outfp);
	fd = areastats.head;
	for (count = 0; count < areastats.count; count++, fd = fd->next)	{
		fprintf (outfp, "%c%s", strlen (fd->name), fd->name);
		fwrite (fd->usage, sizeof (struct area_data) - (sizeof(char *) + sizeof(struct area_data *)), 1, outfp);	/*lint !e420 */
	}
}



void
area_export (void)
{
char buffer[256];
int count;
struct area_data *fd;
int len;

	/* read in the binary version */
	(void) fread (&areastats, sizeof (struct area_stats) - sizeof(struct area_data *), 1, infp);
	for (count = 0; count < areastats.count; count++)	{
		len = fgetc (infp);
		(void) fread (buffer, (unsigned) len, 1, infp);
		buffer[len] = 0;
		fd = create_a_entry (buffer, 0);
		(void) fread (fd->usage, sizeof (struct area_data) - (sizeof(char *) + sizeof(struct area_data *)), 1, infp);	/*lint !e419 */
	}

	/* output the ascii version */
	fprintf (outfp, "Days: %ld\n", areastats.days);
	fd = areastats.head;
	for (count = 0; count < areastats.count; count++, fd = fd->next)	{
		fprintf (outfp, "Name: %s\n", fd->name);
		fprintf (outfp, "Usage: %ld %ld\n", fd->usage[0], fd->usage[1]);
		fprintf (outfp, "Usage2: %ld %ld\n", fd->usage2[0], fd->usage2[1]);
		saveastat (24, &fd->hourly[0][0], "Hourly");
		saveastat (24, &fd->hourly2[0][0], "Hourly2");
		saveastat (7, &fd->daily[0][0], "Daily");
		saveastat (7, &fd->daily2[0][0], "Daily2");
		saveastat (31, &fd->monthly[0][0], "Monthly");
		saveastat (31, &fd->monthly2[0][0], "Monthly2");
		saveastat (12, &fd->yearly[0][0], "Yearly");
		saveastat (12, &fd->yearly2[0][0], "Yearly2");
		fprintf (outfp, "Hour: %ld %ld\n", fd->hour[0], fd->hour[1]);
		fprintf (outfp, "Hour2: %ld %ld\n", fd->hour2[0], fd->hour2[1]);
		fprintf (outfp, "Day: %ld %ld\n", fd->day[0], fd->day[1]);
		fprintf (outfp, "Day2: %ld %ld\n", fd->day2[0], fd->day2[1]);
		fprintf (outfp, "Month: %ld %ld\n", fd->month[0], fd->month[1]);
		fprintf (outfp, "Month2: %ld %ld\n", fd->month2[0], fd->month2[1]);
	}
	finishSavingStat (&areastats.start);
}



static struct fwd_data *
find_f_entry (name)
char *name;
{
struct fwd_data *fd;

	fd = fwdstats.head;
	while (fd)	{
		if (!stricmp (name, fd->name))
			return (fd);
		fd = fd->next;
	}
	return ((struct fwd_data *)-1);
}


static struct fwd_data *
create_f_entry (name, add)
char *name;
int add;
{
struct fwd_data *fd;

	fd = find_f_entry (name);
	if (fd == (struct fwd_data *)-1)	{
		fd = calloc (1, sizeof (struct fwd_data)); /* no error checking, yet */
		if (fd != (struct fwd_data *)0)	{
			fd->name = strdup (name);
			(void) strupr (fd->name);
			fd->next = fwdstats.head;
			fwdstats.head = fd;
			if (add)
				fwdstats.count++;
		}
	}
	return (fd);
}



void
forward_import (void)
{
int count;
struct fwd_data *fd;
char buffer[256], *cp;
long *lp;

	/* read in the ascii version */
	(void) fgets (buffer, 79, infp);
	if (feof(infp))
		goto done;
	rip (buffer);
	cp = strchr (buffer, ' ');
	if (!cp)	{
		fprintf (stderr, "Error in loading stats file\n");
		exit (1);
	}
	fwdstats.days = atol (++cp);
	while (!feof(infp))	{
		(void) fgets (buffer, 79, infp);
		if (feof(infp))
			continue;
		rip (buffer);
		if (strnicmp (buffer, "Name:", 5))
			break;
		fd = create_f_entry (&buffer[6], 1);
		lp = (long *)&fd->messages;	/*lint !e545 */
		while (!feof(infp))	{
			(void) fgets (buffer, 79, infp);
			if (feof(infp))
				continue;
			rip (buffer);
			cp = strchr (buffer, ' ');
			if (!cp)	{
				fprintf (stderr, "Error in loading stats file\n");
				exit (1);
			}
			*lp++ = atol (++cp);
			if (lp > (long *)&fd->month[1])
				break;
			cp = strchr (cp, ' ');
			if (cp)	{
				*lp++ = atol (++cp);
				if (lp > (long *)&fd->month[1])
					break;
			}
		}
	}
	if (!feof(infp))	{
		cp = strchr (buffer, ' ');
		if (!cp)	{
			fprintf (stderr, "Error in loading stats file\n");
			exit (1);
		}
		fwdstats.start = atol (++cp);

		(void) fgets (buffer, 79, infp);
		if (feof(infp))
			goto done;
		rip (buffer);
		cp = strchr (buffer, ' ');
		if (!cp)	{
			fprintf (stderr, "Error in loading stats file\n");
			exit (1);
		}
		fwdstats.last = atol (++cp);
	}
done:	

	/* and output the binary version */
	fwrite (&fwdstats, sizeof (struct fwd_stats) - sizeof(struct fwd_data *), 1, outfp);
	fd = fwdstats.head;
	for (count = 0; count < fwdstats.count; count++, fd = fd->next)	{
		fprintf (outfp, "%c%s", strlen (fd->name), fd->name);
		fwrite (fd->messages, sizeof (struct fwd_data) - (sizeof(char *) + sizeof(struct fwd_data *)), 1, outfp);	/*lint !e420 */
	}
}



void
forward_export (void)
{
char buffer[256];
int count;
struct fwd_data *fd;
int len;

	/* read in the binary version */
	(void) fread (&fwdstats, sizeof (struct fwd_stats) - sizeof(struct fwd_data *), 1, infp);
	for (count = 0; count < fwdstats.count; count++)	{
		len = fgetc (infp);
		(void) fread (buffer, (unsigned) len, 1, infp);
		buffer[len] = 0;
		fd = create_f_entry (buffer, 0);
		(void) fread (fd->messages, sizeof (struct fwd_data) - (sizeof(char *) + sizeof(struct fwd_data *)), 1, infp);	/*lint !e419 */
	}

	/* output the ascii version */
	fprintf (outfp, "Days: %ld\n", fwdstats.days);
	fd = fwdstats.head;
	for (count = 0; count < fwdstats.count; count++, fd = fd->next)	{
		fprintf (outfp, "Name: %s\n", fd->name);
		fprintf (outfp, "Messages: %ld %ld\n", fd->messages[0], fd->messages[1]);
		saveastat (24, &fd->hourly[0][0], "Hourly");
		saveastat (7, &fd->daily[0][0], "Daily");
		saveastat (31, &fd->monthly[0][0], "Monthly");
		saveastat (12, &fd->yearly[0][0], "Yearly");
		fprintf (outfp, "Hour: %ld %ld\n",	fd->hour[0], fd->hour[1]);
		fprintf (outfp, "Day: %ld %ld\n", fd->day[0], fd->day[1]);
		fprintf (outfp, "Month: %ld %ld\n", fd->month[0], fd->month[1]);
	}
	finishSavingStat (&fwdstats.start);
}



void
http_import (void)
{
	/* read in the ascii version */
	loadstats (&httpstats, &httpstats.last);

	/* and output the binary version */
	fwrite (&httpstats, sizeof (struct http_stats), 1, outfp);
}



void
http_export (void)
{
	/* read in the binary version */
	(void) fread (&httpstats, sizeof (struct http_stats), 1, infp);
	
	/* output the ascii version */
	fprintf (outfp, "Days: %ld\nTotalRequests: %ld %ld\n",
		httpstats.days, httpstats.connects[0], httpstats.connects[1]);
	fprintf (outfp, "DailyRequests: %ld %ld\n",
		httpstats.dailyconnects[0], httpstats.dailyconnects[1]);
	saveastat (24, &httpstats.hourly[0][0], "Hourly");
	saveastat (7, &httpstats.daily[0][0], "Daily");
	saveastat (31, &httpstats.monthly[0][0], "Monthly");
	saveastat (12, &httpstats.yearly[0][0], "Yearly");
	fprintf (outfp, "Hour: %ld %ld\n", httpstats.hour[0], httpstats.hour[1]);
	fprintf (outfp, "Day: %ld %ld\n", httpstats.day[0], httpstats.day[1]);
	fprintf (outfp, "Month: %ld %ld\n", httpstats.month[0], httpstats.month[1]);
	finishSavingStat (&httpstats.start);
}



void
message_import (void)
{
	/* read in the ascii version */
	loadstats (&msgstats, &msgstats.last);

	/* and output the binary version */
	fwrite (&msgstats, sizeof (struct msg_stats), 1, outfp);
}



void
message_export (void)
{
	/* read in the binary version */
	(void) fread (&msgstats, sizeof (struct msg_stats), 1, infp);
	
	/* output the ascii version */
	fprintf (outfp, "Days: %ld\nMessages: %ld %ld\n",
		msgstats.days, msgstats.messages[0], msgstats.messages[1]);
	saveastat (24, &msgstats.hourly[0][0], "Hourly");
	saveastat (7, &msgstats.daily[0][0], "Daily");
	saveastat (31, &msgstats.monthly[0][0], "Monthly");
	saveastat (12, &msgstats.yearly[0][0], "Yearly");
	fprintf (outfp, "Hour: %ld %ld\n", msgstats.hour[0], msgstats.hour[1]);
	fprintf (outfp, "Day: %ld %ld\n", msgstats.day[0], msgstats.day[1]);
	fprintf (outfp, "Month: %ld %ld\n", msgstats.month[0], msgstats.month[1]);
	finishSavingStat (&msgstats.start);
}



void
traffic_import (void)
{
	/* read in the ascii version */
	loadstats (&tfcstats, &tfcstats.last);

	/* and output the binary version */
	fwrite (&tfcstats, sizeof (struct tfc_stats), 1, outfp);
}



void
traffic_export (void)
{
	/* read in the binary version */
	(void) fread (&tfcstats, sizeof (struct tfc_stats), 1, infp);
	
	/* output the ascii version */
	fprintf (outfp, "Days: %ld\nMessages: %ld %ld\n",
		tfcstats.days, tfcstats.messages[0], tfcstats.messages[1]);
	fprintf (outfp, "Messages2: %ld %ld\n", tfcstats.messages2[0], tfcstats.messages2[1]);
	saveastat (24, &tfcstats.hourly[0][0], "Hourly");
	saveastat (24, &tfcstats.hourly2[0][0], "Hourly2");
	saveastat (7, &tfcstats.daily[0][0], "Daily");
	saveastat (7, &tfcstats.daily2[0][0], "Daily2");
	saveastat (31, &tfcstats.monthly[0][0], "Monthly");
	saveastat (31, &tfcstats.monthly2[0][0], "Monthly2");
	saveastat (12, &tfcstats.yearly[0][0], "Yearly");
	saveastat (12, &tfcstats.yearly2[0][0], "Yearly2");
	fprintf (outfp, "Hour: %ld %ld\n", tfcstats.hour[0], tfcstats.hour[1]);
	fprintf (outfp, "Hour2: %ld %ld\n", tfcstats.hour2[0], tfcstats.hour2[1]);
	fprintf (outfp, "Day: %ld %ld\n", tfcstats.day[0], tfcstats.day[1]);
	fprintf (outfp, "Day2: %ld %ld\n", tfcstats.day2[0], tfcstats.day2[1]);
	fprintf (outfp, "Month: %ld %ld\n", tfcstats.month[0], tfcstats.month[1]);
	fprintf (outfp, "Month2: %ld %ld\n", tfcstats.month2[0], tfcstats.month2[1]);
	finishSavingStat (&tfcstats.start);
}



void
usage_import (void)
{
	/* read in the ascii version */
	loadstats (&usestats, &usestats.last);

	/* and output the binary version */
	fwrite (&usestats, sizeof (struct use_stats), 1, outfp);
}



void
usage_export (void)
{
	/* read in the binary version */
	(void) fread (&usestats, sizeof (struct use_stats), 1, infp);
	
	/* output the ascii version */
	fprintf (outfp, "Days: %ld\nConnects: %ld %ld\n",
		usestats.days, usestats.connects[0], usestats.connects[1]);
	fprintf (outfp, "Dailyconnects: %ld %ld\n",
		usestats.dailyconnects[0], usestats.dailyconnects[1]);
	fprintf (outfp, "Usage: %ld %ld\n", usestats.usage[0], usestats.usage[1]);
	saveastat (24, &usestats.hourly[0][0], "Hourly");
	saveastat (7, &usestats.daily[0][0], "Daily");
	saveastat (31, &usestats.monthly[0][0], "Monthly");
	saveastat (12, &usestats.yearly[0][0], "Yearly");
	fprintf (outfp, "Hour: %ld %ld\n", usestats.hour[0], usestats.hour[1]);
	fprintf (outfp, "Day: %ld %ld\n", usestats.day[0], usestats.day[1]);
	fprintf (outfp, "Month: %ld %ld\n", usestats.month[0], usestats.month[1]);
	finishSavingStat (&usestats.start);
}



int
main (int argc, char *argv[])
{
int mode = 0;

	if (argc < 4)
		usage_exit ();

	outfp = stdout;
	if (tolower (argv[1][0]) == 'e')
		mode = 1;

	infp = fopen (argv[3], "r");
	if (infp == NULLFILE)	{
		fprintf (stderr, "\nCan't open input file: '%s'\n", argv[3]);
		usage_exit ();
	}

	if (argc > 4)	{
		outfp = fopen (argv[4], "w");
		if (outfp == NULLFILE)	{
			fprintf (stderr, "\nCan't open input file: '%s'\n", argv[4]);
			usage_exit ();
		}
	}

	switch (tolower (argv[2][0]))	{
		case 'a':	/* area file */
				if (mode)
					area_export ();
				else
					area_import ();
				break;
		case 'f':	/* forward file */
				if (mode)
					forward_export ();
				else
					forward_import ();
				break;
		case 'h':	/* http file */
				if (mode)
					http_export ();
				else
					http_import ();
				break;
		case 'm':	/* message file */
				if (mode)
					message_export ();
				else
					message_import ();
				break;
		case 't':	/* traffic file */
				if (mode)
					traffic_export ();
				else
					traffic_import ();
				break;
		case 'u':	/* usage file */
				if (mode)
					usage_export ();
				else
					usage_import ();
				break;
		default:	/* error!!! */
				fprintf (stderr, "\nInvalid file type: '%s'\n", argv[2]);
				usage_exit ();			
	}
	return 0;
}

