
#ifndef MATRIX_H
#define MATRIX_H

#define MAXD 24
#define MAXPATHS 64

class Entry {

public:

	int year, month, day, hour, min;
	int fyear, fmonth, fday, fhour, fmin;
	int syear, smonth, sday, shour, smin;
	int show_time;
	int start_time;
	float startx, starty, xsize, ysize;
	float startfrac, finishfrac;

	int npaths;
	Path *paths[MAXPATHS];
	
	Entry() : npaths(0) { };

	void ResetTime() {
		printf("time is reset\n");
		year = syear;
		month = smonth;
		day = sday;
		hour = shour;
		min = smin;
	};
	
	void Advance(int inc_min) {

		int i;
		int new_time;

		i = timetoint(year,month,day,hour,min);
		//printf("before %d %d %d %d %d\n",year,month,day,hour,min);
		//inttotime(i, &year,&month,&day,&hour,&min);
		//printf("after %d %d %d %d %d\n",year,month,day,hour,min);
		i += inc_min;
		if (i > timetoint(fyear,fmonth,fday,fhour,fmin)) {
			year = syear; month = smonth; day = sday; hour = shour; min = smin;
			show_time = start_time;
		} else {
			new_time = show_time;
			while ((new_time<G1.npaths-1) && 
					(timetoint(G1.paths[new_time]->year,
					  G1.paths[new_time]->month,
					  G1.paths[new_time]->day,
					  G1.paths[new_time]->hour,
					  G1.paths[new_time]->min) < i)) {
				new_time++;
			}
			if (new_time > 0) new_time--;
			show_time = new_time;	
			inttotime(i, &year, &month, &day, &hour, &min);
		}

	};


	void Draw() {

		int cont, i, t;

		// ****************** graph  ***************************************************** 

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(-0.2*G1.x,1.2*G1.x,1.2*G1.y,-0.2*G1.y);
				// left, right, bottom, top
		glViewport(startx, starty+0.3*ysize, xsize, 0.7*ysize);
				// startx, starty, xsize, ysize
				// coordinates begin from lower left corner of window		

	    glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();	

	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		glPushMatrix();

		printf("G1 x and y: %d %d\n", G1.x, G1.y);

		G1.Draw();
		G1.DrawPath(show_time);

		cont = 1;
	
		for (i=show_time-1;(i>=0)&&cont;i--) {
			t = timetoint(G1.paths[i]->year,G1.paths[i]->month,G1.paths[i]->day,G1.paths[i]->hour,G1.paths[i]->min) -
				timetoint(year,month,day,hour,min-win_min);
			if (t > 0) {
				G1.DrawPrevPath(i,(float)t/(float)win_min);
			} else {
				cont = 0;
			}
		}

		for (i=0; i<npaths; i++) {
			G1.DrawPathPtr(paths[i]); // draw all the paths travelled in this time window
		}

		glPopMatrix();


		// ****************** time line, total number of announcements ****************** 

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0,512,0,G1.maxnumanns);
				// left, right, bottom, top
		glViewport(startx + 0.1 * xsize, starty + 0.1 * ysize, 0.8 * xsize, 0.1 * ysize);
				// startx, starty, xsize, ysize
				// coordinates begin from lower left corner of window

	    glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		glPushMatrix();
	    G1.DrawTimeLine(show_time);
	    glPopMatrix();


		// ****************** background **************************************************** 

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0.0,1.0,0.0,1.0);
				// left, right, bottom, top
		glViewport(startx + 0.1 * xsize, starty + 0.2 * ysize, 0.8 * xsize, 0.1 * ysize);
				// startx, starty, xsize, ysize
				// coordinates begin from lower left corner of window
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		glPushMatrix();
		G1.DrawBackground(startfrac,finishfrac);
		glPopMatrix();

		
		// ****************** time line, paths **************************************************** 

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluOrtho2D(0,512,-1,2*(G1.ndistinctpaths+1));
				// left, right, bottom, top
		glViewport(startx + 0.1 * xsize, starty + 0.2 * ysize, 0.8 * xsize, 0.1 * ysize);
				// startx, starty, xsize, ysize
				// coordinates begin from lower left corner of window
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);

		glPushMatrix();
		G1.DrawTimeDistinctPaths(show_time);
		glPopMatrix();

	};


};


class Matrix {

public:

	int x, y;

	Entry entries[MAXD][MAXD];

	Matrix() : x(1), y(1) { };

	void setx(int i) { x = i; Init(); };

	void sety(int i) { y = i; Init(); };

	void Init() {

		int a, b;
		int i, n, j, t;
		int found;
		int stime, ftime, k;
		int sy, smo, sd, sh, smi;
		float wid, ht, xs, ys;
		// set the start time and syear, fyear etc. of the entries
		// also set startx, starty, xsize, ysize of the entries
		startyear = G1.paths[0]->year;
		stime = timetoint(G1.paths[0]->year,G1.paths[0]->month,G1.paths[0]->day,G1.paths[0]->hour,G1.paths[0]->min);
		i = G1.npaths - 1;
		ftime = timetoint(G1.paths[i]->year,G1.paths[i]->month,G1.paths[i]->day,G1.paths[i]->hour,G1.paths[i]->min);
		n = x * y;
		k = 1 + (ftime - stime) / n;
		inc_min = k / incr_frac;
		inc_min_spinner->set_int_val(inc_min);
		win_min = inc_min * 3;
		win_min_spinner->set_int_val(win_min);

		wid = sidewidth / (float)x;
		ht = sideheight / (float)y;

		for (a=0;a<x;a++) {
			for (b=0;b<y;b++) {
				i = a * y + b;
				entries[a][b].startfrac = (float)i/(float)(x*y);
				entries[a][b].finishfrac = (float)(i+1)/(float)(x*y);
				inttotime(stime + k * i, &sy, &smo, &sd, &sh, &smi);
				entries[a][b].year = entries[a][b].syear = sy;
				entries[a][b].month = entries[a][b].smonth = smo;
				entries[a][b].day = entries[a][b].sday = sd;
				entries[a][b].hour = entries[a][b].shour = sh;
				entries[a][b].min = entries[a][b].smin = smi;
				printf("starting time for %d is %d %d %d %d %d\n", i, sy, smo, sd, sh, smi);
				inttotime(stime + k * (i + 1), &sy, &smo, &sd, &sh, &smi);
				entries[a][b].fyear = sy;
				entries[a][b].fmonth = smo;
				entries[a][b].fday = sd;
				entries[a][b].fhour = sh;
				entries[a][b].fmin = smi;
				while (timetoint(G1.paths[entries[a][b].start_time]->year, 
								G1.paths[entries[a][b].start_time]->month, 
								G1.paths[entries[a][b].start_time]->day, 
								G1.paths[entries[a][b].start_time]->hour, 
								G1.paths[entries[a][b].start_time]->min) <
								timetoint(entries[a][b].syear,entries[a][b].smonth,entries[a][b].sday,entries[a][b].shour,entries[a][b].smin)) {
					entries[a][b].start_time++;
				}
				if (entries[a][b].start_time > 0) entries[a][b].start_time--;
				printf("start time index %d\n", entries[a][b].start_time);
				entries[a][b].show_time = entries[a][b].start_time;
				xs = (float)b * wid;
				ys = (float)(x-a-1) * ht;
				entries[a][b].startx = xs;
				entries[a][b].starty = ys;
				entries[a][b].xsize = wid;
				entries[a][b].ysize = ht;
				// set the paths shown in this window
				entries[a][b].npaths = 0;
				t = entries[a][b].start_time;
				i = timetoint(G1.paths[entries[a][b].start_time]->year, 
								G1.paths[entries[a][b].start_time]->month, 
								G1.paths[entries[a][b].start_time]->day, 
								G1.paths[entries[a][b].start_time]->hour, 
								G1.paths[entries[a][b].start_time]->min) + k;
				while ((t<G1.npaths)&&(timetoint(G1.paths[t]->year, G1.paths[t]->month, G1.paths[t]->day, G1.paths[t]->hour, G1.paths[t]->min) < i)) {
					found = 0;
					for (j=0; j<entries[a][b].npaths;j++) {
						if (nodesSame(entries[a][b].paths[j],G1.paths[t])) {
							found = 1;
						}
					}
					if (found==0) {
						entries[a][b].paths[entries[a][b].npaths] = G1.paths[t];
						entries[a][b].npaths++;
					}
					t++;
				}
				printf("num paths %d %d is %d\n", a, b, entries[a][b].npaths);

			}
		}

	};

	void Draw() {
		int i, j;
		for (i=0;i<x;i++) {
			for (j=0;j<y;j++) {
				entries[i][j].Draw();
			}
		}
	};

	void Advance(int inc_min) {
		int i, j;
		printf("indices ");
		for (i=0;i<x;i++) {
			for (j=0;j<y;j++) {
				entries[i][j].Advance(inc_min);
				printf("%d ", entries[i][j].show_time);
			}
		}
		printf("\n");
	};

};



#endif
