// --------------------------------------------------------------------------
// Citadel: Input.CPP
//
// User input routines

#include "ctdl.h"
#pragma hdrstop

#define INPUTMAIN
#include "infilt.h"
#include "log.h"
#include "account.h"
#include "miscovl.h"
#include "term.h"


// --------------------------------------------------------------------------
// Contents
//
// BBSCharReady()	Returns if char is available from modem or console
// setio()			Set output flags according to OutFlag, Echo, and whichIO
// iCharNE()		As below, but don't echo
// iChar()			Get a character from user. This also checks timeout,
//					carrier detect, and a host of other things


// --------------------------------------------------------------------------
// BBSCharReady(): Returns if char is available from modem or console.

int BBSCharReady(void)
	{
	return ((SerialPort.HaveCarrier() && !onConsole && TI()SerialPort.IsInputReady()) || KBReady());
	}


// --------------------------------------------------------------------------
// setio(): Set output flags according to OutFlag, Echo, and whichIO

void setio()
	{
	if (!(TI()UserControl.GetOutFlag() == OUTOK ||
			TI()UserControl.GetOutFlag() == IMPERVIOUS ||
			TI()UserControl.GetOutFlag() == NOSTOP))
		{
		TI()OC.Modem = FALSE;
		TI()OC.Console = FALSE;
		}
	else if (TI()OC.Echo == BOTH)
		{
		TI()OC.Modem = TRUE;
		TI()OC.Console = TRUE;
		}
	else if (TI()OC.Echo == CALLER)
		{
		if (TI()whichIO == MODEM)
			{
			TI()OC.Modem = TRUE;
			TI()OC.Console = FALSE;
			}
		else if (onConsole)
			{
			TI()OC.Modem = FALSE;
			TI()OC.Console = TRUE;
			}
		}
	else if (TI()OC.Echo == NEITHER)
		{
		TI()OC.Modem = FALSE;
		TI()OC.Console = FALSE;
		}

	if (!SerialPort.HaveCarrier() || !TI()modStat)
		{
		TI()OC.Modem = FALSE;
		}
	}


// --------------------------------------------------------------------------
// iCharNE(): iChar() without echo.

int iCharNE(void)
	{
	char c;
	EchoType oldEcho;

	oldEcho = TI()OC.Echo;
	TI()OC.Echo = NEITHER;
	setio();

	c = (char) iChar();

	TI()OC.Echo = oldEcho;
	setio();

	return (c);
	}


// --------------------------------------------------------------------------
// iChar(): Get a character from user. This also checks timeout, carrier
//		detect, and a host of other things.

int iChar(void)
	{
	uchar c = 0;
	time_t ad_timer;

	EchoType oldEcho = TI()OC.Echo;
	TI()OC.Echo = BOTH;
	setio();

	sysopkey = FALSE;	// F6 to go into sysop mode
	eventkey = FALSE;	// Alt+E, +R, or +F for an event
	forceevent = FALSE; // Alt+F or +R

	ad_timer = time(&TI()LastActiveTime);

	TwirlyCursor.Start();

	for (;;)
		{
		CitIsIdle();

		TwirlyCursor.Update();

		// Exit to MS-DOS key hit or carrier lost state or carrier gained at
		// the room prompt
		if (
				TI()ExitToMsdos ||
				!HaveConnectionToUser() ||

				(
				TI()DoWhat == MAINMENU &&
				!TI()loggedIn &&
				!TI()modStat &&
				carrier()
				)
			)
			{
			TwirlyCursor.Stop();
			DebugOut(getdbmsg(89));
			break;
			}

		// Keyboard press
		if (KBReady())
			{
			TwirlyCursor.Stop();
			c = (char) ciChar();

			time(&TI()LastActiveTime);
			break;
			}

		// Get character from modem
		if (TI()SerialPort.IsInputReady() && SerialPort.HaveCarrier() && TI()modStat)
			{
			c = (char) TI()SerialPort.Input();

			if (!onConsole)
				{
				TwirlyCursor.Stop();
				break;
				}
			}

		// Request for sysop menu at main
		if ((sysopkey || TI()chatkey) && TI()DoWhat == MAINMENU)
			{
			TwirlyCursor.Stop();
			DebugOut(getdbmsg(90));
			break;
			}

		// Event key
		if (eventkey && (TI()DoWhat == MAINMENU))
			{
			TwirlyCursor.Stop();
			DebugOut(getdbmsg(91));
			break;
			}

		// Sysop initiated chat
		if (TI()chatkey && TI()DoWhat == PROMPT)
			{
			EchoType oldEcho;

			TwirlyCursor.Stop();

			oldEcho = TI()OC.Echo;
			TI()OC.Echo = BOTH;
			setio();

			doCR();
			chat();
			CRmPrintf(pcts, TI()gprompt);

			TwirlyCursor.Start();

			TI()OC.Echo = oldEcho;
			setio();

			time(&TI()LastActiveTime);

			TI()chatkey = FALSE;
			}

		// Keypress timeout
		if (CheckIdleUserTimeout(FALSE) &&
				(TI()loggedIn || TI()modStat || TI()DoWhat != MAINMENU))
			{
			TI()sleepkey = FALSE;
			time(&TI()LastActiveTime);

			TwirlyCursor.Stop();

			UserHasTimedOut();
			}
		else
			{
			TI()sleepkey = FALSE;
			}

		// Cron timeout
		if (Cron.IsReady() && TI()DoWhat == MAINMENU &&
				!TI()modStat && !TI()loggedIn)
			{
			TwirlyCursor.Stop();
			DebugOut(getdbmsg(92));
			break;
			}

		// else check for ads
		if (cfg.ad_time && TI()loggedIn && TI()DoWhat == MAINMENU &&
				TI()CurrentUser->IsViewBorders() &&
				((int) (time(NULL) - ad_timer) >= cfg.ad_time))
			{
			time(&ad_timer);

			TwirlyCursor.Stop();

			doAd(TRUE);

			GiveRoomPrompt();

			TwirlyCursor.Start();
			}
		}

	if (c < 128)
		{
		c = filt_in[c];
		}
	else if (c == 255)
		{
		c = 0;
		}

	TI()OC.Echo = oldEcho;
	setio();

	if (c != CTRL_A) // don't print ^As
		{
		echocharacter(c);
		}

	return (c);
	}


Bool IsKeyFromUserReady(void)
	{
	// Either a key has been hit on console or there is modem input and
	// someone is on-line
	return (KBReady() || (!onConsole && TI()SerialPort.IsInputReady() && SerialPort.HaveCarrier() &&
			TI()modStat));
	}
