/*
 *                            Author :  Vincent Hayward
 *                                      School of Electrical Engineering
 *                                      Purdue University
 *      Dir     : uti
 *      File    : dsp.c
 *      Remarks : pseudo graphic terminal plotting
 *      Usage   : cc dsp.c -ltermlib  -o mybin/dsp
 */


#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <sgtty.h>


#define MAX     10000
#define PREC    (1.e-2)
#define YES 1
#define NO  0
#define GO(x, y)        fputs(tgoto(CM, y, x), stdout)

static struct sgttyb mode;

main(argc ,argv)
int argc;
char **argv;
{
	FILE *fp ,*nfp, *fptime ,*fpchar ,*fopen();
	char *getenv(), *tgetstr(), *rdchar(), *tgoto();
	char   chars[MAX];
	int ind, dtime, scroll = NO, pro = YES, lx[24], ly[80], incr = 1;
	int np, i, bias, c, pos_disp, vel_disp, acc_disp;
	int abt(), ouf();
	char name[30] ,base[30], root[30],
	     tfil[30], cfil[30], num[20],
	     nname[30], nbase[30];
	char *nbp, *pre, *lab;
	int timb[MAX];
	double pos[MAX] ,vel[MAX] ,acc[MAX] ,*buffer;
	double pmax, pmin, vmax, vmin, amax, amin, maxi ,mini, step, d;
	char buf[1024],  cmbuff[30], *x;
	char *CL, *CM;
	int lin, col;

	signal (SIGINT ,abt);
	if (argc > 2)
		exit(1);
	else {
		if ((pre = getenv("GRAPHDIR")) == NULL) {
			pre = "../g";
		}
		strcpy(root ,pre);
		strcat(root ,"/");
		do {
			strcpy(name, root);
			if (argc == 1) {
				printf("file ? ");
				if (scanf("%s", base) < 0) {
					printf("\n");
					exit(2);
				}
			}
			else {
				strcpy(base ,*++argv);
			}
			strcat(name, base);
			strcat(name ,".out");
			argc = 1;
		} while ((fp = fopen(name ,"r")) == NULL);
	}
	strcpy(tfil, root);
	strcat(tfil, "t.out");
	if ((fptime = fopen(tfil ,"r")) != NULL) {
		np = fread(timb ,sizeof(int) ,MAX ,fptime);
		if (np < 0) {
			printf("read error\n");
			exit(1);
		}
		if (np == 0) {
			printf("empty time file\n");
			exit(2);
		}
		incr = timb[1] - timb[0];
		bias = 6;
	}
	else {
		bias = 4;
	}

	np = fread(pos ,sizeof(double) ,MAX ,fp);
	if (np < 0) {
		printf("read error\n");
		exit(1);
	}
	if (np == 0) {
		printf("empty point file\n");
		exit(2);
	}

	strcpy(cfil, root);
	strcat(cfil, "c.out");
	if ((fpchar = fopen(cfil ,"r")) != NULL) {
		if (fread(chars ,sizeof(char) ,MAX ,fpchar) != np) {
			fprintf(stderr ,"dsp:invalid char file\n");
			exit(3);
		}
	}

	tgetent(buf, getenv("TERM"));
	x = cmbuff;
	CL = tgetstr("cl", &x);
	CM = tgetstr("cm", &x);
	col = tgetnum("co");
	lin = tgetnum("li") - 1;

	gtty(1, &mode);
	mode.sg_flags |= CBREAK;
	ioctl(1, TIOCSETP, &mode);

	signal(SIGINT, ouf);

	buffer = pos;
	ind = 0;
rinit:
	pos_disp = vel_disp = acc_disp = YES;
	pmax = -1.e+38; pmin = 1.e+38;
	vmax = -1.e+38; vmin = 1.e+38;
	amax = -1.e+38; amin = 1.e+38;

	for(i = 0; i < np; i++) {
		if (pmax < pos[i])
			pmax = pos[i];
		if (pmin > pos[i])
			pmin = pos[i];
	}
	if (pmax - pmin < PREC) {
		pos_disp = vel_disp = acc_disp =NO;
		GO(lin, 0);
		printf(
		"Flat curve at %8.3f type any character to continue", pos[0]);
		getchar();
		GO(lin, 0);
		printf(
		"                                                          ");
	}
	else {
		for(i = 1; i < np; i++) {
			vel[i] = pos[i] - pos[i-1];
			if (vmax < vel[i])
				vmax = vel[i];
			if (vmin > vel[i])
				vmin = vel[i];
		}
		vel[0] = vel[1];
		if (vmax - vmin < PREC) {
			vel_disp = acc_disp = NO;
			GO(lin, 0);
			printf(
	"Constant velocity at %8.3f type any character to continue", vel[1]);
			getchar();
			GO(lin, 0);
			printf(
	"                                                                  ");
		}
		else {
			for(i = 2; i < np; i++) {
				acc[i] = vel[i] - vel[i-1];
				if (amax < acc[i])
					amax = acc[i];
				if (amin > acc[i])
					amin = acc[i];
			}
			acc[0] = acc[1] = acc[2];
			if (amax - amin < PREC) {
				acc_disp = NO;
				GO(lin, 0);
				printf(
"Constant acceleration at %8.3f  type any character to continue", acc[2]);
				getchar();
				GO(lin, 0);
				printf(
"                                                                          ");
			}
		}
	}
	for ( ; ;) {
		if (buffer == pos && pos_disp == NO ||
		    buffer == vel && vel_disp == NO ||
		    buffer == acc && acc_disp == NO) {
			goto promt;
		}
		if (!scroll) {
			if (buffer == pos) {
				maxi = pmax;
				mini = pmin;
				lab = "POS";
			}
			if (buffer == vel) {
				maxi = vmax;
				mini = vmin;
				lab = "VEL";
			}
			if (buffer == acc) {
				maxi = amax;
				mini = amin;
				lab = "ACC";
			}
			fputs(CL, stdout);
			if (pro) {
				GO(lin ,col - 9);
				printf("%8.3f" ,maxi);
				GO(lin ,0);
				printf("%8.3f" ,mini);
				GO(lin ,44);
				printf("%s " ,base);
				printf(lab);
				i = ind + lin - 1;
				i = (i > np) ? i - np : i;
				GO(lin ,col - 20);
				printf("         ");
				GO(lin ,col - 20);
				printf(" %-5g", buffer[i]);
			}
			else {
				step = (maxi - mini) / 10.;
				GO(lin,  0);
				i = col - 1;
				while(i--) {
					putchar(' ');
				}
				for (d = mini, i = 0;
				     i < col;
				     i += col / 10, d += step) {
					GO(lin, i);
					printf(" %-6.3g", d);
				}
			}
		}
		else {
			i = ind + lin - 1;
			i = (i > np) ? i - np : i;
			GO(lin ,col - 20);
			printf("          ");
			GO(lin, col - 20);
			printf(" %-5g", buffer[i]);
		}
		for(i = 0; i < lin; i++) {
			while(ind >= np)
				ind -= np;
			while(ind < 0)
				ind += np;
			if (scroll) {
				GO(lx[i], ly[i]);
				putchar(' ');
			}
			GO(i, 0);
			if (fptime == NULL)
				printf("%4d|" ,ind);
			else
				printf("%6d|" ,timb[ind]);
			lx[i] = i;
			ly[i] = bias + (int)((buffer[ind] - mini) /
				(maxi - mini + PREC) * (double)(col - bias));
			GO(lx[i] , ly[i]);
			putchar((fpchar == NULL) ? '#' : chars[ind]);
			ind++;
		}
promt :
		if (scroll) {
			if (pro) {
				GO(lin ,42);
			}
			else {
				GO(lin, 0);
			}
			scroll = NO;
		}
		else {
			if (pro) {
				GO(lin ,10);
				printf("!*/s/r/u/d/g/h/b/f/a/v/p/q/+-n/?");
			}
			else {
				GO(lin, 0);
			}
		}

		c = getchar();
		nbp = num;
		if (isdigit(c) || c == '+' || c == '-') {
			do {
				*nbp++ = c;
				c = getchar();
			} while(isdigit(c));
			*nbp = ' ';
			if (sscanf(num,"%d",&dtime) != 1)
				goto promt;
			ind = dtime / incr;
		}
		else {
			switch(c) {
			case 'f' :
				break;
			case 'h' :
				ind -= lin / 2;
				break;
			case 'g' :
				ind -= lin + lin / 2 + 1;
				break;
			case 'b' :
				ind -= lin + lin;
				break;
			case 'p':
				buffer = pos;
				ind -= lin;
				break ;
			case 'a':
				buffer = acc;
				ind -= lin;
				break;
			case 'v':
				buffer = vel;
				ind -= lin;
				break ;
			case 'd' :
				scroll = YES;
				ind -= lin - 1;
				break;
			case 'u' :
				scroll = YES;
				ind -= lin + 1;
				break;
			case 'r' :
				ind -= lin;
				break;
			case 'q':
				ouf();
			case 's':
				ind -= lin;
				pro = NO;
				break;
			case '@':
				ind -= lin;
				pro = YES;
				break;
			case '!':
				strcpy(nname, root);
				nbp = nbase;
				while((*nbp = getchar()) == ' ')
					;
				while ((*++nbp = getchar()) != ' ')
					;
				*nbp = '\0';
				strcat(nname, nbase);
				strcat(nname ,".out");
				if ((nfp = fopen(nname ,"r")) == NULL) {
					GO(lin, 0);
					printf(
			"can't open %s ,type any character to continue", nname);
					getchar();
					GO(lin, 0);
					printf(
		"                                                          ");
				       ind -= lin;
				}
				else {
					fp = nfp;
					strcpy(base, nbase);
					np = fread(pos ,sizeof(double) ,MAX ,fp);
					if (np < 0) {
						printf("read error\n");
						exit(1);
					}
					if (np == 0) {
						printf("empty point file\n");
						exit(2);
					}
					ind -= lin;
					goto rinit;
				}
				break;
			case '?' :
				fputs(CL, stdout);
				printf("!*/s/r/u/d/g/h/b/f/a/v/p/q/+-n/?\n\n");
				printf("\t?\this message\n");
	printf("\t+-n\t[+,-]digits<space> : direct addressing\n");
				printf("\tq\tquit\n");
				printf("\tp\tposition display\n");
				printf("\tv\tvelocity display\n");
				printf("\ta\tacceleration display\n");
				printf("\tf\tforward one page\n");
				printf("\tb\tbackward one page\n");
				printf("\th\thalf page forward\n");
				printf("\tg\thalf page backward\n");
				printf("\td\tdown one line\n");
				printf("\tu\tup one line\n");
				printf("\tr\tredraw\n");
				printf("\ts\tscale\n");
				printf("\t@\tback to prompt\n");
	printf("\t!*\t!<space>file<space> : show another file\n");
				printf("\n\ngraphic directory is %s\n", pre);
				printf("\n\nType any character to continue");
				getchar();
				ind -= lin;
				break;
			default :
				goto promt;
			}
		}
	}
}

abt()
{
	putchar('\n');
	exit(0);
}

ouf()
{
	putchar('\n');
	mode.sg_flags &= ~CBREAK;
	ioctl(1, TIOCSETP, &mode);
	exit(0);
}

