
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "glut.h"
#include "oasc.h"

IPPrefix::IPPrefix() { }

void IPPrefix::Print() {

	printf("    %d %d %d %d / %d\n\n\n", IPAddress[0], IPAddress[1], IPAddress[2], IPAddress[3], Mask);
}


void OASC::Print() {

	int i;
	char buf[16];

	AssignText((int)type,buf);
	printf("OASC type %s date %d time %d\n", buf, cdate, ctime);

	for (i=0;i<numfrom;i++) {
		printf("%d ", fromAS[i]);
	}
	printf("--> ");
	for (i=0;i<numto;i++) {
		printf("%d ", toAS[i]);
	}
	printf("\n");

	P.Print();

}


void OASC::AddFromAS(int a) {
	if (numfrom<MAX_AS) {
		fromAS[numfrom] = a;
		numfrom++;
	}
}


void OASC::AddToAS(int a) {
	if (numto<MAX_AS) {
		toAS[numto] = a;
		numto++;
	}
}



unsigned int IPPrefix::IPAddressToInt() {

	unsigned int i;

	i = (unsigned int)IPAddress[0];
	i = i << 8;
	i += (unsigned int)IPAddress[1];
	i = i << 8;
	i += (unsigned int)IPAddress[2];
	i = i << 8;
	i += (unsigned int)IPAddress[3];

	return i;

}


void IPPrefix::IntToIPAddress(unsigned int i) {

	unsigned int j;

	j = i >> 24;
	IPAddress[0] = (unsigned char)j;
	j = i >> 16;
	j = j & (unsigned int)255;
	IPAddress[1] = (unsigned char)j;
	j = i >> 8;
	j = j & (unsigned int)255;
	IPAddress[2] = (unsigned char)j;
	j = j & (unsigned int)255;
	IPAddress[3] = (unsigned char)j;

}


void IPPrefix::ReMask() {

	unsigned int i;
	unsigned int m;
	int j;

	i = IPAddressToInt();
	
	m = 0;
	for (j=0;j<Mask;j++) {
		m = m | (1 << (31-j));
	}
	i = i & m;
	IntToIPAddress(i);

}

void IPPrefix::GenerateText() {
	sprintf(text,"%d.%d.%d.%d/%d", (int)IPAddress[0], 
		(int)IPAddress[1], (int)IPAddress[2], (int)IPAddress[3], Mask);
}

Countries::Countries() : numAS(0) { }

void Countries::ReadCountry(char *fname) {

	FILE *fptr;
	int next;
	int a;
	char n[32];

	numAS = 0;
	fptr = fopen(fname,"rt");
	while (!(feof(fptr))) {
		fgets(buf,500000,fptr);
		sscanf(buf,"%s",n);
		if (strcmp(n,cname)==0) {
			next = 3;
			while (next<strlen(buf)-2) {
				sscanf(&(buf[next]),"%s", n);
				sscanf(n,"%d",&(ASList[numAS]));
				numAS++;
				next = next + strlen(n) + 1;
			}
		}
	}
	fclose(fptr);

}

/*
Countries::Countries() : numcountries(0) { 
	int i;
	for (i=0;i<MAX_COUNTRIES;i++) {
		numAS[i] = 0;
	}
}


void Countries::AddEntry(char *n, int a) {
	int i;
	int found;
	int temp[20000];
	found = -1;
	for (i=0;i<numcountries;i++) {
		if (strcmp(n,names[i])==0) found = i;
	}
	if (found<0) {
		strcpy(names[numcountries],n);
		found = numcountries;
		numcountries++;
	}
	if (numAS[found]==0) {
		//AS[found] = new int[5];
		AS[found][0] = a;
		numAS[found] = 1;
	} else {
		//for (i=0;i<numAS[found];i++) temp[i] = AS[found][i];
		//delete [] AS[found];
		//AS[found] = new int[numAS[found]+1];
		//for (i=0;i<numAS[found];i++) AS[found][i] = temp[i];
		AS[found][numAS[found]] = a;
		numAS[found]++;
	}
	//printf("%d %d\n", numcountries, numAS[found]);
}

void Countries::ReadFromFile(char *fname) {

	FILE *fptr;
	FILE *ofptr;
	char buf[64];
	int i, j;
	int a;
	char n[32];

	fptr = fopen(fname,"rt");
	while (!(feof(fptr))) {
		fgets(buf,64,fptr);
		for (i=0;i<strlen(buf);i++) {
			if (buf[i]==',') buf[i] = ' ';
		}
		//printf("%s",buf);
		sscanf(buf,"%d %s", &a, n);
		AddEntry(n, a);
	}
	fclose(fptr);

	ofptr = fopen("../data_aux/countries.txt","wt");
	for (i=0;i<numcountries;i++) {
		fprintf(ofptr, "%s ", names[i]);
		for (j=0;j<numAS[i];j++) {
			fprintf(ofptr, "%d ", AS[i][j]);
		}
		fprintf(ofptr,"\n");
	}
	
}
*/



OASCViz::OASCViz() { }


OASCViz::OASCViz(int sx, int sy, int xs, int ys) : qtoffx(50), qtoffy(120), S(sx+qtoffx,sy+qtoffy,512,10,0,65536),
Visualization(sx,sy,xs,ys), numdaily(0), numdetail(0), Q(sx+qtoffx,sy+qtoffy,512), numdays(0), H(sx,sy,xs,100,200) ,
LG(sx+10,sy+650,100,100) , LG2(sx+100,sy+650,100,100) , TT(sx+220,sy+650,300,100) , num_highlighted_AS(0) ,
SP(sx+qtoffx,sy+qtoffy,512,512) { 

	int i;
	LG.numitems = LG2.numitems = 8;
	strcpy(LG.title,"Per day count");
	strcpy(LG2.title,"Per update count");
	LG.colors = new float[4*8];
	LG.names = new char*[8];
	LG2.colors = new float[4*8];
	LG2.names = new char*[8];
	for (i=0;i<8;i++) {
		LG.names[i] = new char[16];
		AssignColor(i, &(LG.colors[i*4]));
		OASC::AssignText(i, LG.names[i]);
		LG2.names[i] = new char[16];
		AssignColor(i, &(LG2.colors[i*4]));
		OASC::AssignText(i, LG2.names[i]);
	}

	strcpy(CN.cname,"US");
	CN.ReadCountry("../data_aux/countries.txt");
	printf("%d AS in this country\n", CN.numAS);

}

void OASCViz::Init() { Q.MakeTextureMap(); }


int OASCViz::ReadOneOASC(FILE *fptr) {


	char buffer[128];
	char nextchar;
	int counter;
	int i;

	// read the type
	counter = 0;
	nextchar = (char)getc(fptr);
	if (feof(fptr)) return 0;
	while (nextchar!=':') {
		buffer[counter] = nextchar;
		nextchar = (char)getc(fptr);
		if (feof(fptr)) return 0;
		counter++;
	}

	if ((buffer[0]=='O') && (buffer[1]=='S')) {
		dailyOASC[numdaily].type = OS;
	} else if ((buffer[0]=='O') && (buffer[1]=='M')) {
		dailyOASC[numdaily].type = OM;
	} else if (buffer[0]=='B') {
		dailyOASC[numdaily].type = BSS;
	} else if (buffer[0]=='H') {
		dailyOASC[numdaily].type = HSS;
	} else if ((buffer[0]=='C') && (buffer[1]=='S') && (buffer[2]=='M')) {
		dailyOASC[numdaily].type = CSM;
	} else if ((buffer[0]=='C') && (buffer[1]=='M') && (buffer[2]=='S')) {
		dailyOASC[numdaily].type = CMS;
	} else if ((buffer[0]=='C') && (buffer[1]=='M') && (buffer[2]=='M')) {
		dailyOASC[numdaily].type = CMM;
	} else if ((buffer[0]=='C') && (buffer[1]=='S') && (buffer[2]=='S')) {
		dailyOASC[numdaily].type = CSS;
	}

	// read the each byte of the IP address
	for (i=0;i<4;i++) {  
		counter = 0;
		nextchar = (char)getc(fptr);
 	    if (feof(fptr)) return 0;	
		while ((nextchar!='.')&&(nextchar!='/')) {
			buffer[counter] = nextchar;
			nextchar = (char)getc(fptr);
			if (feof(fptr)) return 0;
			counter++;
		}
		buffer[counter] = '\0';
		dailyOASC[numdaily].P.IPAddress[i] = (unsigned char)atoi(buffer);
	}

	// read the mask
	counter = 0;
	nextchar = (char)getc(fptr);
	if (feof(fptr)) return 0;
	while ((nextchar!=' ')&&(nextchar!='*')&&(nextchar!='\t')) {
		buffer[counter] = nextchar;
		nextchar = (char)getc(fptr);
		if (feof(fptr)) return 0;
		counter++;
	}
	buffer[counter] = '\0';
	dailyOASC[numdaily].P.Mask = atoi(buffer);
		
	// read the Autonomous System numbers
	if (nextchar=='*') nextchar = (char)getc(fptr);		
	nextchar = (char)getc(fptr);
	if (nextchar == '(') {
		while (nextchar != ')') nextchar = (char)getc(fptr);
		nextchar = (char)getc(fptr);
		nextchar = (char)getc(fptr);
	}
	counter = 0;
	if (feof(fptr)) return 0;
	while ((nextchar!=' ')&&(nextchar!='*')&&(nextchar!='\t')&&(nextchar!=',')&&(nextchar!='\n')) {
		buffer[counter] = nextchar;
		nextchar = (char)getc(fptr);
		if (feof(fptr)) return 0;
		counter++;
	}
	buffer[counter] = '\0';
	dailyOASC[numdaily].fromAS[0] = atoi(buffer);
	dailyOASC[numdaily].numfrom = 1;
	dailyOASC[numdaily].numto = 0;
	while ((nextchar==',') && (dailyOASC[numdaily].numfrom<MAX_NUM_AS)) {
		nextchar = (char)getc(fptr);
		counter = 0;
		while ((nextchar!=' ')&&(nextchar!='\t')&&(nextchar!=',')&&(nextchar!='\n')) {
			buffer[counter] = nextchar;
			nextchar = (char)getc(fptr);
			if (feof(fptr)) return 1;
			counter++;
		}
		buffer[counter] = '\0';
		dailyOASC[numdaily].fromAS[dailyOASC[numdaily].numfrom] = atoi(buffer);
		dailyOASC[numdaily].numfrom++;
	}
	if (nextchar=='\n') return 1;

	// read the arrow
	nextchar = (char)getc(fptr);
	if (nextchar=='\n') return 1;
	if (nextchar=='=') {
		nextchar = (char)getc(fptr); // '='
		nextchar = (char)getc(fptr); // '>'
		nextchar = (char)getc(fptr); // '\t'
		nextchar = (char)getc(fptr);
		counter = 0;
		while ((nextchar!=' ')&&(nextchar!='\t')&&(nextchar!=',')&&(nextchar!='\n')) {	
			buffer[counter] = nextchar;
			nextchar = (char)getc(fptr);
			if (feof(fptr)) return 1;
			counter++;
		}
		buffer[counter] = '\0';
		dailyOASC[numdaily].toAS[dailyOASC[numdaily].numto] = atoi(buffer);
		dailyOASC[numdaily].numto++;
		while ((nextchar==',') && (dailyOASC[numdaily].numto<MAX_NUM_AS)) { // read the 'to' ASes
			nextchar = (char)getc(fptr);
			counter = 0;
			while ((nextchar!=' ')&&(nextchar!='\t')&&(nextchar!=',')&&(nextchar!='\n')) {	
				buffer[counter] = nextchar;
				nextchar = (char)getc(fptr);
				if (feof(fptr)) return 1;
				counter++;
			}
			buffer[counter] = '\0';
			dailyOASC[numdaily].toAS[dailyOASC[numdaily].numto] = atoi(buffer);
			dailyOASC[numdaily].numto++;
		}
	}		
			
	// read and ignore rest of the line
	if (nextchar != '\n') {
		fgets(buffer,128,fptr);
	}

	return 1;


}


void OASCViz::ReadDaily(int d) {

	FILE *fptr;
	char fname[128];
	char buf[128];
	int nums[8];
	int i;

	strcpy(fname,"../data_perday/md3-");
	itoa(d,buf,10);
	strcat(fname,buf);
	itoa(nextday(d),buf,10);
	strcat(fname,"-");
	strcat(fname,buf);
	strcat(fname,".a");
	printf("filename %s\n",fname);
	fptr = fopen(fname,"rt");

	numdaily = 0;
	for (i=0;i<8;i++) nums[i] = 0;
	if (fptr!=NULL) {
		LG.title2[0] = '\0';
		while(!feof(fptr)) {
			if (ReadOneOASC(fptr)) {
				nums[(int)(dailyOASC[numdaily].type)]++;
				if (numdaily>=MAX_OASC) {
					printf("exceeded ");	
				} else {
					numdaily++;
				}
			}
		}
		fclose(fptr);
	} else {
		strcpy(LG.title2,"(no file read)");
	}
	for (i=0;i<8;i++) {
		sprintf(buf,"    %d", nums[i]);
		LG.names[i][5] = '\0';
		strcat(LG.names[i],buf);
	}

}


void OASCViz::ReadDetail(int d) {


	FILE *fptr;
	char fname[128];
	char buf[128];
	int i;
	int typecounts[8];

	for (i=0;i<8;i++) typecounts[i] = 0;

	strcpy(fname,"../data_perupdate/");
	itoa(d,buf,10);
	strcat(fname,buf);
	strcat(fname,".txt");
	printf("filename %s\n",fname);
	fptr = fopen(fname,"rt");

	numdetail = 0;

	if (fptr!=NULL) {
		LG2.title2[0] = '\0';
		while(!feof(fptr)) {
			if (ReadOneDetail(fptr)) {
				typecounts[(int)(detailOASC[numdetail].type)]++;
				if (numdetail>=MAX_UPDATE_OASC) {
					printf("exceeded ");	
				} else {
					numdetail++;
				}
			}
		}
		fclose(fptr);
	} else {
		strcpy(LG2.title2,"(no file read)");
	}

	
	for (i=0;i<8;i++) {
		sprintf(buf,"    %d", typecounts[i]);
		LG2.names[i][5] = '\0';
		strcat(LG2.names[i],buf);
	}

	//for (i=0;i<numdetail;i++) detailOASC[i].Print();

}

int OASCViz::ReadOneDetail(FILE *fptr) {

	char buffer[2048];
	char entry[2048];
	int typenum;
	int i, found, temp, starting;

	fgets(buffer,2048,fptr);
	if (strlen(buffer)<10) return 0;
	strcpy(entry,buffer);
	if (entry[0]!='O') return 0;
	// read the type
	entry[6] = '\0';
	sscanf(&(entry[4]),"%d",&typenum);
	if (typenum<=4) { printf("CSS  ");
	} else if (typenum<=8) { printf("CSM  "); detailOASC[numdetail].type = CSM;
	} else if (typenum<=12) { printf("CMM  "); detailOASC[numdetail].type = CMM;
	} else if (typenum<=16) { printf("nothing  "); return 0;
	} else if (typenum<=18) { printf("OS  "); detailOASC[numdetail].type = OS;
	} else if (typenum<=20) { printf("HSSorBSS  "); detailOASC[numdetail].type = HSS;
	} else if (typenum<=24) { printf("nothing  "); return 0;
	} else if (typenum<=28) { printf("CMS  "); detailOASC[numdetail].type = CMS;
	} else if (typenum<=32) { printf("CMM  "); detailOASC[numdetail].type = CMM;
	} else { printf("nothing");
	}
	// search for "GMT:"
	found = 0;
	for (i=0;((i<strlen(buffer)) && (!found));i++) {
		strcpy(entry,&(buffer[i]));
		entry[4] = '\0';
		if (strcmp(entry,"GMT:")==0) found = i+4;
	}
	// read the time
	if (!found) { printf("error: ReadOneDetail\n"); return 0; }
	strcpy(entry,&(buffer[found])); // read the year
	entry[4] = '\0';
	sscanf(entry,"%d",&temp);
	detailOASC[numdetail].cdate = temp * 10000;
	strcpy(entry,&(buffer[found+5])); // read the month
	entry[2] = '\0';
	sscanf(entry,"%d",&temp);
	detailOASC[numdetail].cdate += temp * 100;
	strcpy(entry,&(buffer[found+8])); // read the day
	entry[2] = '\0';
	sscanf(entry,"%d",&temp);
	detailOASC[numdetail].cdate += temp;
	strcpy(entry,&(buffer[found+11])); // read the hour
	entry[2] = '\0';
	sscanf(entry,"%d",&temp);
	detailOASC[numdetail].ctime = temp * 10000;
	strcpy(entry,&(buffer[found+14])); // read the minute
	entry[2] = '\0';
	sscanf(entry,"%d",&temp);
	detailOASC[numdetail].ctime += temp * 100;
	strcpy(entry,&(buffer[found+17])); // read the second
	entry[2] = '\0';
	sscanf(entry,"%d",&temp);
	detailOASC[numdetail].ctime += temp;
	// read the prefix
	found = 0;
	for (i=0;((i<strlen(buffer)) && (!found));i++) {
		strcpy(entry,&(buffer[i]));
		entry[7] = '\0';
		if (strcmp(entry,"Prefix(")==0) found = i+7;
	}
	if (!found) { printf("error: ReadOneDetail\n"); return 0; }
	strcpy(entry,&(buffer[found]));
	for (i=0;entry[i]!='.';i++);
	entry[i] = '\0';
	sscanf(entry,"%d",&temp); // read IPAddress[0]
	detailOASC[numdetail].P.IPAddress[0] = (unsigned char)temp;
	starting = i+1;
	for (i=starting;entry[i]!='.';i++);
	entry[i] = '\0';
	sscanf(&(entry[starting]),"%d",&temp); // read IPAddress[1]
	detailOASC[numdetail].P.IPAddress[1] = (unsigned char)temp;
	starting = i+1;
	for (i=starting;entry[i]!='.';i++);
	entry[i] = '\0';
	sscanf(&(entry[starting]),"%d",&temp); // read IPAddress[2]
	detailOASC[numdetail].P.IPAddress[2] = (unsigned char)temp;
	starting = i+1;
	for (i=starting;entry[i]!='/';i++);
	entry[i] = '\0';
	sscanf(&(entry[starting]),"%d",&temp); // read IPAddress[3]
	detailOASC[numdetail].P.IPAddress[3] = (unsigned char)temp;
	starting = i+1;
	for (i=starting;entry[i]!=')';i++);
	entry[i] = '\0';
	sscanf(&(entry[starting]),"%d",&temp); // read Mask
	detailOASC[numdetail].P.Mask = (unsigned char)temp;
	// read the old AS
	found = 0;
	for (i=0;((i<strlen(buffer)) && (!found));i++) {
		strcpy(entry,&(buffer[i]));
		entry[6] = '\0';
		if (strcmp(entry,"Oldas(")==0) found = i+6;
	}
	if (!found) { printf("error: ReadOneDetail\n"); return 0; }
	strcpy(entry,&(buffer[found]));
	starting = 0;
	found = 0;
	while (!found) {
		for (i=starting;!((entry[i]==',') || (entry[i]==')'));i++);
		if (entry[i]==')') found = 1;
		if (i!=starting) {
			entry[i] = '\0';
			sscanf(&(entry[starting]),"%d",&temp);
			detailOASC[numdetail].AddFromAS(temp);
			starting = i+1;
		}
	}
	// read the new AS
	found = 0;
	for (i=0;((i<strlen(buffer)) && (!found));i++) {
		strcpy(entry,&(buffer[i]));
		entry[6] = '\0';
		if (strcmp(entry,"Newas(")==0) found = i+6;
	}
	if (!found) { printf("error: ReadOneDetail\n"); return 0; }
	strcpy(entry,&(buffer[found]));
	starting = 0;
	found = 0;
	while (!found) {
		for (i=starting;!((entry[i]==',') || (entry[i]==')'));i++);
		if (entry[i]==')') found = 1;
		if (i!=starting) {
			entry[i] = '\0';
			sscanf(&(entry[starting]),"%d",&temp);
			detailOASC[numdetail].AddToAS(temp);
			starting = i+1;
		}
	}
	// if H type, read the first big
	if (detailOASC[numdetail].type == HSS) {
		found = 0;
		for (i=0;((i<strlen(buffer)) && (!found));i++) {
			strcpy(entry,&(buffer[i]));
			entry[4] = '\0';
			if (strcmp(entry,"Big(")==0) found = i+4;
		}
		if (!found) { printf("error: ReadOneDetail\n"); return 0; }
		strcpy(entry,&(buffer[found]));
		for (i=0;entry[i]!=':';i++);
		sscanf(&(entry[i+1]),"%d",&temp);
		detailOASC[numdetail].AddFromAS(temp);
		if (detailOASC[numdetail].fromAS[0]==detailOASC[numdetail].toAS[0]) detailOASC[numdetail].type = BSS;
	}

	return 1;
}


// generate the count for each type on each date, output to file
void OASCViz::PreProcess(char *fname) {
	int i, j;
	FILE *fptr;
	int counts[NUM_OASC_TYPES];

	fptr = fopen(fname,"wt");
	for (i=preprocess_begin;i<preprocess_end;i=nextday(i)) {
		for (j=0;j<NUM_OASC_TYPES;j++) counts[j] = 0;
		ReadDaily(i);
		for (j=0;j<numdaily;j++) {
			counts[(int)(dailyOASC[j].type)]++;
		}
		fprintf(fptr,"%d ", i);
		for (j=0;j<NUM_OASC_TYPES;j++) fprintf(fptr,"%d ", counts[j]);
		fprintf(fptr,"\n");
	}

	fclose(fptr);

	
	//CN.ReadFromFile("../data_aux/as2country.txt");


}

// read the file containing the count
void OASCViz::ReadCount(char *fname) {

	FILE *fptr;
	int i, j, lay;
	int *d_array;
	char buffer[512];
	float col[4];

	numdays = 0;

	fptr = fopen(fname,"rt");

	while (!feof(fptr)) {
		fgets(buffer,512,fptr);
		sscanf(buffer,"%d %d %d %d %d %d %d %d %d", &(dates[numdays]),
			&(daily_counts[numdays][0]), &(daily_counts[numdays][1]), 
			&(daily_counts[numdays][2]), &(daily_counts[numdays][3]), 
			&(daily_counts[numdays][4]), &(daily_counts[numdays][5]), 
			&(daily_counts[numdays][6]), &(daily_counts[numdays][7]) );
		if ((dates[numdays] >= first_date) && (dates[numdays] <= last_date)) numdays++;
	}
	fclose(fptr);

	H.SetResolution(numdays);
	d_array = new int[numdays];
	for (i=0;i<NUM_OASC_TYPES;i++) {
		AssignColor(i,col);
		lay = H.AddLayer((float)i*0.1, col); // depth, color
		for (j=0;j<numdays;j++) d_array[j] = daily_counts[j][i];
		H.AddData(lay, d_array); // layer, data
	}
	for (i=0;i<numdays;i++) {
		d_array[i] = dates[i];
	}
	H.AddLabels(d_array);
	delete [] d_array;
}


int OASCViz::FilterOASC(OASC &OO) {

	return (show_type[(int)(OO.type)]);

}

void OASCViz::DisplayOASC3D(OASC &OO, int high) {
	int i;
	unsigned int ipaddress;
	float col[4];
	float mul;
	float coords[3];
	
	if (high==0) { mul = 0.3; 
	} else { mul = 1.0; }

	ipaddress = OO.P.IPAddressToInt();
	Q.DataToScreenNormalized(ipaddress,OO.P.Mask,coords[0],coords[2]);
	AssignColor((int)(OO.type),col);
	for (i=0;i<4;i++) col[i] = col[i] * mul;
		
	coords[1] = (float)OO.fromAS[0]/65536.0;

	SP.AddPoint(coords,col,0.05);
	
}


// highlight level: O:faded, 1:normal, 2:label
void OASCViz::DisplayOASC(OASC &OO, int high) {
		
	int i, j;
	unsigned int ipaddress;
	int scrx, scry, scrw, scrh, asx, asy;
	float col[4];
	float mul;
	char str[32];
	float f;
	float z;
	
	if (high==0) { mul = 0.3; z = 0.0;
	} else { mul = 1.0; z = 0.2;
	}


	ipaddress = OO.P.IPAddressToInt();
	Q.DataToScreen(ipaddress,OO.P.Mask,scrx,scry,scrw,scrh);
	AssignColor((int)(OO.type),col);
	glColor4f(col[0]*mul,col[1]*mul,col[2]*mul,col[3]*mul);
	// draw the box in the ip quadtree square
	if ((scrw>1) && (scrh>1)) {
		glBegin(GL_QUADS);
		glVertex3f((float)(scrx+qtoffx),(float)(scry+qtoffy),0.0);
		glVertex3f((float)(scrx+scrw+qtoffx),(float)(scry+qtoffy),0.0);
		glVertex3f((float)(scrx+scrw+qtoffx),(float)(scry+scrh+qtoffy),0.0);
		glVertex3f((float)(scrx+qtoffx),(float)(scry+scrh+qtoffy),0.0);
		glEnd();
	} else {
		glPointSize(1);
		glBegin(GL_POINTS);
		glVertex3f((float)(scrx+qtoffx),(float)(scry+qtoffy),0.0);
		glEnd();
	}
	if (high==2) {
		glRasterPos3f((float)(scrx+qtoffx),(float)(scry+qtoffy),0.3);
		sprintf(str,"%d.%d.%d.%d/%d",(int)OO.P.IPAddress[0],(int)OO.P.IPAddress[1],
			(int)OO.P.IPAddress[2],(int)OO.P.IPAddress[3],(int)OO.P.Mask);
		NT.font.Render(str);
	}
	// draw the lines from the ip quadtree square to the surrounding lines
	if (show_lines) {
		for (j=0;j<OO.numfrom;j++) {
			S.DataToScreen(OO.fromAS[j],asx,asy);
			glBegin(GL_LINES);
			glVertex3f((float)(scrx+qtoffx),(float)(scry+qtoffy),z);
			glVertex3f((float)asx,(float)asy,z);
			glEnd();
			if (high==2) {
				glRasterPos3f((float)asx,(float)asy,0.3);
				sprintf(str,"%d",OO.fromAS[j]);
				NT.font.Render(str);
			}
		}
		for (j=0;j<OO.numto;j++) {
			S.DataToScreen(OO.toAS[j],asx,asy);
			glPointSize(2);
			glBegin(GL_POINTS);
			for (f=0.0;f<1.0;f+=0.03) {
				glVertex3f(f*(float)(scrx+qtoffx)+(1.0-f)*(float)asx,f*(float)(scry+qtoffy)+(1.0-f)*(float)asy,z);
			}
			glEnd();
			if (high==2) {
				glRasterPos3f((float)asx,(float)asy,0.3);
				sprintf(str,"%d",OO.toAS[j]);
				NT.font.Render(str);
			}
		}
	}

}

void OASCViz::DisplayOASCOutline(OASC &OO) {

	int i, j;
	unsigned int ipaddress;
	int scrx, scry, scrw, scrh, asx, asy;
	float col[4];
	float mul;
	char str[32];
	float f;
	float z;

	ipaddress = OO.P.IPAddressToInt();
	Q.DataToScreen(ipaddress,OO.P.Mask,scrx,scry,scrw,scrh);
	glColor4f(0.2,0.2,0.2,0.8);
	glLineWidth(1);
	// draw the box in the ip quadtree square
	if ((scrw>1) && (scrh>1)) {
		glBegin(GL_LINES);
		glVertex3f((float)(scrx+qtoffx),(float)(scry+qtoffy),0.5);
		glVertex3f((float)(scrx+scrw+qtoffx),(float)(scry+qtoffy),0.5);

		glVertex3f((float)(scrx+qtoffx),(float)(scry+qtoffy),0.5);
		glVertex3f((float)(scrx+qtoffx),(float)(scry+scrh+qtoffy),0.5);

		glVertex3f((float)(scrx+qtoffx),(float)(scry+scrh+qtoffy),0.5);
		glVertex3f((float)(scrx+scrw+qtoffx),(float)(scry+scrh+qtoffy),0.5);

		glVertex3f((float)(scrx+scrw+qtoffx),(float)(scry+qtoffy),0.5);
		glVertex3f((float)(scrx+scrw+qtoffx),(float)(scry+scrh+qtoffy),0.5);
		glEnd();
	}
}

int OASCViz::Within(OASC &address, OASC &prefix) {

	unsigned int a;
	unsigned int b1;
	unsigned int b2;

	a = address.P.IPAddressToInt();

	b1 = prefix.P.IPAddressToInt();
	b2 = prefix.P.IPAddressToInt();
	b2 += 1 << 32 - prefix.P.Mask;

	if ((a>=b1) && (a<b2)) {
		return 1;
	} else {
		return 0;
	}
}

int OASCViz::DecideHighlight(OASC &OO) {

	int j, k;
	int hmode = 0;
	for (j=0;j<OO.numfrom;j++) {
		if ((highlight_AS_click_mode) &&
			(OO.fromAS[j]>=highlighted_AS_clicked) && 
			(OO.fromAS[j]<highlighted_AS_clicked+highlighted_AS_range)) {
			hmode = 2;
		}
		if (highlight_AS_list_mode) {
			for (k=0;k<num_highlighted_AS;k++) {
				if (OO.fromAS[j] == highlighted_AS[k]) hmode = 2;
			}
		}
		if (highlight_AS_country_mode) {
			for (k=0;k<CN.numAS;k++) {
				if (OO.fromAS[j] == CN.ASList[k]) hmode = 2;
			}
		}
	}
	for (j=0;j<OO.numto;j++) {
		if ((highlight_AS_click_mode) &&
			(OO.toAS[j]>=highlighted_AS_clicked) && 
			(OO.toAS[j]<highlighted_AS_clicked+highlighted_AS_range)) {
			hmode = 2;
		}
		if (highlight_AS_list_mode) {
			for (k=0;k<num_highlighted_AS;k++) {
				if (OO.toAS[j] == highlighted_AS[k]) hmode = 2;
			}
		}
		if (highlight_AS_country_mode) {
			for (k=0;k<CN.numAS;k++) {
				if (OO.toAS[j] == CN.ASList[k]) hmode = 2;
			}
		}
	}
	return hmode;
}

void OASCViz::Draw() {

	int i, j, k;
	unsigned int ipaddress;
	int scrx, scry, scrw, scrh, asx, asy;
	float col[4];
	float mul;
	char str[512];
	char str1[32];
	float f;
	int hmode;
	int num_perupdate;
	OASC *lastOASC;

	if (per==0) { mul = 1.0;
	} else { mul = 0.3;
	}

	
	// draw the quadtree background
	if (dimension_flag==0) Q.Draw();

	// draw the legend
	LG.Draw();
	LG2.Draw();


	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0,xsize,0,ysize);
			// left, right, bottom, top
	glViewport(startx, starty, xsize, ysize);
			// startx, starty, xsize, ysize
			// coordinates begin from lower left corner of window
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	
	// print out the highlighted AS
	strcpy(str,"Highlighted AS: ");
	str1[0] = '\0';
	for (i=0;i<num_highlighted_AS;i++) {
		sprintf(str1,"%d ", highlighted_AS[i]);
		strcat(str,str1);
	}
	glColor3f(0.1,0.1,0.1);
	glRasterPos3f((float)startx, (float)(starty + ysize - 50), 0.0);
	NT.font.Render(str);


	if (dimension_flag==0) {
		// draw the OASC lines and points in the quadtree square 
		for (i=0;i<numdaily;i++) {
			if (FilterOASC(dailyOASC[i])) {
				if ((highlight_AS_list_mode)||(highlight_AS_click_mode)||(highlight_AS_country_mode)) {
					hmode = DecideHighlight(dailyOASC[i]);
				} else if (highlight_IP_click_mode) {
					DisplayOASCOutline(highlighted_IP_prefix);
					hmode = 0;
					if (Within(dailyOASC[i],highlighted_IP_prefix)) {
						hmode = 2;
					}
				}
				if (per==1) hmode = 0;
				DisplayOASC(dailyOASC[i],hmode);
				if (hmode==2) dailyOASC[i].Print();
			}
		}	
		if (per==1) { // if draw per update
			num_perupdate = 0;
			TT.numitems = 0;
			TT.mintime = timetoint(detailOASC[current_entry].ctime) - 1;
			if (current_entry+perupdate_window-1 >= numdetail) {
				TT.maxtime = timetoint(detailOASC[numdetail-1].ctime) + 1;
			} else {
				TT.maxtime = timetoint(detailOASC[current_entry+perupdate_window-1].ctime) + 1;
			}
			for (i=current_entry;(i<numdetail)&&(i<current_entry+perupdate_window)&&(i<numdetail);i++) {
				if (FilterOASC(detailOASC[i])) {
					num_perupdate++;
					lastOASC = &(detailOASC[i]);
					AddTimeItem(detailOASC[i]);
					hmode = 1;
					if ((highlight_AS_list_mode)||(highlight_AS_click_mode)||(highlight_AS_country_mode)) {
						hmode = DecideHighlight(detailOASC[i]);
					} else if (highlight_IP_click_mode) {
						DisplayOASCOutline(highlighted_IP_prefix);
						hmode = 0;
						if (Within(detailOASC[i],highlighted_IP_prefix)) {
							hmode = 2;
						}
					}
					DisplayOASC(detailOASC[i],hmode);
				}
			}
			if (num_perupdate > TT.maxitems) {
				TT.numitems = 1;
				AddTimeItem(*lastOASC);
			}
			TT.Arrange();
		}	
		// draw the surrounding lines
		S.Draw();
	} else {
		Draw3D();
	}


	// draw the histogram
	H.Draw();

	// draw the time text
	if (per==1) TT.Draw(); // if drawing per update


}


void OASCViz::Draw3D() {

	int i;
	int hmode;


	SP.num_points = 0;
	if (per==0) {
		for (i=0;i<numdaily;i++) {
			if (FilterOASC(dailyOASC[i])) {
				if ((highlight_AS_list_mode)||(highlight_AS_click_mode)||(highlight_AS_country_mode)) {
					hmode = DecideHighlight(dailyOASC[i]);
				} else if (highlight_IP_click_mode) {
					DisplayOASCOutline(highlighted_IP_prefix);
					hmode = 0;
					if (Within(dailyOASC[i],highlighted_IP_prefix)) {
						hmode = 2;
					}
				}
				if (per==1) hmode = 0;
				DisplayOASC3D(dailyOASC[i],hmode);
			}
		}
	}

	SP.MakeTexMaps();

	SP.Draw();
	Q.DrawSquareXZ();


}



void OASCViz::AddTimeItem(OASC &OO) {

	char buf[256];
	int i;

	if (TT.numitems<TT.maxitems) {
		TT.times[TT.numitems] = timetoint(OO.ctime);
		AssignColor((int)(OO.type),TT.colors[TT.numitems]);
		OASC::AssignText((int)(OO.type), buf);
		sprintf(TT.texts[TT.numitems],"%d %s %d.%d.%d.%d/%d    ", 
			OO.ctime, buf, OO.P.IPAddress[0], OO.P.IPAddress[1], OO.P.IPAddress[2], OO.P.IPAddress[3], OO.P.Mask);
		for (i=0;i<OO.numfrom;i++) {
			sprintf(buf,"%d ", OO.fromAS[i]);
			strcat(TT.texts[TT.numitems], buf);
		}
		strcat(TT.texts[TT.numitems], "--> ");
		for (i=0;i<OO.numto;i++) {
			sprintf(buf,"%d ", OO.toAS[i]);
			strcat(TT.texts[TT.numitems], buf);
		}
		TT.numitems++;
	}

}

void OASCViz::AssignColor(int t, float *f_ptr) {

	float OASC_colors[8][4] = {
		{ 1.0, 0.0, 0.0, 1.0 } ,
		{ 0.0, 1.0, 0.0, 1.0 } ,
		{ 0.0, 0.0, 1.0, 1.0 } ,
		{ 0.8, 1.0, 0.0, 1.0 } ,
		{ 1.0, 0.0, 1.0, 1.0 } ,
		{ 0.0, 1.0, 1.0, 1.0 } ,
		{ 0.9, 0.5, 0.1, 1.0 } ,
		{ 0.1, 0.5, 0.9, 1.0 } };


	if ((t>=0) && (t<8)) {
		f_ptr[0] = OASC_colors[t][0];
		f_ptr[1] = OASC_colors[t][1];
		f_ptr[2] = OASC_colors[t][2];
		f_ptr[3] = OASC_colors[t][3];
	}

}

void OASC::AssignText(int t, char *t_ptr) {

	if (t==0) { strcpy(t_ptr,"OS ");
	} else if (t==1) { strcpy(t_ptr,"OM ");
	} else if (t==2) { strcpy(t_ptr,"CSM");
	} else if (t==3) { strcpy(t_ptr,"CMS");
	} else if (t==4) { strcpy(t_ptr,"CMM");
	} else if (t==5) { strcpy(t_ptr,"CSS");
	} else if (t==6) { strcpy(t_ptr,"H  ");
	} else if (t==7) { strcpy(t_ptr,"B  ");
	}

}

void OASCViz::AdvanceDate() {
	int d;
	d = nextday(current_date);
	SetDate(d);
}

void OASCViz::BackDate() {
	int d;
	d = prevday(current_date);
	SetDate(d);
}

void OASCViz::SetDate(int d) {
	if (d>last_date) { current_date = last_date;
	} else if (d<first_date) { current_date = first_date;
	} else { current_date = d;
	}
	ReadDaily(current_date);
	ReadDetail(current_date);
	perupdate_time = 0;
	if (numdetail>0) perupdate_time = detailOASC[0].ctime;
	current_entry = 0;
	H.SetInd(current_date);
}


void OASCViz::AddHighlightAS(int a) {
	int i, ind;
	ind = -1;
	for (i=0;i<num_highlighted_AS;i++) {
		if (highlighted_AS[i] == a) ind = i;
	}
	if ((num_highlighted_AS<MAX_HIGHLIGHT)&&(ind<0)) {
		highlighted_AS[num_highlighted_AS] = a;
		num_highlighted_AS++;
	}
}

void OASCViz::RemoveHighlightAS(int a) {
	int i, ind;
	ind = -1;
	for (i=0;i<num_highlighted_AS;i++) {
		if (highlighted_AS[i] == a) ind = i;
	}
	if (ind>=0) {
		highlighted_AS[ind] = highlighted_AS[num_highlighted_AS-1];
		num_highlighted_AS--;
	}
}









