/*
 * DBOT Version 1.0           Author :  Vincent Hayward
 *                                      School of Electrical Engineering
 *                                      Purdue University
 *      Dir     : db
 *      File    : edb.c
 *      Remarks : The data base editor.
 *      Usage   : make edb
 */

#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include "../h/rccl.h"
#include "../h/umac.h"

#define BEGIN   0
#define RW      2
#define BUFS    1024

static TRSF cht;
static TRSF_PTR ch = &cht;
static TRSF pht;
static TRSF_PTR ph = &pht;
static char readn[80];
static errset;

/*
 * works on a copy of the file
 * if exit by 'q' copy new into old, keep old
 * if exit by 'q!' copy the copy into original
 */

main(argc, argv)
int argc;
char **argv;
{
	char *strcat(), *strcpy(), *sprintf();
	int intr();
	char st[20], sto[20], sti[20];
	int fddb, fddbo, fddbi;
	int q, action, saved = YES;
	char trname[80];
	char *unitn = "UNIT";
	TRSF tr;

	if (argc != 2) {
		fprintf(stderr, "usage : edbt file\n");
		exit(1);
	}
 (void) strcpy(st, argv[1]);
	if ((fddb = open(st, RW)) < 0) {
		printf("can't open %s, create ?", st);
		QUERY(q);
		if (q == 'y') {
			if ((fddb = makedb(st)) < 0) {
				exit(14);
			}
			if ((fddb = open(st, RW)) < 0) {
				exit(15);
			}
		}
		else {
			exit(0);
		}
	}

 (void) signal(SIGINT, intr);
 (void) strcpy(sto, st);
 (void) strcat(sto, ".old");
	fddbo = make(sto);
	copy(fddbo, fddb);
	if ((fddbo = open(sto, RW)) < 0) {
		fprintf(stderr, "can't open %s\n", sto);
		exit(2);
	}
	printf("transform data base editor V1.0\n");
	tr.name = trname;
 (void) strcpy(trname, unitn);
	Assigntr(&tr, unitr);
	for (; ; ) {
		Assigntr(ch, unitr);
		while ((action = parse()) == 'e' || action == ' ') {
		}
		switch (action) {
		case 'x' :
			copy(fddbo, fddb);
			exit(0);

		case 'q' :
			if (!saved) {
				printf("loose %s ?", tr.name);
				QUERY(q);
				if (q == 'n') {
					break;
				}
			}
		 (void) sprintf(sti, "%d", getpid());
		 (void) strcat(sti, ".edb");
			if (compactdb(sto) < 0) {
				fprintf(stderr, "compact error\n");
				exit(8);
			}
			fddbi = make(sti);
			copy(fddbi, fddb);
			fddb = make(st);
			copy(fddb, fddbo);
			fddbo = make(sto);
			copy(fddbo, fddbi);
			if (unlink(sti) < 0) {
				fprintf(stderr, "could'nt unlink\n");
			}
			exit(0);

		case 'd' :
			if (dumpdb(fddbo, NO) < 0) {
				exit(21);
			}
			break;

		case 'D' :
			if (dumpdb(fddbo, YES) < 0) {
				exit(22);
			}
			break;

		case 'u' :
			if (!saved) {
				printf("loose %s ?", tr.name);
				QUERY(q);
				if (q == 'n') {
					break;
				}
			}
			if (strcmp(readn, "UNIT") == 0) {
			 (void) strcpy(tr.name, unitn);
				Assigntr(&tr, unitr);
				break;
			}
			tr.name = readn;
			switch (gettr(&tr, fddbo)) {
			case -1 :
				exit(24);

			case -2 :
				tr.name = trname;
				break;

			default :
				tr.name = trname;
			 (void) strcpy(tr.name, readn);
				break;
			}
			saved = YES;
			break;

		case 's' :
			if ((q = savetr(&tr, fddbo)) < 0) {
				exit(23);
			}
			if (q == 0) {
				saved = YES;
			}
			break;

		case 'n' :
		 (void) strcpy(tr.name, readn);
			printf("renamed %s\n", tr.name);
			saved = NO;
			break;

		case ':' :
			printrn(&tr, stdout);
			break;

		case 'r' :
			printf("remove %s ?", readn);
			QUERY(q);
			if (q == 'y') {
				if (remtr(readn, fddbo) == -1) {
					exit(25);
				}
			}
			break;

		case 'y' :
			saved = NO;
			Trmultinp(&tr, ch);
			break;

		case 'p' :
			saved = NO;
			Taketrsl(&tr, ph);
			break;

		case 'P' :
			saved = NO;
			Takerot(&tr, ph);
			break;

		case 'i' :
			saved = NO;
			Invertinp(&tr);
			break;

		default :
			break;
		}
	}
}



static char coml[80], *c;


static parse()  /*##*/
{
	double getreal();
	double x1, x2, x3, x4, x5, x6;

	errset = NO;
	putchar('?');
 (void) gets(coml);
	if (strlen(coml) == 0) {
		return(' ');
	}

	for (c = coml; *c != '\0';) {
		while (*c != '\0' && isspace(*c)) {
			++c;
		}
		switch (*c) {
		case 'q' :
			++c;
			if (*c == '!') {
				if (*++c != '\0') {
					err();
					return('e');
				}
				return('x');
			}
			else {
				if (*c != '\0') {
					err();
					return('e');
				}
				return('q');
			}

		case 'r' :
			while (isspace(*++c))
				;
		 (void) strcpy(readn, c);
			return('r');

		case 'n' :
			while (isspace(*++c))
				;
		 (void) strcpy(readn, c);
			if (strlen(readn) == 0) {
				err();
				return('e');
			}
			return('n');

		case ':' :
			if (*++c != '\0') {
				err();
				return('e');
			}
			return(':');

		case 's' :
			if (*++c != '\0') {
				err();
				return('e');
			}
			return('s');

		case 'd' :
			++c;
			if (*c == 'v') {
				if (*++c != '\0') {
					err();
					return('e');
				}
				return('D');
			}
			else {
				if (*c != '\0') {
					err();
					return('e');
				}
				return('d');
			}

		case 'u' :
			while (isspace(*++c))
				;
		 (void) strcpy(readn, c);
			if (strlen(readn) == 0) {
				err();
				return('e');
			}
			return('u');

		case 'i':
			if (*++c != '\0') {
				err();
				return('e');
			}
			return('i');

		case 'p' :
			switch(*++c) {
			case 't' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				if (!errset) {
					Trsl(ph, x1, x2, x3);
				}
				else {
					return('e');
				}
				return('p');

			case 'X' :
				Rot(ph, xunit, getreal());
				return('P');

			case 'Y' :
				Rot(ph, yunit, getreal());
				return('P');

			case 'Z' :
				Rot(ph, zunit, getreal());
				return('P');

			case 'a' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				x4 = getreal();
				x5 = getreal();
				x6 = getreal();
				if (!errset) {
					Vao(ph, x1, x2, x3, x4, x5, x6);
				}
				else {
					return('e');
				}
				return('P');

			case 'e' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				if (!errset) {
					Eul(ph, x1, x2, x3);
				}
				else {
					return('e');
				}
				return('P');

			case 'r' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				if (!errset) {
					Rpy(ph, x1, x2, x3);
				}
				else {
					return('e');
				}
				return('P');

			default :
				err();
				break;
			}
			break;

		case 'm' :
			switch(*++c) {
			case 't' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				if (!errset) {
					Trslm(ch, x1, x2, x3);
				}
				else {
					return('e');
				}
				break;

			case 'X' :
				Rotm(ch, xunit, getreal());
				break;

			case 'Y' :
				Rotm(ch, yunit, getreal());
				break;

			case 'Z' :
				Rotm(ch, zunit, getreal());
				break;

			case 'a' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				x4 = getreal();
				x5 = getreal();
				x6 = getreal();
				if (!errset) {
					Vaom(ch, x1, x2, x3, x4, x5, x6);
				}
				else {
					return('e');
				}
				break;

			case 'e' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				if (!errset) {
					Eulm(ch, x1, x2, x3);
				}
				else {
					return('e');
				}
				break;

			case 'r' :
				x1 = getreal();
				x2 = getreal();
				x3 = getreal();
				if (!errset) {
					Rpym(ch, x1, x2, x3);
				}
				else {
					return('e');
				}
				break;

			default :
				err();
				return('e');
			}
			break;

		case '\0':
			break;

		default :
			err();
			return('e');
		}
	}
	return('y');
}


/*
 *                  -------        -< d >-
 *                \|       |     \|       |
 *                 --< d >---< . >---------
 *       -< + >-  |        |              |
 *      |       | |         --------------|/
 *   >--------------< . >----< d >-------------->
 *      |       |          |\      |
 *       -< - >-            -------
 */

static double getreal()  /*##*/
{
	char *f;
	double v;

	++c;
	while (isspace(*c)) {
		++c;
	}
	f = c;
	switch (*c) {
	case '\0' :
		err();
		return(0.);

	case '+' :
		++c;
		break;

	case '-' :
		++c;
		break;
	}
	switch (*c) {
	case '\0' :
		err();
		return(0.);

	case '.' :
		++c;
		if (!isdigit(*c)) {
			err();
			return(0.);
		}
		while (isdigit(*c)) {
			++c;
		}
		break;

	default :
		if (!isdigit(*c)) {
			err();
			return(0.);
		}

		while (isdigit(*c)) {
			++c;
		}
		if (*c == '.') {
			++c;
			while(isdigit(*c)) {
				++c;
			}
		}
		break;
	}
	v = atof(f);
	if (FABS(v) > 10000) {
		err();
		v = 0.;
	}
	return(v);
}



static err() /*##*/
{
	int n;

	if (errset) {
		return;
	}
	errset = YES;
	*c = '\0';
	n = strlen(coml) + 1;
	while (n--) {
		putchar(' ');
	}
	putchar('^');
	putchar('\n');
}


static copy(t, s)  /*##*/
int t, s;
{
	char bd[BUFS];
	int n;
	long lseek();

	if (lseek(s, 0L, BEGIN) < 0) {
		fprintf(stderr, "can't rewind data base file\n");
		exit(10);
	}
	if (lseek(t, 0L, BEGIN) < 0) {
		fprintf(stderr, "can't rewind data base file\n");
		exit(11);
	}
	while ((n = read(s, bd, BUFS)) > 0) {
		if (write(t, bd, n) < 0) {
			fprintf(stderr, "can't duplicate data base file\n");
			exit(12);
		}
	}
}


static make(n)  /*##*/
char *n;
{
	int f;

	if ((f = creat(n, 0644)) < 0) {
		fprintf(stderr, "can't creat data base file %s\n", n);
		exit(20);
	}
	if ((f = open(n, RW)) < 0) {
		fprintf(stderr, "open error on data base file %s\n", n);
		exit(21);
	}
	return (f);
}


static char help[] =
"\
These commands are executed one per line:\n\
\tq\t\tquit and save file\n\
\tq!\t\tquit and do not save\n\
\td[v]\t\tdump data base [verbose]\n\
\tu <name>\tuse transform 'name'\n\
\ts\t\tsave active transform\n\
\tn <name>\trename active transform\n\
\t:\t\tshow active transform\n\
\tr <name>\tremove transform 'name' from file\n\
\ti\t\tinvert active transform\n\
\tpt x y z\tpatch a translation x y z\n\
\tp<X/Y/Z> a\tpatch a rotation a around X, Y, or Z axis\n\
\tpa x y z x y z\tpatch a rotation defined by a and o vectors\n\
\tpe phi the psi\tpatch a rotation from Euler angles\n\
\tpr phi the psi\tpatch a rotation from roll pitch and yaw angles\n\
These commands are cumulative:\n\
\tmt x y z\tmultiply by translation x y z\n\
\tm<X/Y/Z> a\tmultiply by rotation a around X, Y, or Z axis\n\
\tma x y z x y z\tmultiply by rotation defined by a and o vectors\n\
\tme phi the psi\tmultiply by rotation from Euler angles\n\
\tmr phi the psi\tmultiply by rotation from roll pitch and yaw angles\n\
";


static intr()  /*##*/
{
	signal(SIGINT, intr);
	printf("commands:\n");
	printf("%s", help);
	*coml = '\0';
}
