#include "config.h"
#include "ctype.h"
#include <time.h>
#include "dirutil.h"
#include "session.h"
#include "commands.h"
#include "x.h"
#ifdef MSDOS
#include <conio.h>
#endif

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: statline.c,v 1.9 2000/05/09 16:48:28 brian Exp $";
#endif


int STATLINE = 0;
static int statlines = 2;
#define STATMODE_BBS		1
#define STATMODE_CONF		2
#define STATMODE_FTP		4
#define STATMODE_TUT		8
#define STATMODE_NNTP		16
#define STATMODE_HTTP		32
#define STATMODE_UPTIME		64
#define STATMODE_SHORT		128
#define STATMODE_MARQUEE	256
static int statmode = STATMODE_FTP
#ifdef MAILBOX
	| STATMODE_BBS
#endif
#ifdef CONVERS
	| STATMODE_CONF
#endif
#ifdef TUTOR
	| STATMODE_TUT
#endif
#ifdef BROWSER
	| STATMODE_MARQUEE
#endif
	;

#ifdef BROWSER
static int newsMarqueePosition = 0;
static char *newsMarquee = NULLCHAR;
#endif


char *NextCmdMsg;
short NextCmd;
unsigned char SCREENwidth = 80, SCREENlength = 25;
extern char statversion[], statversion_flow[];
extern int BbsUsers, FtpUsers, Tutored, NntpUsers, HttpUsers;
extern int main_exit;		/* from main program (flag) */
extern uint32 Ip_addr;
extern int Mprunning;


#ifdef HOLDMONITOR
extern int HOLDindicator;
#endif

#ifdef ALERTMONITOR
extern int ALERTindicator;
#endif


int BLOCKStatline = 0;
int INStatline = 0;
static int StatlineBeep = 1;
struct session *ScreenOwner;	/* Session currently displayed */


void statlog (const char *buf);
void displayStatLine (int offset, int phase, int onlymarquee);
void statLineToggle (int clearmarquee);
static void my_strtime (char *str);
static void getuptime (char *timebf);
extern int CountConfUsers (void);
#ifndef MSDOS
extern int socklen (int s, int rtx);
#endif



void
statlog (const char *buf)
{
	NextCmd = 0;
	free (NextCmdMsg);
	NextCmdMsg = NULLCHAR;
	if (Command && Command->screen->statline) {	/* Command status line is on */
		NextCmdMsg = strdup (buf);
		rip (NextCmdMsg);
		NextCmd = 120;
	}
#ifdef XSERVER
	xnotify (X_MSG);
#endif
}



static void
my_strtime (char *str)
{
char *cp;
time_t tm;

	(void) time (&tm);
	cp = ctime (&tm);
	strncpy (str, cp, 11);
	strncpy (&str[11], &cp[10], 6);
	str[17] = 0;
}



void
screendaemon (int i OPTIONAL, void *v1 OPTIONAL, void *v2 OPTIONAL)
{
int k;

	server_disconnect_io ();
	for (;;) {
		for (k = 0; k < 5; k++)	{
			kpause (100L);
			if (!k
#ifdef BROWSER
			    || statmode & STATMODE_MARQUEE
#endif
			    )
				displayStatLine (0, 1, (k == 0) ? 0 : 1);
		}

		for (k = 0; k < 5; k++)	{
			kpause (100L);
			if (!k
#ifdef BROWSER
			    || statmode & STATMODE_MARQUEE
#endif
			    )
				displayStatLine (0, 0, (k == 0) ? 0 : 1);
		}

#ifdef SCREENSAVER
		screensaver ();
#endif
	}
}



static void
getuptime (char *timebf)
{
char *cp;
int fill;

	cp = tformat (secclock ());
	fill = 14 - (int) strlen (cp);
	sprintf (timebf, "Up:%*.*s%s", fill, fill, " ", cp);
}



void 
displayStatLine (int offset, int phase, int onlymarquee)
{
struct session *sp;
int stop, r;
int iscmd = 0;
char timebf[20];
short beepit = 0;
static short lastbeep = 0;
int origx, origy, k;
char mybuf[256], smallbuf[16];
int do_prompt = 0;
#ifdef MSDOS
struct text_info tr;
int savedattr, attr;
struct session *tochk;
#endif


	/* if offset == 1 then we are turning it off, -1 is turning it on,
	   and 0 is leaving it the same and just updating it */
	   
	/* if we should ignore this update due to a blocking event, return */
	if (main_exit)
		return;

	/* if this is at beginning of TNOS's life (and not all init'ed), exit */
	if (Mprunning < 0)
		return;

	if (BLOCKStatline)
		return;

	/* if we have nothing to do, return */
	if (ScreenOwner && !ScreenOwner->screen->statline && offset != 1)
		return;

	/* if we do not own the screen, then return */
	if (ScreenOwner != Current)
		return;

#ifdef SCREENSAVER
	/* if the screen saver is on, return */
	if (ssenabled ())
		return;
#endif

#ifdef MSDOS
	gettextinfo(&tr);
	savedattr = tr.attribute;
	tochk = Current;
	if (Current == Command)
		tochk = Lastcurr;
#endif
	origx = wherex ();		/* get current x and y positions */
	origy = wherey ();

	/* mark if this is the Command Session's statline or not */
	if (ScreenOwner == Command)
		iscmd = 1;

	if (!iscmd && onlymarquee)
		return;

	INStatline = 1;			/* mark statline as being updated */

	window (1, 1, SCREENwidth, (iscmd) ? (statlines + 1) : 2);

#ifdef MSDOS
	attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
	textattr ((offset == 1) ? tr.attribute : attr);
	textattr ((offset == 1) ? tr.attribute : attr);
#else


#ifndef PATCURSES

	highvideo ();
#endif
#endif

	if (!onlymarquee)
		clreol ();
	if (offset != 1) {	/* if update required */
		if (onlymarquee)
			goto marqueeonly;
		sprintf (mybuf, (ScreenOwner->flowmode) ? statversion_flow : statversion, Nsessions);
		cputs (mybuf);
		stop = 10;
		if (Nsessions < (unsigned) stop)
			stop = (int) Nsessions;
		for (sp = Sessions; sp < &Sessions[stop + 1]; sp++) {
			if (sp->type == FREE || sp->type == COMMAND || sp->type == TRACESESSION) {
#ifdef MSDOS
				textattr (attr);
#endif
				cputs ("   ");
				continue;
			}
			r = socklen (sp->output, 1);
#ifdef MSDOS
			textattr ( (r) ? attr | 0x80 : attr);
#endif
			if (r && !beepit && sp != ScreenOwner)
				beepit = 1;
#ifdef MSDOS
			if (tochk == sp)
				highvideo ();
#endif
			sprintf (mybuf, "%2d%c", sp->index, (r) ? '*' : ' ');
			cputs (mybuf);
#ifdef MSDOS
			lowvideo ();
#endif
		}
		clreol ();
		k = (59 - ((stop + 1) * 3)) - (int) strlen (statversion);
		if (SCREENwidth > 80)
			k += (SCREENwidth - 80);
		for ( ; k; k--)
			cputs (" ");
#ifdef HOLDMONITOR
		if (HOLDindicator)
			cputs ("!");
		else
#endif
			cputs (" ");
#ifdef ALERTMONITOR
		if (ALERTindicator)
			cputs ("@");
		else
#endif
			cputs (" ");

		cputs ("  ");
		if (statlines == 2 && statmode & STATMODE_UPTIME)
			getuptime (timebf);
		else	{
			my_strtime (timebf);
			if (!phase)
				timebf[14] = ' ';
		}
#ifdef MSDOS
		textattr (attr);
#endif
		cputs (timebf);
		cputs (" ");
		if (iscmd) {
			clreol ();
			strcpy (mybuf, " ");
#ifdef MAILBOX
			if (statmode & STATMODE_BBS)	{
				sprintf (smallbuf, "%s=%2d ", (statmode & STATMODE_SHORT) ? "B" : "BBS", BbsUsers);
				strcat (mybuf, smallbuf);
			}
#endif
#ifdef CONVERS
			if (statmode & STATMODE_CONF)	{
				sprintf (smallbuf, "%s=%3d ", (statmode & STATMODE_SHORT) ? "C" : "CONF", CountConfUsers ());
				strcat (mybuf, smallbuf);
			}
#endif
			if (statmode & STATMODE_FTP)	{
				sprintf (smallbuf, "%s=%2d ", (statmode & STATMODE_SHORT) ? "F" : "FTP", FtpUsers);
				strcat (mybuf, smallbuf);
			}
#ifdef TUTOR
			if (statmode & STATMODE_TUT)	{
				sprintf (smallbuf, "%s=%2d ", (statmode & STATMODE_SHORT) ? "T" : "TUT", Tutored);
				strcat (mybuf, smallbuf);
			}
#endif
#ifdef NNTPS
			if (statmode & STATMODE_NNTP)	{
				sprintf (smallbuf, "%s=%2d ", (statmode & STATMODE_SHORT) ? "N" : "NNTP", NntpUsers);
				strcat (mybuf, smallbuf);
			}
#endif
#ifdef HTTP
			if (statmode & STATMODE_HTTP)	{
				sprintf (smallbuf, "%s=%2d ", (statmode & STATMODE_SHORT) ? "H" : "HTTP", HttpUsers);
				strcat (mybuf, smallbuf);
			}
#endif
			cputs (mybuf);
			k = 80 - ((int) strlen(mybuf) + 3);
			if (SCREENwidth > 80)
				k += (SCREENwidth - 80);
			if (statlines == 2)
				sprintf (mybuf, "- %-*.*s ", k, k, (NextCmd) ? NextCmdMsg : "");
			else	{
				if (statmode & STATMODE_UPTIME)
					getuptime (timebf);
				else
					sprintf (timebf, " ");
				sprintf (mybuf, "%*.*s ", k + 2, k + 2, timebf);
				cputs (mybuf);
				k = 74;
				if (SCREENwidth > 80)
					k += (SCREENwidth - 80);		
				sprintf (mybuf, "     %-*.*s ", k, k, (NextCmd) ? NextCmdMsg : "");
			}
			cputs (mybuf);
		}
		if (NextCmd)
			if (!--NextCmd) {
				free (NextCmdMsg);
				NextCmdMsg = 0;
#ifdef XSERVER
				xnotify (X_MSG);
#endif
			}
		if (!lastbeep && beepit && StatlineBeep)
			cputs ("\007");
		lastbeep = beepit;
marqueeonly:
#ifdef BROWSER
		if (iscmd && (statmode & STATMODE_MARQUEE))	{
			gotoxy (1, statlines);
			marquee_display (newsMarquee, &newsMarqueePosition);
		}
#endif
		window (1, 2 + ((iscmd) ? statlines - 1 : 0), SCREENwidth, SCREENlength - (ScreenOwner->split * 2));

		/* the last section replaces the cursor to the proper position
		   and depends on the value of 'offset'. If -1, then positioning
		   is adjusted, otherwise, it goes back to where it was. */
		if (offset == -1 && iscmd)	{
			offset = (-1 * statlines);
			if (origy < statlines)	{
				origy = statlines + 1;
				origx = 1;
				do_prompt = 1;
			}
		}
		gotoxy (origx, (int) (origy + offset));
	} else {	/* otherwise, we are turning the statline off! */
		if (iscmd) {
			for (r = statlines - 1; r; r--)	{
				cputs ("\n");
				clreol ();
			}
		}
		window (1, 1, SCREENwidth, SCREENlength - (ScreenOwner->split * 2));
		gotoxy (origx, (int) (origy + 1 + ((iscmd) ? statlines - 1 : 0)));
	}
#ifdef MSDOS
	textattr (savedattr);
#else
#ifndef PATCURSES

	normvideo ();
#endif

	rflush ();
#endif
	INStatline = 0;
	if (do_prompt)
		netPrompt();
}



int
getStatlines (void)
{
	return statlines;
}



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

	itwas = STATLINE;
	retval = setbool (&STATLINE, "Status line", argc, argv);
	StatlineBeep = ((argc > 2) && (tolower (argv[2][0]) == 'q')) ? 0 : 1;
#ifdef BROWSER
	newsMarqueePosition = 0;
#endif
	if (STATLINE && !itwas) {
		Command->screen->statline = uchar (STATLINE);
		displayStatLine (-1, 1, 0);
	}
	if (!STATLINE && itwas) {
		Command->screen->statline = uchar (STATLINE);
		displayStatLine (1, 1, 0);
	}
	return (retval);
}



/* Set status line mode */
int
dostatmode (int argc, char *argv[], void *p OPTIONAL)
{
int statwas;

	if (argc == 1)	{
		/* Display active mode items */
		tprintf ("The Command Session status line is configured with a %d line display:\n\t(using %s labels)\n",
			statlines, (statmode & STATMODE_SHORT) ? "short" : "normal");
#define prtstat(f, z)	tprintf ("%-21.21s: %s displayed\n", z, (statmode & f) ? "   " : "NOT");
		prtstat(STATMODE_UPTIME, "System Uptime");
#ifdef MAILBOX
		prtstat(STATMODE_BBS, "BBS Users");
#endif
#ifdef CONVERS
		prtstat(STATMODE_CONF, "Convers Users");
#endif
		prtstat(STATMODE_FTP, "FTP Users");
#ifdef TUTOR
		prtstat(STATMODE_TUT, "Tutor/News/Info Users");
#endif
#ifdef NNTPS
		prtstat(STATMODE_NNTP, "NNTP Users");
#endif
#ifdef HTTP
		prtstat(STATMODE_HTTP, "HTTP Users");
#endif
#ifdef BROWSER
		prtstat(STATMODE_MARQUEE, "News Marquee");
#endif
		return 0;
	}
	/* Set active statline items */
	(void) strupr (argv[1]);
	statmode = 0;

#define onestat(c,f)	if (strchr (argv[1], c))	statmode |= f
#ifdef MAILBOX
	onestat('B', STATMODE_BBS);
#endif
#ifdef CONVERS
	onestat('C', STATMODE_CONF);
#endif
	onestat('F', STATMODE_FTP);
#ifdef TUTOR
	onestat('T', STATMODE_TUT);
#endif
#ifdef NNTPS
	onestat('N', STATMODE_NNTP);
#endif
#ifdef HTTP
	onestat('H', STATMODE_HTTP);
#endif
#ifdef BROWSER
	onestat('M', STATMODE_MARQUEE);
#endif
	onestat('U', STATMODE_UPTIME);
	onestat('-', STATMODE_SHORT);
	statwas = STATLINE;
	if (statwas)
		displayStatLine (1, 1, 0);
	statlines = (strchr (argv[1], '3')) ? 3 : 2;
#ifdef BROWSER
	if (statmode & STATMODE_MARQUEE)	{
		statlines++;
		newsMarqueePosition = 0;
	}
#endif
	if (statwas)
		displayStatLine (-1, 1, 0);
	return 0;	
}



/* Status line toggle */
void
statLineToggle (int clearmarquee OPTIONAL)
{
	ScreenOwner->screen->statline ^= 1;
	if (ScreenOwner == Command)
		STATLINE = ScreenOwner->screen->statline;
	displayStatLine ((ScreenOwner->screen->statline) ? -1 : 1, 1, 0);
#ifdef BROWSER
	if (clearmarquee)
		newsMarqueePosition = 0;
#endif
}



void
marquee_display (char *str, int *position)
{
char *buf;
int len;

#if 0
	if (str == NULLCHAR || !*str)
		return;
#endif

	buf = (char *) mallocw (SCREENwidth + 1);
	if (!str || !*str || *position > (int) strlen (str))
		*position = 0;
	memset (buf, ' ', SCREENwidth);
	if (*position < SCREENwidth)	{
		if (*position)	{
			len = SCREENwidth - *position;
			sprintf (&buf[len], "%*.*s", *position,
				*position, (str) ? str : "");
		}
	} else
		sprintf (buf, "%*.*s", SCREENwidth, SCREENwidth,
			&str[*position - SCREENwidth]);		/*lint !e613 */

	buf[SCREENwidth] = 0;
	(*position)++;

	cputs (buf);
	free (buf);	
}


#ifdef BROWSER


static int StatnewsEnabled = 0;

/* Start up statusline news service */
int
statnews1 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
char *cp;
time_t now, realnow, then;
int blockstate, part;

	if (StatnewsEnabled)	{
		tprintf ("Statusline News Service already started: reloading URL\n");
		ksignal (&newsMarquee, 1);
		return 0;
	}

	StatnewsEnabled = 1;
	server_disconnect_io ();
	log (-1, "Statusline News Service: started");
	while (StatnewsEnabled)	{
		cp = obtain_statline_marquee ();
		if (cp != NULLCHAR)	{
			blockstate = BLOCKStatline;
			BLOCKStatline = 1;
			while (INStatline)
				kwait (NULL);
			free (newsMarquee);
			newsMarquee = cp;
			BLOCKStatline = blockstate;
		}
		realnow = time ((time_t *)0);
		now = (realnow % 3600);

		/* 'now' contains seconds till minute zero - BUT....
		   if all TNOS sites are hitting the server at the
		   same second, this is BOUND to back up ones on slower
		   links, so we randomize this a bit, by adding the
		   last actet of the IP address (mod 60) to the count */

		part = (int) (Ip_addr & 0x00ff);
		now -= (part % 60);
		then = (3600 - now);
		kalarm ((long)then * 1000L);
		kwait (&newsMarquee);
		kalarm (0);
	}

	log (-1, "Statusline News Service: stopped");
	return 0;
}



/* Stop statusline news service */
int
statnews0 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	StatnewsEnabled = 0;
	ksignal (&newsMarquee, 1);
	return 0;
}

#endif
