/* New routines added by TNOS/KO4KS version of NOS */

#include "vmsmgr.hpp"
#include <conio.h>
#include <ctype.h>
#include <dos.h>
#include <time.h>
#include "config.h"

vmsmgr *VMSscreens;
#define ASCII_TYPE 0
#define	READ_TEXT	"rt"
int myVMSinited = 0;
int STATLINE = 0;
char *NextCmdMsg;
short NextCmd;
static unsigned char orgMode;
unsigned char SCREENwidth = 80, SCREENlength = 25;
char vgaDesired = 0;
extern char statversion[];
extern int BbsUsers, FtpUsers, Tutored;
extern int main_exit;			/* from main program (flag) */
int myVMSsortinited = 0;
vmsmgr *VMSsort;

extern "C" 	{
int pwait (volatile void *event);
void log(int s,char *fmt, ...);
int tprintf (char *fmt, ...);
int socklen (int s,int rtx);
int setbool (int *var,char *label,int argc,char *argv[]);
int CountConfUsers (void);
void rip (char *);

// from dirutil.h
struct cur_dirs {
           int drv;
           char * curdir[27];
           char * dir;                
} ;


// from session.h
struct screen {
	char *save;		/* Screen save buffer */
	int row;		/* Saved cursor location */
	int col;
	unsigned char attr;
	unsigned char statline;
};

struct ttystate {
	struct mbuf *line;	/* Line buffer */
	int echo;		/* Keyboard local echoing? */
	int edit;		/* Local editing? */
	int crnl;		/* Translate cr to lf? */
};

/* Session control structure; only one entry is used at a time */
struct session {
	int type;
#define	FREE	0
#define	TELNET	1
#define	FTP	2
#define	AX25TNC	3
#define	FINGER	4
#define	PING	5
#define NRSESSION 6
#define	COMMAND	7
#define	MORE	8
#define	HOP	9
#define	TIP	10
#define	PPPPASS	11
#define DIAL	12
#define DQUERY	13
#define DCLIST	14
#define	RLOGIN	15
#define TRACESESSION 16

	char *name;	/* Name of remote host */
	union {
		struct ftpcli *ftp;
		struct telnet *telnet;
	} cb;
	struct proc *proc;	/* Primary session process (e.g., tn recv) */
	struct proc *proc1;	/* Secondary session process (e.g., tn xmit) */
	struct proc *proc2;	/* Tertiary session process (e.g., upload) */
	int s;			/* Primary network socket (control for FTP) */
	FILE *record;		/* Receive record file */
	char *rfile;		/* Record file name */
	FILE *upload;		/* Send file */
	char *ufile;		/* Upload file name */
	struct ttystate ttystate;
	struct screen *screen;
	int input;		/* Input socket */
	int output;		/* Output socket */
	int flowmode;		/* control "more" mode */
	int row;		/* Rows remaining until "more" */
	int morewait;		/* Output driver is waiting on us */
	int tsavex;		/* Save for x top screen */
	int tsavey;		/* Save for y top screen */
	int bsavex;		/* Save for x bottom screen */
	int bsavey;		/* Save for y bottom screen */
	int split;		/* Signal for split screen */
	struct cur_dirs *curdirs; 
	int index;		/* session # (0 - (Nsessions - 1)) */
};
#define	NULLSESSION	(struct session *)0
extern unsigned Nsessions;		/* Maximum number of sessions */
extern struct session *Sessions;	/* Session descriptors themselves */
extern struct session *Current;
extern struct session *Command;
extern struct session *Lastcurr;	/* Last non-command session */
extern struct session *Trace;
struct session *ScreenOwner;		/* Session currently displayed */
}


void realvmsstat ()
{
unsigned long lng;

	lng = VMSscreens->size();
	lng *= VMSscreens->elements();
	tprintf ("VMS mode - %s, %-lu bytes in use for screens ",
		VMSscreens->inmemory() ? "Extended Memory" :
		"Temporary Disk File", lng);
	lng = VMSscreens->elements();
	tprintf ("(%-lu/%-lu)\n", VMSscreens->size(), lng);
}

void realVMSinit ()
{
struct text_info tr;
size_t scrsize;

	gettextinfo(&tr);
	orgMode = tr.currmode;
	if (vgaDesired)		{
		textmode (C4350);
		gettextinfo(&tr);
		}
	SCREENwidth = tr.screenwidth;
	SCREENlength = tr.screenheight;
	window (1,1,SCREENwidth,SCREENlength);
	scrsize = 2*tr.screenheight*tr.screenwidth;
	if (myVMSinited == 0)	{
		VMSscreens = new vmsmgr(scrsize, Nsessions);
		myVMSinited = 1;
		}
}

void realVMSterm ()
{
	delete VMSscreens;
	textmode (orgMode);
}


void realstowit (size_t index, int save, unsigned char attr)
{
char far *nerf;
register int k, l, split;
register char *cp;

	nerf = (char far*) farmalloc(VMSscreens->size());
	if (save)	{
		gettext(1,1,SCREENwidth,SCREENlength,nerf);
		VMSscreens->stow (nerf, index);
		}
	else	{
		VMSscreens->fetch (nerf, index);
		if (attr & 0x80)	{
			attr &= 0x7f;
			l = (VMSscreens->size() / 2);
			split = Sessions[index].split;
			if (split)
				l -= 160;	// last 2 lines reversed
			cp = (nerf + 1);
			for (k = 0; k < l; k++)	{
				*cp &= 8;	// keep high video bit
				*cp |= attr;
				cp += 2;
				}
			attr = ((attr & 0x0f) << 4) + ((attr & 0x70) >> 4);
			if (split)
				for (k = 0; k < 160; k++)	{
					*cp &= 8;	// keep high video bit
					*cp |= attr;
					cp += 2;
				}
			}
		puttext (1,1,SCREENwidth,SCREENlength,nerf);
		}
	farfree (nerf);
}


extern "C"	{
long sendfile(FILE *fp,int s,int mode,int hash);
int chksession (struct session *sp);
int ssenabled (void);

int DisplayFile (char *fname,int socket)
{
FILE *fp;
int size = 0;
char buf[100];

	if(fp = fopen(fname,READ_TEXT)) {
		sendfile(fp,socket,ASCII_TYPE,0);
		size = ftell (fp);
		fclose(fp);
		}
	return (size);
}

void stowit (size_t index, int save, unsigned char attr)
{
	realstowit (index, save, attr);
}

void VMSinit ()
{
int i;
	realVMSinit ();
//	_OvrInitExt (0, 0);
}

void VMSterm ()
{
	realVMSterm ();
}

void vmsstat ()
{
	realvmsstat ();
}

int VMSsortInit (unsigned long size, unsigned long number)
{
	while (myVMSsortinited)
		pwait(NULL);
	myVMSsortinited = 1;
	VMSsort = new vmsmgr(size, number);
	return VMSsort->is_installed();
}

void VMSsortTerm (void)
{
	delete VMSsort;
	myVMSsortinited = 0;
}

void VMSsortFetch (char far *databuf, size_t index)
{
	VMSsort->fetch (databuf, index);
}

void VMSsortStow (char far *databuf, size_t index)
{
	VMSsort->stow (databuf, index);
}



int SYSback = 40, SYSfore = 37;
static char nope[] = "Color '%s' unknown!\nAvailable colors: black, red, green, cyan, blue, magenta, and white\n";
//static char setem[] = "\x1b[%-2d;%-2dm";
static int backs[8] = {0, 4, 2, 0, 1, 5, 3, 7};
static int fores[8] = {0, 4, 2, 0, 1, 5, 3, 7};

void
setscreens (int back, int fore, int clr)
{
char theback;

	if (!back && !fore)	{	// if both black, use system colors
		back = SYSback;
		fore = SYSfore;
		back = backs[back - 40];
		fore = fores[fore - 30];
		}
	textbackground (back);
	textcolor (fore);
//	tprintf (setem, back, fore);
	theback = back;
	asm	{
		mov ah,0bh		// set background border
		mov bh,00h
		mov bl,theback
		int 10h			// call driver
		}
	if (clr)
		clrscr ();
}


int
getcolor (char *str)
{
char *ptr;
	for (ptr = str; *ptr; ptr++)
		*ptr = tolower (*ptr);
	switch (*str)	{
		case 'r':	return 31;
		case 'g':	return 32;
		case 'm':	return 35;
		case 'c':	return 36;
		case 'w':	return 37;
		case 'b':	if (str[1] != 'l')
					return 0;
				switch (str[2])	{
					case 'a':	return 30;
					case 'u':	return 34;
				}
		default:	return 0;
		}
}

/* Set terminal colors */
int
docolor (int argc, char *argv[], void *p)
{
int temp;
int back, fore;
struct session *sp;

	temp = getcolor (argv[1]);
	if (!temp)
		tprintf (nope, argv[1]);
	else	{
		back = temp + 10;
		temp = getcolor (argv[2]);
		if (!temp)
			tprintf (nope, argv[2]);
		else	{
			fore = temp;
			if (argc > 3)	{
				temp = atoi(argv[3]);
				if (temp)	{
					sp = &Sessions[temp];
					if (chksession (sp))
						sp->screen->attr = (((backs[back - 40] << 4) + (fores[fore - 30])) | 0x80);
				}
			} else	{
				SYSback = back;
				SYSfore = fore;
				setscreens (0, 0, 1);
			}
		}
	}
	return 0;
}

void
statlog (char *buf)
{
	NextCmd = 0;
	free (NextCmdMsg);
	if (Command && Command->screen->statline)		{ // Command status line is on
		NextCmdMsg = strdup (buf);
		rip (NextCmdMsg);
		NextCmd = 120;
	}
}


void displayStatLine (int offset, int phase)
{
struct session *sp, *tochk;
int stop, r;
struct text_info tr;
unsigned char attr, iscmd = 0;
char timebf[9];
short beepit = 0;
static short lastbeep = 0;

	if (main_exit)
		return;
	if (!ScreenOwner->screen->statline && offset != 1)
		return;
	if (vgaDesired)
		return;
#ifdef SCREENSAVER
	if (ssenabled ())
		return;
#endif
//	sound (440);
	gettextinfo(&tr);
	if (ScreenOwner == Command)
		iscmd = 1;
	window (1,1,SCREENwidth,(iscmd) ? 2 : 1);
	tochk = Current;
	if ((Current == Trace) || (Current == Command))
		tochk = Lastcurr;
	attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
	textattr ((offset == 1) ? tr.attribute : attr);
	if (offset)
		clrscr ();
	if (offset != 1)		{
		cprintf (statversion, Nsessions);
		stop = 20;
		if (Nsessions < stop)
			stop = Nsessions;
		for(sp=Sessions; sp < &Sessions[stop];sp++)	{
		        if(sp->type == FREE || sp->type == COMMAND || sp->type == TRACESESSION)	{
				cprintf ("   ");
				continue;
				}
			r = socklen(sp->output,1);
			textattr ( (r) ? attr | 0x80 : attr);
			if (r && !beepit)
				beepit = 1;
			if (tochk == sp)
				highvideo ();
			cprintf ("%2d ", sp->index);
			lowvideo ();
			}
		clreol ();
		gotoxy (75, 1);
		_strtime (timebf);
		timebf[5] = 0;		// clip off the seconds
		if (!phase)
			timebf[2] = ' ';
		textattr (attr);
		cprintf (timebf);
		if (iscmd)	{
//			gotoxy (2, 1);
#ifdef CONVERS
			cprintf ("\r\n BBS=%2d CONF=%2d FTP=%2d TUT=%2d  ", BbsUsers, CountConfUsers(), FtpUsers, Tutored);
#else
			cprintf ("\r\n BBS=%2d FTP=%2d TUT=%2d           ", BbsUsers, FtpUsers, Tutored);
#endif
			clreol ();
			if (NextCmd)
				cprintf ("- %-45.45s", NextCmdMsg);
		}
		if (NextCmd)
			if (!--NextCmd)	{
				free (NextCmdMsg);
				NextCmdMsg = 0;
			}
		if (!lastbeep && beepit)
			cprintf ("\007");
		lastbeep = beepit;
// 		window (1,2,SCREENwidth,SCREENlength);
// 		window (1,2 + iscmd,SCREENwidth,SCREENlength - (ScreenOwner->split * 2) - iscmd - 1);
 		window (1,2 + iscmd,SCREENwidth,SCREENlength - (ScreenOwner->split * 2));
		gotoxy (tr.curx, tr.cury + offset + (offset * iscmd));
		}
	else	{
//		window(1,1,SCREENwidth,SCREENlength);
		window(1,1,SCREENwidth,SCREENlength - (ScreenOwner->split * 2));
		gotoxy (tr.curx, tr.cury + 1 + iscmd);
	}
	textattr (tr.attribute);
//	nosound ();
}

/* Set status line on/off */
int
dostatline (int argc, char *argv[], void *p)
{
int retval, itwas;

    if (vgaDesired)	{
	tprintf ("Status Line not yet functional in EGA/VGA mode, sorry!\n");
	return 0;
	}
    itwas = STATLINE; 
    retval = setbool(&STATLINE,"Status line",argc,argv);
    if (STATLINE && !itwas)	{
 	Command->screen->statline = STATLINE;
	displayStatLine (-1, 1);
	}
    if (!STATLINE && itwas)	{
 	Command->screen->statline = STATLINE;
	displayStatLine (1, 1);
	}
    return (retval);
}

/* Status line toggle */
void
statLineToggle ()
{
    if (vgaDesired)
	return;
    ScreenOwner->screen->statline ^= 1;
    if (ScreenOwner == Command)
	STATLINE = ScreenOwner->screen->statline;
    displayStatLine ((ScreenOwner->screen->statline) ? -1 : 1, 1);
}


}	// end of extern "C" stuff

