#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include "configure.h"
#include "gd.h"
#include "chart.h"

/* Safe for a few years at least -- we're talking top-level domains here! */

#define domainsMax 2000

char *domainNames[domainsMax];
long domainAccesses[domainsMax];
int domainOrder[domainsMax];
int domainsTotal;
int domainDefault;
int domainUnknown;
int accessesTotal;
#define minPercent 10

void chartAddDomain(/* int domain */);

void chartAdd(site)
	char *site;
{
	if (isdigit(*site)) {
		/* It's an IP -- unknown domain name */
		chartAddDomain(domainUnknown);
		return;
	} else {
		int i;
		int domain;
		char *dname;
		dname = strrchr(site, '.');
		if (!dname) {
			/* No domain name -- add to the default domain */
			domain = domainDefault;
			chartAddDomain(domain);
		} else {
			char s[81];
			int found = 0;
			dname++;
			/* Scan aliases first. Search for domain
				surrounded by spaces. */
			strcpy(s, " ");
			strcat(s, dname);
			strcat(s, " ");
			for (i=0; (i<domainAliasesTotal); i++) {
				if (strstr(domainAliases[i], s)) {
					char *sp;
					int nlen;
					/* Determine new, aliased name */
					sp = strchr(domainAliases[i]+1, ' ');
					nlen = (sp - domainAliases[i]) - 1;
					strncpy(s, domainAliases[i]+1,
						nlen);
					s[nlen] = '\0';
					dname = s;
					break;
				}
			}	
			/* Seek and ye shall find */
			for (i=0; (i<domainsTotal); i++) {
				if (!strcmp(domainNames[i], dname)) {
					chartAddDomain(i);
					found = 1;
					break;
				}
			}
			if (!found) {
				/* New domain */
				domain = domainsTotal;
				domainNames[domain] = mystrdup(dname);
				chartAddDomain(domain);
				domainsTotal++;
			} 
		}	
	}
}

int chartSetup(dname)
	char *dname;
{
	int i;
	domainDefault = 0;	
	domainUnknown = 1;
	domainNames[0] = mystrdup(dname);
	domainNames[1] = mystrdup("?");	
	domainsTotal = 2;
	chartReset();
	return 1;
}

void chartReset() {
	int i;
	for (i=2; (i<domainsTotal); i++) {
		free(domainNames[i]);
		domainAccesses[i] = 0;
	}
	for (i=0; (i<2); i++) {
		domainAccesses[i] = 0;
	}
	domainsTotal = 2;
	accessesTotal = 0;
}

void chartShutdown() {
	free(domainNames[0]);
	free(domainNames[1]);
}

void chartAddDomain(domain)
	int domain;
{
	domainAccesses[domain]++;
	accessesTotal++;
}

int domainsCompare(/* int *arg1, int *arg2 */);

#define mypi 3.141592653
#define pix2 (mypi * 2)

#define SIZE 360
#define RADIUS 179

void chartHtml(out)
	FILE *out;
{
	int i;
	int total;
	for (i=0; (i<domainsTotal); i++) {
		domainOrder[i] = i;	
	}
	qsort(domainOrder, domainsTotal, sizeof(int), domainsCompare);
	total = 10;
	if (total > domainsTotal) {
		total = domainsTotal;
	}
	if (total < domainsTotal) {
		fprintf(out, "<LI>Accesses by top %d domains:\n", total);
	} else {
		fprintf(out, "<LI>Accesses by domain:\n", total);
	}
	fprintf(out, "<UL>\n");
	for (i=0; (i<total); i++) {
		fprintf(out, "<LI>%s: %d\n", domainNames[domainOrder[i]],
			domainAccesses[domainOrder[i]]);
	}
	fprintf(out, "</UL>\n");
}
	
void chartGif(out)
	FILE *out;
{
	gdImagePtr im;
	int i;
	int otherFlag;
	int white;
	int black;
	double scale;
	long total;
	long otherTotal;
	for (i=0; (i<domainsTotal); i++) {
		domainOrder[i] = i;	
	}
	qsort(domainOrder, domainsTotal, sizeof(int), domainsCompare);
	im = gdImageCreate(SIZE, SIZE);
	white = gdImageColorAllocate(im, 255, 255, 255);
	gdImageColorTransparent(im, white);
	black = gdImageColorAllocate(im, 0, 0, 0);
	gdImageArc(im, SIZE/2, SIZE/2, RADIUS*2, RADIUS*2, 0, 360, black);   
	if (accessesTotal) {
		scale = pix2 / (double)accessesTotal;
	} else {
		scale = 0.0;
	}	
	total = 0;
	otherFlag = 0;
	for (i=0; (i<domainsTotal); i++) {
		int x, y;
		int x2, y2;
		int percent;
		double htotal;
		char *name;
		int nameLen;
		if (!domainAccesses[domainOrder[i]]) {
			continue;
		}
		if (!otherFlag) {
			percent = ((double)domainAccesses[domainOrder[i]] /
				(double)accessesTotal) * 100.0;
			if (percent < minPercent) {
				otherFlag = 1;
				otherTotal = domainAccesses[domainOrder[i]];
			} else {
				htotal = (double)total + 
				(double)domainAccesses[domainOrder[i]]/2.0;
			}
		} else {
			otherTotal += domainAccesses[domainOrder[i]];
		}
		total += domainAccesses[domainOrder[i]];
		if (otherFlag) {
			if (i == (domainsTotal - 1)) {
				htotal = (double)(total - otherTotal/2);
				name = "Other";
			} else {
				continue;
			}
		} else {			
			name = domainNames[domainOrder[i]]; 
		}
		x = (int)(cos((double)total * scale) * 
			RADIUS + (SIZE/2));
		y = (int)(sin((double)total * scale) * 
			RADIUS + (SIZE/2));
		x2 = (int)(cos((double)htotal * scale) * 
			(RADIUS/2) + (SIZE/2));
		y2 = (int)(sin((double)htotal * scale) * 
			(RADIUS/2) + (SIZE/2));
		gdImageLine(im, SIZE/2, SIZE/2, x, y, black);
		nameLen = strlen(name);
		gdImageString(im, x2-(nameLen * gdFontWidth / 2),
			y2-gdFontHeight/2, name, black); 
	}
	gdImageGif(im, out);
	gdImageDestroy(im);
}					
 
int domainsCompare(arg1, arg2)
	int *arg1;
	int *arg2;
{
	return - (domainAccesses[(*arg1)] - 
		domainAccesses[(*arg2)]);
}

/* #define TEST_CODE 1 */

#ifdef TEST_CODE

int main() {
	int i;
	FILE *out;
	char s[1024];
	chartSetup("org");
	while (!feof(stdin)) {
		if (!fgets(s, 1023, stdin)) {
			break;
		}
		if (s[strlen(s)-1] == '\n') {
			s[strlen(s)-1] = '\0';
		}
		chartAdd(s);
	}	
	out = fopen("chart.gif", "w");
	chartGif(out);
	fclose(out);
}

#endif /* TEST_CODE */
