/* -------------------------------------------------------------------- */
/*	WINDOVL.CPP 					Citadel 							*/
/*			Machine dependent windowing routines for Citadel			*/
/* -------------------------------------------------------------------- */
#ifndef WINCIT
#include "ctdl.h"
#pragma hdrstop

#include "cwindows.h"
#include "scrlback.h"

/* -------------------------------------------------------------------- */
/*								Contents								*/
/* -------------------------------------------------------------------- */
/*	cls()					clears the screen							*/
/*	help()					toggles help menu							*/
/*	setscreen() 			sets videotype flag 						*/
/*	setscreen() 			Set SCREEN to correct address for VIDEO 	*/
/*	save_screen()			allocates a buffer and saves the screen 	*/
/*	setborder() 			wow.										*/
/* -------------------------------------------------------------------- */

extern ConsoleLockC ConsoleLock;

/* -------------------------------------------------------------------- */
/*	setborder() 			wow.										*/
/* -------------------------------------------------------------------- */
void setborder(int battr)
	{
	union REGS REG;

	if (battr != 0xff)
		{
		REG.h.ah = 11;
		REG.x.bx = ScreenSaver.IsOn() ? 0 : battr;
		int86(0x10, &REG, &REG);					/* border clr */
		}
	}


/* -------------------------------------------------------------------- */
/*	cls()				clears the screen								*/
/* -------------------------------------------------------------------- */
void cls(int whatToDo)
	{
	if (whatToDo == SCROLL_SAVE && cfg.scrollSize)
		{
		int row, col;
		readpos(&row, &col);

		SaveToScrollBackBuffer(row);
		}

	if (cfg.bios && !ScreenSaver.IsOn() && !StatusLine.IsFullScreen() &&
			!allWindows)
		{
		scroll_bios(conRows, 0, cfg.attr);
		}
	else
		{
		cls_fast(ScreenSaver.IsOn() ? 0 : cfg.attr);
		}

	setborder(cfg.battr);
	position(0, 0);

	if (allWindows && !oPhys)
		{
		RedrawAll();
		}
	}

/* -------------------------------------------------------------------- */
/*	help()				this toggles our help menu						*/
/* -------------------------------------------------------------------- */
void StatusLineC::ToggleHelp(void)
	{
	int row, col;

	if (!Visible)
		{
		Toggle();
		}
	else
		{
		readpos(&row, &col);

		// small window?
		if (!HelpTimeout)
			{
			// Make big window...

			time(&HelpTimeout);

			scrollpos = conRows - Height();

			if (row > scrollpos)
				{
				scroll(row, row - scrollpos, cfg.attr);
				row = scrollpos;
				}
			}
		else
			{
			// Make small window...

			HelpTimeout = 0;

			if (State == SL_TWOLINES)
				{
				clearline(conRows - 5, cfg.attr);
				}

			clearline(conRows - 4, cfg.attr);
			clearline(conRows - 3, cfg.attr);
			clearline(conRows - 2, cfg.attr);
			clearline(conRows - 1, cfg.attr);

			scrollpos = conRows - Height();
			}

		position(row, col);
		updateStatus = TRUE;
		}
	}


/* -------------------------------------------------------------------- */
/*	sftf10(void)		Blank stat lines.								*/
/* -------------------------------------------------------------------- */
void StatusLineC::Toggle(void)
	{
	int row, col;
	int i;

	readpos(&row, &col);

	if (Visible)
		{
		Visible = FALSE;

		for (i = scrollpos + 1; i <= conRows; i++)
			{
			clearline(i, cfg.attr);
			}

		scrollpos = conRows;
		}
	else
		{
		Visible = TRUE;

		scrollpos = conRows - Height();

		if (row > scrollpos)
			{
			scroll(row, row - scrollpos, cfg.attr);
			row = scrollpos;
			}
		}

	position(row, col);
	updateStatus = TRUE;
	}


/* -------------------------------------------------------------------- */
/*	altF10(void)		Extra stat line.								*/
/* -------------------------------------------------------------------- */
void StatusLineC::ToggleSecond(void)
	{
	// No second line when in full-screen mode
	if (State == SL_FULLSCREEN)
		{
		return;
		}

	// If nothing is visible... make it so.
	if (!Visible)
		{
		Toggle();
		}
	else
		{
		int row, col;
		readpos(&row, &col);

		if (State == SL_ONELINE)
			{
			// Make it two...

			State = SL_TWOLINES;

			scrollpos = conRows - Height();

			if (row > scrollpos)
				{
				scroll(row, row - scrollpos, cfg.attr);
				row = scrollpos;
				}
			}
		else
			{
			// Make it one...

			State = SL_ONELINE;

			scrollpos = conRows - Height();

			clearline(scrollpos, cfg.attr);
			}

		position(row, col);
		updateStatus = TRUE;
		}
	}

/* -------------------------------------------------------------------- */
/*	save_screen()		allocates a buffer and saves the screen 		*/
/* -------------------------------------------------------------------- */
Bool save_screen(void)
	{
	if (TI()saveBuffer == NULL)
		{
		compactMemory();

		TI()saveBuffer = new char[(conRows + 1) * conCols * 2];

		if (TI()saveBuffer == NULL)
			{
			mPrintfCR(getmsg(135));
			return (FALSE);
			}
		else
			{
			memcpy(TI()saveBuffer, TI()logiScreen,
					((scrollpos + 1) * conCols * 2));

			if (scrollpos != conRows)
				{
				memset(TI()saveBuffer + ((scrollpos + 1) * conCols * 2), 0,
						(conRows - scrollpos) * conCols * 2);
				}

			s_conRows = conRows;
			return (TRUE);
			}
		}
	else
		{
		return (FALSE);
		}
	}


/* -------------------------------------------------------------------- */
/*	restore_screen()	restores screen and frees buffer				*/
/* -------------------------------------------------------------------- */
void restore_screen(void)
	{
	int j, i;

	if (ScreenSaver.IsOn() || allWindows)
		{
		return;
		}

	/* just to be sure, here */
	if (TI()logiScreen == TI()saveBuffer)
		{
		TI()logiScreen = physScreen;
		dgLogiScreen = TI()logiScreen;
		}

	if (TI()saveBuffer != NULL)
		{
		if (s_conRows <= conRows)
			{
			readpos(&i, &j);
			cls(SCROLL_NOSAVE);
			position(i, j);
			memcpy(physScreen, TI()saveBuffer, (s_conRows+1) * conCols * 2);
			}
		else
			{
			if (cfg.scrollSize)
				{
				char *SaveIt = TI()logiScreen;
				TI()logiScreen = TI()saveBuffer;

				SaveToScrollBackBuffer(s_conRows - conRows);

				TI()logiScreen = SaveIt;
				}

			memcpy(physScreen,
					TI()saveBuffer + (s_conRows - conRows) * conCols * 2,
					(conRows+1) * conCols * 2);
			}

		delete [] TI()saveBuffer;
		TI()saveBuffer = NULL;
		}
	}

/* -------------------------------------------------------------------- */
/*	setscreen() 		set video mode flag 0 mono 1 cga				*/
/* -------------------------------------------------------------------- */
void setscreen(void)
	{
	int mode;
	union REGS REG;
	static uchar heightmode = 0;
	static uchar scanlines = 0;
	char mono = 0;
	char far *CrtHite = (char far *) 0x00400085L;

	if (!cfg.restore_mode)
		{
		heightmode = 0;
		scanlines = 0;
		}

	if (gmode() == 7)
		{
		mono = TRUE;
		}

	if (!heightmode)
		{
		if (*CrtHite == 8)
			{
			heightmode = 0x012;
			}
		else if (*CrtHite == 14)
			{
			heightmode = 0x011;
			}
		else if (*CrtHite == 16)
			{
			heightmode = 0x014;
			}
		}

	if (scanlines)
		{
		REG.h.ah = 0x12;			// Video function:
		REG.h.bl = 0x30;			// Set scan lines
		REG.h.al = scanlines;		// Num scan lines
		int86(0x10, &REG, &REG);
		}

	if (heightmode && conMode != -1)	// make sure heightmode is set
		{
		/* conMode 1000 --> EGA 43 line, or VGA 50 line */

		REG.h.ah = 0x00;
		REG.h.al = (uchar) ((conMode >= 1000) ? 3 : conMode);
		int86(0x10, &REG, &REG);

		/* Set to character set 18, (EGA 43 line, or VGA 50 line) */
		if (conMode == 1000)
			{
			REG.h.ah = 0x11;
			REG.h.al = 18;
			REG.h.bl = 0x00;
			int86(0x10, &REG, &REG);
			}
		else
			{
			REG.h.ah = 0x11;
			REG.h.al = heightmode;
			REG.h.bl = 0x00;
			int86(0x10, &REG, &REG);
			}
		}

	if (!scanlines)
		{
		getScreenSize((&conCols), (&conRows));

		if (!mono)
			{
			if (conRows == 24)
				{
				if (*CrtHite == 14) scanlines = 1;	// Old char set
				if (*CrtHite == 16) scanlines = 2;	// Vga char set
				}

			if (conRows == 42) scanlines = 1;
			if (conRows == 49) scanlines = 2;
			}
		else
			{
			if (conRows == 24) scanlines = 1;
			if (conRows == 27) scanlines = 2;		// herc only
			if (conRows == 42) scanlines = 1;
			}
		}

	mode = gmode();
	conMode = (mode == 3 && conMode >= 1000) ? conMode : mode;

	if (mode == 7)
		{
		physScreen = (char far *) 0xB0000000L;		// mono
		TI()logiScreen = TI()saveBuffer ? TI()saveBuffer : physScreen;
		}
	else
		{
		physScreen = (char far *) 0xB8000000L;		// cga
		TI()logiScreen = TI()saveBuffer ? TI()saveBuffer : physScreen;
		setborder(cfg.battr);
		}
	dgLogiScreen = TI()logiScreen;

	getScreenSize((&conCols), (&conRows));

	scrollpos = conRows - StatusLine.Height();

	if (cfg.bios)
		{
		charattr = bioschar;
		stringattr = biosstring;
		}
	else
		{
		charattr = directchar;
		stringattr = directstring;
		}

	TI()OC.ansiattr = cfg.attr;
	}

void getScreenSize(uchar *Cols, uchar *Rows)
	{
	*Cols = *(uchar far *) (0x0000044A);
	*Rows = *(uchar far *) (0x00000484);

	/*
	 * sanity checks, some cards don't set these locations.
	 * (Heather's CGA for example. =] )
	 */
	if (*Cols < 40) *Cols = 80;
	if (*Rows < 15) *Rows = 24;

	/*
	 * now an overide for stupid CGA's (like Krissy's) who
	 * insist on writing to this location..
	 */
	if (conMode == 1001)
		{
		*Cols = 80;
		*Rows = 24;
		}
	}

/* -------------------------------------------------------------------- */
/*	ClearToEndOfLine()	delete to end of line							*/
/* -------------------------------------------------------------------- */
void ClearToEndOfLine(void)
	{
	int row, col;
	int i;

	readpos(&row, &col);

	for (i=col; i < conCols; i++)
		{
		putch(' ');
		}

	position(row, col);
	}

Bool ScreenSaverC::TurnOn(void)
	{
	if (!On && save_screen())
		{
		int row, col;
		readpos(&row , &col);

		int wow = cfg.attr;
		int wow2 = cfg.battr;

		cfg.attr = 0;
		cfg.battr = 0;

		cls(SCROLL_NOSAVE);

		cfg.attr = wow;
		cfg.battr = wow2;

		position(row, col);

		On = TRUE;

		TI()logiScreen = TI()saveBuffer;
		dgLogiScreen = TI()logiScreen;

		if (!cfg.really_really_fucking_stupid)
			{
			cursoff();
			}

		if (cfg.LockOnBlank && *cfg.f6pass)
			{
			ConsoleLock.Lock();
			}
		}

	return (On);
	}

void ScreenSaverC::TurnOff(void)
	{
	if (On)
		{
		On = FALSE;

		TI()logiScreen = physScreen;
		dgLogiScreen = TI()logiScreen;

		restore_screen();
		curson();
		StatusLine.Update();
		}
	}

void outPhys(Bool phys)
	{
	static char *save;

	if (phys)
		{
		save = TI()logiScreen;
		TI()logiScreen = physScreen;
		dgLogiScreen = TI()logiScreen;
		oPhys = TRUE;
		}
	else
		{
		if (save)
			{
			TI()logiScreen = save;
			dgLogiScreen = TI()logiScreen;
			oPhys = FALSE;
			}
		}
	}

Bool StatusLineC::ToggleFullScreen(void)
	{
	if (!ScreenSaver.IsOn())
		{
		if (State == SL_FULLSCREEN)
			{
			State = SL_ONELINE;

			TI()logiScreen = physScreen;
			dgLogiScreen = TI()logiScreen;

			restore_screen();

			curson();

			return (TRUE);
			}
		else
			{
			if (!Visible)
				{
				Toggle();
				}

			if (State == SL_TWOLINES)
				{
				ToggleSecond();
				}

			State = SL_FULLSCREEN;
			updateStatus = TRUE;

			int oldrow, oldcol;

			if (save_screen())
				{
				TI()logiScreen = TI()saveBuffer;
				dgLogiScreen = TI()logiScreen;

				readpos(&oldrow, &oldcol);

				if (!cfg.really_really_fucking_stupid)
					{
					cursoff();
					}

				outPhys(TRUE);
				cls(SCROLL_NOSAVE);
				outPhys(FALSE);

				position(oldrow, oldcol);

				return (TRUE);
				}
			else
				{
				State = SL_ONELINE;
				}
			}

		}

	return (FALSE);
	}
#endif
