
#ifndef INSTABILITY_H
#define INSTABILITY_H

#include <math.h>

#define MAX_NUM_INSTABILITY_ENTRIES 128
#define MAX_NANNS 32
#define MAX_NUM_REGIONS 32
#define MAX_LEGEND_CLASSES 32

#ifndef PI
#define PI 3.14159265

float segmentcolors[6][3] = { { 1.0, 0.0, 0.0} , { 0.0, 1.0, 0.0} , 
								{ 0.0, 1.0, 1.0} , { 1.0, 0.0, 1.0} , 
								{ 1.0, 1.0, 0.0} , { 0.0, 0.0, 1.0} };

float regioncolors[5][5][3] = { 
{ {1.0,0.0,0.3},{1.0,0.2,0.0},{1.0,0.5,0.3},
	{1.0,0.3,0.1},{1.0,0.4,0.1} },
{ {0.3,1.0,0.4},{0.1,1.0,0.3},{0.3,1.0,0.1},
	{0.2,1.0,0.2},{0.0,1.0,0.2} },
{ {0.3,0.1,1.0},{0.1,0.4,1.0},{0.1,0.1,1.0},
	{0.2,0.0,1.0},{0.0,0.0,1.0} },
{ {0.3,1.0,0.4},{0.1,1.0,0.3},{0.3,1.0,0.1},
	{0.2,1.0,0.2},{0.0,1.0,0.2} },
{ {0.3,1.0,0.4},{0.1,1.0,0.3},{0.3,1.0,0.1},
	{0.2,1.0,0.2},{0.0,1.0,0.2} } 
};

class InstabilityEntry {

public:
	int Flags; // os pure/impure bal/unbal sc preWD postWD rshort rlong
			   // 0  1           2         3  4     5      6      7
			   // multWD
			   // 8

	int TimeStamp;

	float x, y, r, x1, x2;
	int resolution;

	int n; // num announcements in this instability sequence
	int s; // index of first announcement

	InstabilityEntry() : Flags(0) , TimeStamp(0) , resolution(60) , n(0) { };


	void renderCenter(float cx, float cy, float mulx, float muly) { // draw circle

		int i;
		int segments[6];
		int numsegments;
		float incr, theta;
		float segmentangle;
		float adj,adj1,adj2;
		int no_signature;

		numsegments = 0;
		for (i=0;i<6;i++) {
			if (Flags & 1 << i) {
				segments[numsegments] = i;
				numsegments++;
			}
		}

		no_signature = 0;
		if (numsegments==0) {
			numsegments = 1;
			no_signature = 1;
		}

		incr = 2.0*PI/(float)resolution;
		segmentangle = 2.0*PI/(float)numsegments;

		for (i=0;i<numsegments;i++) {

			if (no_signature==1) {
				glColor3f(0.5,0.5,0.5);
			} else {
				glColor3f(segmentcolors[segments[i]][0],segmentcolors[segments[i]][1],segmentcolors[segments[i]][2]);
			
			}
			glBegin(GL_POLYGON);
			for (theta = segmentangle*(float)i; theta<(segmentangle*(float)(i+1)); theta += incr) {
				glVertex3f(cx+mulx*r*cos(theta),cy+muly*r*sin(theta),0.0);
			}
			glVertex3f(cx+mulx*r*cos(segmentangle*(float)(i+1)),cy+muly*r*sin(segmentangle*(float)(i+1)),0.0);
			glEnd();
		}
		
		if (publication) {
			glColor3f(0.0,0.0,0.0);
		} else {
			glColor3f(1.0,1.0,1.0);
		}
		

	};


	void render() {
		renderCenter(x,y,1.0,1.0);
		
		glLineWidth(1);
		glBegin(GL_LINES);
		glVertex3f(x,y,0.1);
		glVertex3f(x1,0.0,0.1);
		glVertex3f(x,y,0.1);
		glVertex3f(x2,0.0,0.1);
		glEnd();

	};



	void render_base() {

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glColor4f(0.5,0.5,0.5,0.3);
		glBegin(GL_TRIANGLES);
		glVertex3f(x,y,0.1);
		glVertex3f(x1,0.0,0.1);
		glVertex3f(x2,0.0,0.1);
		glEnd();
		glDisable(GL_BLEND);

	};
};


class Instability {

public:

	int numentries;

	int beginunivtime, endunivtime;

	float startx, starty, xsize, ysize;

	InstabilityEntry Entries[MAX_NUM_INSTABILITY_ENTRIES];

	Instability() : numentries(0) { };

	void Init(float sx, float sy, float xs, float ys) {
		startx = sx; starty = sy; xsize = xs; ysize = ys;
	};

	void Draw() {

		int i;

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0.0,1.0,0.0,ysize/xsize);
				// 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();
	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		for (i=0;i<numentries;i++) {
			Entries[i].render();
		}

		for (i=0;i<numentries;i++) {
			Entries[i].render_base();
		}
	};


	void DrawRaw(int tstart, int twin) {

		int st, et, i, j, n;
		int firstwritepath;
		int lastwritepath;
		int slot;
		int es, ee;
		int n1, n2;

		st = tstart; // starting time of the window
		et = tstart + twin;

		slot = 0;
		i = G1.pindices[slot];
		while ((slot<511)&&(i<G1.npaths)&&(G1.paths[i]->univtime < st)) {
			i = G1.pindices[slot];
			slot++;
		}
		if (slot > 0) slot--;
		i = G1.pindices[slot];
		while ((i<G1.npaths)&&(G1.paths[i]->univtime < st)) i++;
		firstwritepath = i;
		while ((i<G1.npaths)&&(G1.paths[i]->univtime < et)) i++;
		lastwritepath = i;

		for (i=0;i<numentries;i++) {
			es = Entries[i].s;
			ee = Entries[i].s + Entries[i].n - 1;
			if (((es >= firstwritepath) && (es <= lastwritepath)) ||
				((ee >= firstwritepath) && (ee <= lastwritepath)) ||
				((firstwritepath > es) && (firstwritepath < ee))) {
				n1 = es - firstwritepath;
				n2 = ee - firstwritepath;
				glColor3f(0.5,0.5,0.5);
				glLineWidth(1);
				glBegin(GL_LINES);
				glVertex3f(80.0,45.0-1.25*(float)n1,0.0);
				glVertex3f(80.0,45.0-1.25*(float)n2,0.0);
				glVertex3f(80.0,45.0-1.25*(float)n1,0.0);
				glVertex3f(100.0,45.0-1.25*0.5*(float)(n1+n2),0.0);
				glVertex3f(80.0,45.0-1.25*(float)n2,0.0);
				glVertex3f(100.0,45.0-1.25*0.5*(float)(n1+n2),0.0);
				glEnd();
				Entries[i].renderCenter(100.0,45.0-1.25*0.5*(float)(n1+n2),200.0,100.0);
			}
		}

	};


	void ReadEntry(int y, int m, int d, int h, int min, int y2, int m2, int d2, int h2, int min2, 
					char *flags, int start, int nanns, float maxT) {
		int t,i,temp;
		int array[5];
		array[0] = y;
		array[1] = m;
		array[2] = d;
		array[3] = h;
		array[4] = min;
		t = G1.ArrayToUniv(array);
		Entries[numentries].x1 = (float)(t-beginunivtime)/(float)(endunivtime-beginunivtime);
		array[0] = y2;
		array[1] = m2;
		array[2] = d2;
		array[3] = h2;
		array[4] = min2;
		t = G1.ArrayToUniv(array);
		Entries[numentries].x2 = (float)(t-beginunivtime)/(float)(endunivtime-beginunivtime);
		Entries[numentries].x = 0.5 * (Entries[numentries].x1 + Entries[numentries].x2);
		Entries[numentries].y = 0.1;
		Entries[numentries].r = sqrt(maxT)/100.0;
		Entries[numentries].s = start;
		Entries[numentries].n = nanns;
		for (i=0;i<9;i++) {
			if (flags[i]=='1') {
				Entries[numentries].Flags = Entries[numentries].Flags | (1<<i);
			}
		}
		numentries++;	
	};



	void ReadIFile(char *fname) {
		FILE *fptr;
		char buf[256];
		int y,m,d,h,min,y2,m2,d2,h2,min2,s,n;
		float mT;
		char fg[16];
		int i,j;
		float intervals[128][2];
		int nintervals;
		float es;
		float proposedy, conflictedEnd;
		int conflicted;
		int nn;
		if (numentries > 0) {
			for (i=0; i<numentries; i++) {
				Entries[i].Flags = 0;
				Entries[i].TimeStamp = 0;
				Entries[i].n = 0;
			}
			numentries = 0;
		}
		//beginunivtime = univs[2001-UNIVSTARTYEAR][0][0] * 24 * 60;
		//endunivtime = univs[2002-UNIVSTARTYEAR][0][0] * 24 * 60;
		fptr = fopen(fname,"rt");
		fgets(buf,256,fptr);
		sscanf(buf,"%d", &nn);
		for (i=0;i<nn;i++) {
			fgets(buf,256,fptr);
			sscanf(buf,"%d %d %d %d %d %d %d %d %d %d %s %d %d %f", 
				&y,&m,&d,&h,&min,&y2,&m2,&d2,&h2,&min2,fg,&s,&n,&mT);
			if (strlen(buf)>1) {
				ReadEntry(y,m,d,h,min,y2,m2,d2,h2,min2,fg,s,n,mT);
			}
		}
		fclose(fptr);		
		for (i=0;i<numentries;i++) {
			es = Entries[i].x - Entries[i].r;
			nintervals = 0;
			for (j=0;j<i;j++) {
				if (Entries[j].x + Entries[j].r > es) {
					intervals[nintervals][0] = Entries[j].y - Entries[j].r;
					intervals[nintervals][1] = Entries[j].y + Entries[j].r;
					nintervals++;
				}
			}
			conflicted = 1;
			conflictedEnd = 0.01;
			proposedy = conflictedEnd + Entries[i].r;
			while (conflicted) {
				conflicted = 0;
				for (j=0;j<nintervals;j++) {
					if (((intervals[j][0] < proposedy + Entries[i].r) && (intervals[j][0] >= proposedy - Entries[i].r)) ||
						((intervals[j][1] <= proposedy + Entries[i].r) && (intervals[j][1] > proposedy - Entries[i].r)) ||
						((proposedy + Entries[i].r <= intervals[j][1]) && (proposedy + Entries[i].r > intervals[j][0]))) {
						if (intervals[j][1] > conflictedEnd) conflictedEnd = intervals[j][1];
						proposedy = conflictedEnd + Entries[i].r + 0.001;
						conflicted = 1;
					}
				}
			}
			Entries[i].y = proposedy;
		}
	};

}; 

class Regions {

public:

	int beginunivtime, endunivtime;

	float startx, starty, xsize, ysize;


	int numregions;
	float regionsx[MAX_NUM_REGIONS];
	int regions[MAX_NUM_REGIONS];
	int subregions[MAX_NUM_REGIONS];

	void Init(float sx, float sy, float xs, float ys) {
		startx = sx; starty = sy; xsize = xs; ysize = ys;
	};

	Regions() : numregions(0) { };

	void ReadIFile(char *fname) {
		FILE *fptr;
		char buf[256];
		int r,sr,y,m,d,h,min;
		int t;
		beginunivtime = univs[2001-UNIVSTARTYEAR][0][0] * 24 * 60;
		endunivtime = univs[2002-UNIVSTARTYEAR][0][0] * 24 * 60;
		fptr = fopen(fname,"rt");
		while(!feof(fptr)) {
			fgets(buf,256,fptr);
			sscanf(buf,"%d %d %d %d %d %d %d",&r,&sr,&y,&m,&d,&h,&min);
			if (strlen(buf)>1) {
				regions[numregions] = r;
				subregions[numregions] = sr;
				t = univs[y-UNIVSTARTYEAR][m-1][d-1] * 24 * 60 + h + min;
				regionsx[numregions] = (float)(t-beginunivtime)/(float)(endunivtime-beginunivtime);
				numregions++;
			}
		}
		regionsx[numregions] = 1.0;
		fclose(fptr);		
	};

	void Draw() {

		int i;
		int r, sr;

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0.0,1.0,0.0,1.0);
				// 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();
	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		for (i=0;i<numregions;i++) {
			r = regions[i]; sr = subregions[i];
			glColor3f(0.3*regioncolors[r][sr][0],0.3*regioncolors[r][sr][1],0.3*regioncolors[r][sr][2]);
			glBegin(GL_QUADS);
			glVertex3f(regionsx[i],0.0,-0.1);
			glVertex3f(regionsx[i],1.0,-0.1);
			glVertex3f(regionsx[i+1],1.0,-0.1);
			glVertex3f(regionsx[i+1],0.0,-0.1);
			glEnd();
			glColor3f(regioncolors[r][sr][0],regioncolors[r][sr][1],regioncolors[r][sr][2]);
			glBegin(GL_QUADS);
			glVertex3f(regionsx[i],0.23,0.0);
			glVertex3f(regionsx[i],0.25,0.0);
			glVertex3f(regionsx[i+1],0.25,0.0);
			glVertex3f(regionsx[i+1],0.23,0.0);
			glEnd();
		}

	};

};

class Legend {

public:

	int numClasses;

	float colors[MAX_LEGEND_CLASSES][3];
	char labels[MAX_LEGEND_CLASSES][64];

	float startx, starty, xsize, ysize;

	Legend() : numClasses(0) { };

	void Init(float sx, float sy, float xs, float ys) {
		startx = sx; starty = sy; xsize = xs; ysize = ys;
		colors[0][0] = 1.0; colors[0][1] = 0.0; colors[0][2] = 0.0; 
		colors[1][0] = 1.0; colors[1][1] = 0.3; colors[1][2] = 0.0; 
		colors[2][0] = 1.0; colors[2][1] = 0.0; colors[2][2] = 0.3;
		colors[3][0] = 0.0; colors[3][1] = 1.0; colors[3][2] = 0.0;
		colors[4][0] = 0.5; colors[4][1] = 1.0; colors[4][2] = 0.0;
		colors[5][0] = 0.0; colors[5][1] = 1.0; colors[5][2] = 0.5;
		colors[6][0] = 1.0; colors[6][1] = 1.0; colors[6][2] = 0.0;
		colors[7][0] = 0.9; colors[7][1] = 0.9; colors[7][2] = 0.0;
		colors[8][0] = 0.0; colors[8][1] = 0.0; colors[8][2] = 1.0;
		strcpy(labels[0],"A");
		strcpy(labels[1],"B");
		strcpy(labels[2],"C");
		strcpy(labels[3],"D");
		strcpy(labels[4],"E");
		strcpy(labels[5],"F");
		strcpy(labels[6],"");
		strcpy(labels[7],"");
		strcpy(labels[8],"");
		numClasses = 9;
	};
	
	void Draw() {

		int i,j;
		float boxw, realboxw, margin;

		boxw = 1.0/(float)numClasses;
		margin = 0.1 * boxw;
		realboxw = 0.8 * boxw;

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0.0,1.0,0.0,1.0);
				// 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();
	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		glColor3f(0.6,0.6,0.6);
		glBegin(GL_QUADS);
		glVertex3f(0.0,0.0,0.0);
		glVertex3f(0.0,1.0,0.0);
		glVertex3f(1.0,1.0,0.0);
		glVertex3f(1.0,0.0,0.0);
		glEnd();

		for (i=0; i<6; i++) {
			glColor3f(segmentcolors[i][0],segmentcolors[i][1],segmentcolors[i][2]);
			glBegin(GL_QUADS);
			glVertex3f(boxw*(float)i + margin, 0.5, 0.1);
			glVertex3f(boxw*(float)i + margin, 0.8, 0.1);
			glVertex3f(boxw*(float)i + margin + realboxw, 0.8, 0.1);
			glVertex3f(boxw*(float)i + margin + realboxw, 0.5, 0.1);
			glEnd();

			glColor3f(0.0,0.0,0.0);
			for (j=0;j<strlen(labels[i]);j++) {
				glRasterPos3f(boxw*(float)i + margin + 0.008*(float)j,0.3,0.1);
				glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,labels[i][j]);
			}
		
		}

	};


};

#endif PI

#endif INSTABILITY_H

