#include "term.h"
#include <osbind.h>
#include <mintbind.h>
#include <keycodes.h>
#include <process.h>
#include <signal.h>
#include <sgtty.h>

/* key that gets us out of VT52 -- ^G, for now */
#define QUITKEY '\007'
extern void normal_putch(), escy_putch();

int kidpid;		/* child's process id */
int kidfd;		/* child's file descriptor */
int savex, savey;	/* saved x, y coordinates */
void (*state)();

/*
 * clrfrom(x1, y1, x2, y2): clear screen from position (x1,y1) to
 * position (x2, y2) inclusive. It is assumed that y2 >= y1.
 */

void
clrfrom(x1, y1, x2, y2)
	int x1,y1,x2,y2;
{
}

void
ignore()
{
	state = normal_putch;
}

/*
 * putesc(v, c): handle the control sequence ESC c
 */

#define gotoxy(x, y) m_move(x, y)

void
putesc(c)
	int c;
{
	int cx, cy;

	switch (c) {
	case 'A':		/* cursor up */
		m_up(10);	/* BUG -- this scrolls; it shouldn't */
		break;
	case 'B':		/* cursor down */
		m_down(10);	/* BUG -- this scrolls; it shouldn't */
		break;
	case 'C':		/* cursor right */
		m_right(10);
		break;
	case 'D':		/* cursor left */
		m_left(10);
		break;
	case 'E':		/* clear home */
		m_clear();
		break;
	case 'H':		/* cursor home */
		gotoxy(0, 0);
		break;
	case 'I':		/* cursor up, insert line */
		m_up(10);
		break;
	case 'J':		/* clear below cursor */
		m_cleareos();
		break;
	case 'K':		/* clear remainder of line */
		m_cleareol();
		break;
	case 'L':		/* insert a line */
		m_addline();
		break;
	case 'M':		/* delete line */
		m_deleteline();
		break;
	case 'Y':
		state = escy_putch;
		return;		/* YES, this should be 'return' */
	case 'b':		/* set foreground color */
	case 'c':		/* set background color */
		state = ignore;
		return;
	case 'd':		/* clear to cursor position */
		get_cursor(&cx, &cy);
		clrfrom(0, 0, cx, cy);
		break;
	case 'e':		/* enable cursor */
		m_setcursor(CS_BLOCK);
		break;
	case 'f':		/* cursor off */
		m_setcursor(CS_INVIS);
		break;
	case 'j':		/* save cursor position */
		get_cursor(&savex, &savey);
		break;
	case 'k':		/* restore saved position */
		gotoxy(savex, savey);
		break;
	case 'l':		/* clear line */
		get_cursor(&cx, &cy);
		gotoxy(0, cy);
		m_cleareol();
		break;
	case 'o':		/* clear from start of line to cursor */
		get_cursor(&cx, &cy);
		clrfrom(0, cy, cx, cy);
		break;
	case 'p':		/* reverse video on */
		m_standout();
		break;
	case 'q':		/* reverse video off */
		m_standend();
		break;
	case 'v':		/* wrap on */
		m_clearmode(M_NOWRAP);
		break;
	case 'w':
		m_setmode(M_NOWRAP);
		break;
	}
	state = normal_putch;
}

/*
 * escy1_putch(c): for when an ESC Y + char has been seen
 */

int escy1;

void
escy1_putch(c)
	int c;
{
	gotoxy(c - ' ', escy1 - ' ');
	state = normal_putch;
}

/*
 * escy_putch(v, c): for when an ESC Y has been seen
 */

void
escy_putch(c)
	int c;
{
	escy1 = c;
	state = escy1_putch;
}

/*
 * normal_putch(c): put character 'c' on screen. This is the default
 * for when no escape, etc. is active
 */

void
normal_putch(c)
	int c;
{
	if (c == '\033')
		state = putesc;
	else
		m_putchar(c);
}

static inline
void
put_ch(c)
	int c;
{
	(*state)(c);
}

int
run(shell, argv)
	char *shell, **argv;
{
	int fd, oldtty;
	long pid;
	static char pty[] = "Q:\\VT52@";

/* create our handle */
	pid = 0;
	do {
		pty[7]++; pid++;
		fd = Fcreate(pty, FA_SYSTEM|FA_HIDDEN);
	} while (fd < 0 && pid < 8);

	if (fd < 0) {
		printf("couldn't create a pty\n");
		quit(2);
	}
	kidfd = fd;

/* now create the child's handle */
	fd = Fopen(pty, 2);

	oldtty = Fdup(-1);
	if (oldtty < 0) {
		Cconws("couldn't dup control terminal!\r\n");
		quit(2);
	}
	Fforce(-1, fd);			/* set up new control terminal */
	Fforce(0, fd);
	Fforce(1, fd);
	Fforce(2, fd);
	pid = spawnvp(P_NOWAIT, shell, argv); /* spawn child in background */
	Fforce(-1, oldtty);
	Fforce(0, oldtty);
	Fforce(1, oldtty);
	Fforce(2, oldtty);
	if (pid < 0) {
		Cconws("couldn't run ");
		Cconws(shell);
		Cconws("\r\n");
		quit((int)pid);
	}
	Psetpgrp((int)pid, (int)pid);	/* set the child's process group */
	Fcntl(fd, &pid, TIOCSPGRP);	/* set the terminal process group */
	Fclose(fd);

	kidpid = pid;
	return kidfd;
}

int
quit(x)
	int x;
{
	m_setnoraw();
	if (kidpid)
		Pkill((int)-kidpid, SIGHUP);
	Pterm(x);
}

#define INBUFSIZ 256

main(argc, argv)
	int argc;
	char **argv;
{
	int fd;
	long s, c;
	long reads, fdmask;
	unsigned char cbuf[INBUFSIZ], *cb;
	char *shell, *getenv();
	struct sgttyb sg;

	if (argc == 3 && !strcmp(argv[1], "-f")) {
		fd = Fopen(argv[2], 2);
		if (fd < 0) {
			perror(argv[2]);
			exit(1);
		}
		s = Pgetpgrp();
		Fcntl(fd, &s, TIOCSPGRP);
		Fcntl(fd, &sg, TIOCGETP);
		sg.sg_flags = RAW;
		Fcntl(fd, &sg, TIOCSETP);
	}
	else {
		if (argv[1]) {
			argv++;
			shell = argv[0];
		}
		else {
			shell = getenv("SHELL");
			if (!shell) shell="init.prg";
			argv[0] = shell;
			argv[1] = 0;
		}
		fd = run(shell, argv);
	}

	m_setup(0);

	m_size(80, 25);
	m_clear();
	m_setraw();
	m_setmode(M_NOBUCKEY);

	state = normal_putch;

	fdmask = 1L << fd;

	for(;;) {
		reads = 1 | fdmask;
		Fselect(0, &reads, 0L, 0L);

		if (reads & fdmask) {
			s = Finstat(fd);
			if (s > 0) {
				if (s > INBUFSIZ) s = INBUFSIZ;
				cb = cbuf;
				s = Fread(fd, s, cb);
				while (s-- > 0)
					put_ch(*cb++);
				m_flush();
			}
			else if (s < 0) {
				Cconws("Child exited??\r\n");
				quit((int)s);
			}
		}
		if (reads & 1) {
				c = Fgetchar(0, 0);
				if ( (c & 0xff) == QUITKEY )
					quit(0);
				Fputchar(fd, c, 0);
		}
	}
}
