#include "global.h"
#ifdef STATS_AREA
#include "stats.h"
#include "stats_a.h"
#ifdef MSDOS
#include "ctype.h"
#endif


#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: stats_a.c,v 1.12 1997/07/31 00:44:20 root Exp $";
#endif

static int STATdaily_area (int argc,char *argv[],void *p);
static int STATgeneral_area (int argc,char *argv[],void *p);
static int STATlist_area (int argc,char *argv[],void *p);
static int STATmonthly_area (int argc,char *argv[],void *p);
static int STATweekly_area (int argc,char *argv[],void *p);
static int STATyearly_area (int argc,char *argv[],void *p);

static struct area_stats areastats;

static struct area_data *sanity_check (int argc,char *argv[],void *p);
static struct area_data *find_entry (char *name);
static struct area_data *create_entry (char *name, int add);


static const char areadailyhdr[] = "%7.7s%-36.36sMSG READ\n\n";
static const char areadailyhdr2[] = "%8.8s%-35.35sAREA CHG\n\n";
static const char areaweeklyhdr[] = "%12.12s%-40.40sMSG READ\n\n";
static const char areaweeklyhdr2[] = "%12.12s%-40.40sAREA CHG\n\n";
static const char listedstr[] = "MSG LISTED";
static const char receivedstr[] = "MSG RECV";
static const char inareastr[] = "%s usage";
static const char areamonthlyhdr[] = "%10.10s%-44.44sMSG READ\n\n";
static const char areamonthlyhdr2[] = "%12.12s%-42.42sAREA CHG\n\n";
static const char areayearlyhdr[] = "%1.1s%-24.24sMSG READ\n\n";
static const char areayearlyhdr2[] = "%2.2s%-23.23sAREA CHG\n\n";


static struct cmds STATSareacmds[] = {
	{ "clear",	doSTATclear_area,	0,	0,	NULLCHAR },
	{ "daily",	STATdaily_area,		0,	0,	NULLCHAR },
	{ "general",	STATgeneral_area,	0, 	0,	NULLCHAR },
	{ "list",	STATlist_area,		0, 	0,	NULLCHAR },
	{ "monthly",	STATmonthly_area,	0, 	0,	NULLCHAR },
	{ "weekly",	STATweekly_area,	0, 	0,	NULLCHAR },
	{ "yearly",	STATyearly_area,	0, 	0,	NULLCHAR },
	{ NULLCHAR,	NULL,			0,	0,	NULLCHAR }
};



int
doSTATarea (int argc, char *argv[], void *p)
{
char *temp;

	if (argc == 3)	{
		temp = argv[1];
		argv[1] = argv[2];
		argv[2] = temp;
	} else if (argc == 2 && tolower(argv[1][0]) != 'l' )
		tprintf ("Syntax: stats area <areaname> <subcommand>\n\n");
	return subcmd(STATSareacmds,argc,argv,p);
}


static struct area_data *
find_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_entry (char *name, int add)
{
struct area_data *fd;

	fd = find_entry (name);
	if (fd == (struct area_data *)-1)	{
		fd = callocw (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);
}


static struct area_data *
sanity_check (int argc, char *argv[], void *p OPTIONAL)
{
struct area_data *fd;

	if (argc < 2)	{
		tprintf ("This command requires both an 'areaname' and a subcommand\n");
		return ((struct area_data *)-1);
	}
	
	fd = find_entry(argv[1]);
	if (fd == (struct area_data *)-1)
		tprintf ("Statistics data for that area not found\n");
	return (fd);
}


int
doSTATclear_area (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct area_data *fd, *temp;

	if(Curproc->input != Command->input)
		tputs (STAT_cannotclear);
	else	{
		fd = areastats.head;
		while (fd)	{
			free (fd->name);
			temp = fd;
			fd = fd->next;
			free (temp);
		}

		memset (&areastats, 0, sizeof (struct area_stats));
		areastats.days = 1;
		areastats.start = time((time_t *)0);
		savestats_area();
		log (-1, "Clearing area stats");
	}
	return 0;
}



static int
STATlist_area (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct area_data *fd;
int theindex = 0;

	tputs ("Areas with defined statistics:\n\n");
	fd = areastats.head;
	while (fd)	{
		tprintf ("%-19.19s", fd->name);
		if (!(++theindex % 4))
			tputc ('\n');
		fd = fd->next;
	}
	tputc ('\n');
	if (theindex % 4)
		tputc ('\n');
	return 0;
}


static int
STATgeneral_area (int argc, char *argv[], void *p)
{
char buf1[45], buf2[26], buf3[36];
struct area_data *fd;

	if ((fd = sanity_check (argc, argv, p)) == (struct area_data *)-1)
		return 0;

	tprintf ("\n%26.26s: %-26.26s%-24.24s\n", fd->name, listedstr, "MSG READ");
	sprintf (buf1, "%ld", fd->usage[0]);
	sprintf (buf2, "%ld", fd->usage[1]);
	sprintf (buf3, "Usage since %6.6s", &(ctime(&areastats.start))[4]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n", buf3, buf1, buf2);
	sprintf (buf1, "%ld", fd->day[0]);
	sprintf (buf2, "%ld", fd->day[1]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n", "Usage since midnight",
		buf1, buf2);
	sprintf (buf1, "%ld", fd->hour[0]);
	sprintf (buf2, "%ld", fd->hour[1]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n", "Usage this hour",
		buf1, buf2);
	sprintf (buf1, "%d", (areastats.days > 1) ? (int)((fd->usage[0] - fd->day[0] + (areastats.days - 2)) / (areastats.days - 1)) : (int)fd->usage[0]);
	sprintf (buf2, "%d", (areastats.days > 1) ? (int)((fd->usage[1] - fd->day[1] + (areastats.days - 2)) / (areastats.days - 1)) : (int)fd->usage[1]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n", "Average usage per day",
		buf1, buf2);

	tprintf ("\n%26.26s: %-26.26s%-24.24s\n", fd->name, receivedstr, "AREA CHG");
	sprintf (buf1, "%ld", fd->usage2[0]);
	sprintf (buf2, "%ld", fd->usage2[1]);
	sprintf (buf3, "Usage since %6.6s", &(ctime(&areastats.start))[4]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n", buf3, buf1, buf2);
	sprintf (buf1, "%ld", fd->day2[0]);
	sprintf (buf2, "%ld", fd->day2[1]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n", "Usage since midnight",
		buf1, buf2);
	sprintf (buf1, "%ld", fd->hour2[0]);
	sprintf (buf2, "%ld", fd->hour2[1]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n", "Usage this hour",
		buf1, buf2);
	sprintf (buf1, "%d", (areastats.days > 1) ? (int)((fd->usage2[0] - fd->day2[0] + (areastats.days - 2)) / (areastats.days - 1)) : (int)fd->usage2[0]);
	sprintf (buf2, "%d", (areastats.days > 1) ? (int)((fd->usage2[1] - fd->day2[1] + (areastats.days - 2)) / (areastats.days - 1)) : (int)fd->usage2[1]);
	tprintf ("  %24.24s: %-26.26s%-24.24s\n\n", "Average usage per day",
		buf1, buf2);

	return 0;
}



static int
STATdaily_area (int argc, char *argv[], void *p)
{
char buf[45];
struct area_data *fd;

	if ((fd = sanity_check (argc, argv, p)) == (struct area_data *)-1)
		return 0;
	sprintf (buf, inareastr, fd->name);
	tprintf (dailyhdr, buf);
	tprintf (areadailyhdr, STAT_emptystr,listedstr);
	doGraph (24, fd->hourly);
	tputs (STAT_dailytrailer);
	tprintf (areadailyhdr2, STAT_emptystr,receivedstr);
	doGraph (24, fd->hourly2);
	tputs (STAT_dailytrailer);
	return 0;
}



static int
STATweekly_area (int argc, char *argv[], void *p)
{
char buf[45];
struct area_data *fd;

	if ((fd = sanity_check (argc, argv, p)) == (struct area_data *)-1)
		return 0;
	sprintf (buf, inareastr, fd->name);
	tprintf (weeklyhdr, buf);
	tprintf (areaweeklyhdr, STAT_emptystr,listedstr);
	doGraph (7, fd->daily);
	tputs (STAT_weeklytrailer);
	tprintf (areaweeklyhdr2, STAT_emptystr,receivedstr);
	doGraph (7, fd->daily2);
	tputs (STAT_weeklytrailer);
	return 0;
}


static int
STATmonthly_area (int argc, char *argv[], void *p)
{
char buf[45];
struct area_data *fd;

	if ((fd = sanity_check (argc, argv, p)) == (struct area_data *)-1)
		return 0;
	sprintf (buf, inareastr, fd->name);
	tprintf (monthlyhdr, buf);
	tprintf (areamonthlyhdr, STAT_emptystr,listedstr);
	doGraph (31, fd->monthly);
	tputs (STAT_monthlytrailer);
	tprintf (areamonthlyhdr2, STAT_emptystr,receivedstr);
	doGraph (31, fd->monthly2);
	tputs (STAT_monthlytrailer);
	return 0;
}


static int
STATyearly_area (int argc, char *argv[], void *p)
{
char buf[45];
struct area_data *fd;

	if ((fd = sanity_check (argc, argv, p)) == (struct area_data *)-1)
		return 0;
	sprintf (buf, inareastr, fd->name);
	tprintf (yearlyhdr, buf);
	tprintf (areayearlyhdr, STAT_emptystr,listedstr);
	doGraph (12, fd->yearly);
	tputs (STAT_yearlytrailer);
	tprintf (areayearlyhdr2, STAT_emptystr,receivedstr);
	doGraph (12, fd->yearly2);
	tputs (STAT_yearlytrailer);
	return 0;
}


void
STATS_addarea (int which, int amount, char *name)
{
struct area_data *fd;

	if (which < 0 || which > 3)
		return;
	if (issysarea(name))	{
		fd = create_entry (name, 1);
		if (which < 2)	{
			which %= 2;
			fd->usage[which] += amount;
			fd->hour[which] += amount;
			fd->day[which] += amount;
			fd->month[which] += amount;
		} else {
			which %= 2;
			fd->usage2[which] += amount;
			fd->hour2[which] += amount;
			fd->day2[which] += amount;
			fd->month2[which] += amount;
		}
	}
}


void
updatestats_area (void)
{
	/* nothing, at this time - addareastats() does all the work */
}


void
loadstats_area(void)
{
struct area_data *fd;
char buffer[256];
int count, len;
FILE *fp;

	sprintf (buffer, "%s/area.dat", STATSDir);
	fp = fopen (buffer, "r");
	if (fp != NULLFILE)	{
		(void) fread (&areastats, sizeof (struct area_stats) - sizeof(struct area_data *), 1, fp);
		for (count = 0; count < areastats.count; count++)	{
			len = fgetc (fp);
			(void) fread (buffer, (unsigned) len, 1, fp);
			buffer[len] = 0;
			fd = create_entry (buffer, 0);
			(void) fread (fd->usage, sizeof (struct area_data) - (sizeof(char *) + sizeof(struct area_data *)), 1, fp);	/*lint !e419 */
		}
		(void) fclose (fp);
	}
}


void
savestats_area(void)
{
FILE *fp;
char buffer[256];
struct area_data *fd;
int count;

	sprintf (buffer, "%s/area.dat", STATSDir);
	fp = fopen (buffer, "w");
	if (fp != NULLFILE)	{
		fwrite (&areastats, sizeof (struct area_stats) - sizeof(struct area_data *), 1, fp);
		fd = areastats.head;
		for (count = 0; count < areastats.count; count++, fd = fd->next)	{
			fprintf (fp, "%c%s", strlen (fd->name), fd->name);
			fwrite (fd->usage, sizeof (struct area_data) - (sizeof(char *) + sizeof(struct area_data *)), 1, fp);	/*lint !e420 */
		}
		(void) fclose (fp);
	} else
		log (-1, "Can't open stats file '%s/area.dat'", STATSDir);
}


void
newhour_area (int hour)
{
struct area_data *fd;

	fd = areastats.head;
	while (fd)	{
		fd->hourly[hour][0] = fd->hour[0];
		fd->hourly[hour][1] = fd->hour[1];
		fd->hour[0] = fd->hour[1] = 0;
		fd->hourly2[hour][0] = fd->hour2[0];
		fd->hourly2[hour][1] = fd->hour2[1];
		fd->hour2[0] = fd->hour2[1] = 0;
		fd = fd->next;
	}
}


void
newday_area (int day)
{
struct area_data *fd;

	fd = areastats.head;
	while (fd)	{
		fd->daily[day][0] = fd->day[0];
		fd->daily[day][1] = fd->day[1];
		fd->daily2[day][0] = fd->day2[0];
		fd->daily2[day][1] = fd->day2[1];
		fd = fd->next;
	}
}


void
endmonthclear_area (int day, int month)
{
int k;
struct area_data *fd;
FILE *fp;

	fd = areastats.head;
	fp = tmpfile();
	if (fp)	{
		fprintf (fp, "Monthly Area Stats for the month of %s: %s\n\n", Months[month], Hostname);
		while (fd)	{
			/* clear out non-existent days of last month */
			for (k = day; k < 31; k++)	{
				fd->monthly[k][0] = fd->monthly[k][1] = 0L;
				fd->monthly2[k][0] = fd->monthly2[k][1] = 0L;
			}
			fd->yearly[month][0] = fd->month[0];
			fd->yearly[month][1] = fd->month[1];
			fprintf (fp, "[%s] Messages Listed: %ld\n[%s] Messages Read: %ld\n", fd->name, fd->month[0], fd->name, fd->month[1]);
			fprintf (fp, "[%s] Messages Received: %ld\n[%s] Area Changes: %ld\n", fd->name, fd->month2[0], fd->name, fd->month2[1]);
			fd->month[0] = fd->month[1] = 0;
			fd->month2[0] = fd->month2[1] = 0;
			fd = fd->next;
		}
		rewind (fp);
		(void) rdaemon (fp, NULLCHAR, NULLCHAR, "sysop", "Monthly Area Stats", 'P', 0);
		(void) fclose (fp);
	}
}


void
endday_area (int day)
{
struct area_data *fd;

	fd = areastats.head;
	while (fd)	{
		fd->monthly[day][0] = fd->day[0];
		fd->monthly[day][1] = fd->day[1];
		fd->day[0] = fd->day[1] = 0;
		fd->monthly2[day][0] = fd->day2[0];
		fd->monthly2[day][1] = fd->day2[1];
		fd->day2[0] = fd->day2[1] = 0;
		fd = fd->next;
	}
	areastats.days++;
}


void
eachcycle_area (time_t now)
{
	areastats.last = now;
}


void
init_area (time_t now)
{
	areastats.days = 1;
	areastats.start = now;
}


#endif /* STATS_AREA */
