/*
**	$Id: termXEM.c,v 1.7 92/08/15 20:15:28 olsen Sta Locker: olsen $
**	$Revision: 1.7 $
**	$Date: 92/08/15 20:15:28 $
**
**	External emulation support routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* xem_swrite():
	 *
	 *	Send a few bytes across the serial line.
	 */

STATIC LONG __saveds __asm
xem_swrite(register __a0 UBYTE *Buffer,register __d0 LONG Size)
{
	if(WriteRequest)
	{
		SerWrite(Buffer,Size);

		return(0);
	}
	else
		return(-1);
}

	/* xem_sbreak():
	 *
	 *	Send a break signal across the serial line.
	 */

STATIC BOOL __saveds
xem_sbreak()
{
	if(!WriteRequest)
		return(-1);
	else
	{
		WriteRequest -> IOSer . io_Command = SDCMD_BREAK;

		return((LONG)DoIO(WriteRequest));
	}
}

	/* xem_sstart():
	 *
	 *	Restart serial read activity.
	 */

STATIC VOID __saveds
xem_sstart()
{
	if(ReadRequest)
	{
		ReadRequest -> IOSer . io_Command	= CMD_READ;
		ReadRequest -> IOSer . io_Data		= ReadBuffer;
		ReadRequest -> IOSer . io_Length	= 1;

		SetSignal(0,SIG_SERIAL);

		SendIO(ReadRequest);
	}
}

	/* xem_sstop():
	 *
	 *	Stop serial read activity.
	 */

STATIC VOID __saveds
xem_sstop()
{
	if(ReadRequest)
	{
		if(!CheckIO(ReadRequest))
			AbortIO(ReadRequest);

		WaitIO(ReadRequest);
	}
}

	/* xem_tgets(UBYTE *Prompt,UBYTE *Buffer,ULONG Size):
	 *
	 *	Get a string from the user.
	 */

STATIC BOOL __saveds __asm
xem_tgets(register __a0 UBYTE *Prompt,register __a1 UBYTE *Buffer,register __d0 ULONG Size)
{
	return((BOOL)xpr_gets(Prompt,Buffer));
}

	/* xem_tbeep(ULONG Times,ULONG Delay):
	 *
	 *	Beep the terminal display.
	 */

STATIC VOID __saveds __asm
xem_tbeep(register __d0 ULONG Times,register __d1 ULONG Delay)
{
	WORD i;

	for(i = 0 ; i < Times ; i++)
	{
			/* Handle the visual part. */

		if(Config . VisibleBell)
		{
			if(StatusProcess)
				Signal(StatusProcess,SIGBREAKF_CTRL_D);
		}

			/* Let it beep. */

		if(Config . AudibleBell)
			Beep();
	}
}

	/* xem_macrodispatch(struct XEmulatorMacroKey *XEM_MacroKey):
	 *
	 *	Dispatch a macro key call.
	 */

STATIC VOID __saveds __asm
xem_macrodispatch(register __a0 struct XEmulatorMacroKey *XEM_MacroKey)
{
	VOID (*Routine)(VOID);

		/* If a routine to call is available (most likely xON or xOFF),
		 * make a call to it, else process the macro key data.
		 */

	if(Routine = XEM_MacroKey -> xmk_UserData)
		(*Routine)();
	else
		SerialCommand(MacroKeys -> Keys[XEM_MacroKey -> xmk_Qualifier][XEM_MacroKey -> xmk_Code - 0x50]);
}

	/* SetEmulatorOptions(BYTE Mode):
	 *
	 *	Save or load the emulator options.
	 */

BYTE
SetEmulatorOptions(BYTE Mode)
{
	BYTE Success = FALSE;

		/* Is the library available and running? */

	if(XEmulatorBase && XEM_IO)
	{
			/* Are we using the new library code? */

		if(XEmulatorBase -> lib_Version >= 4)
		{
				/* Get the name of the library. */

			strcpy(SharedBuffer,FilePart(XEmulatorBase -> lib_Node . ln_Name));

				/* Does it have any name? */

			if(SharedBuffer[0])
			{
				UBYTE	OtherBuffer[50];
				WORD	i;

					/* Strip the `.library' bit. */

				for(i = strlen(SharedBuffer) - 1 ; i >= 0 ; i--)
				{
					if(SharedBuffer[i] == '.')
					{
						SharedBuffer[i] = 0;

						break;
					}
				}

					/* What are we to do? */

				if(Mode == XEM_PREFS_LOAD)
				{
						/* Restore settings... */

					strcpy(OtherBuffer,"ENV:");

					if(AddPart(OtherBuffer,SharedBuffer,50))
					{
							/* If we can't load them,
							 * reset to defaults.
							 */

						if(!XEmulatorPreferences(XEM_IO,OtherBuffer,Mode))
							XEmulatorPreferences(XEM_IO,NULL,XEM_PREFS_RESET);
						else
							Success = TRUE;
					}
				}
				else
				{
						/* Save settings to ENV: */

					strcpy(OtherBuffer,"ENV:");

					if(AddPart(OtherBuffer,SharedBuffer,50))
					{
						if(XEmulatorPreferences(XEM_IO,OtherBuffer,Mode))
							Success = TRUE;
					}

					if(Success)
					{
						Success = FALSE;

							/* Save settings to ENVARC: */

						strcpy(OtherBuffer,"ENVARC:");

						if(AddPart(OtherBuffer,SharedBuffer,50))
						{
							if(XEmulatorPreferences(XEM_IO,OtherBuffer,Mode))
								Success = TRUE;
						}
					}
				}
			}
		}
	}

		/* Return result. */

	return(Success);
}

	/* SetupEmulator(BYTE OpenConsole):
	 *
	 *	Initialize the XEM_IO structure.
	 */

STATIC BYTE
SetupEmulator(VOID)
{
	if(!XEM_IO)
	{
		if(XEM_IO = (struct XEM_IO *)AllocVec(sizeof(struct XEM_IO),MEMF_ANY|MEMF_CLEAR))
		{
			XEM_IO -> xem_window		= Window;
			XEM_IO -> xem_font		= CurrentFont;
			XEM_IO -> xem_signal		= &XEM_Signal;
			XEM_IO -> xem_screendepth	= Screen -> RastPort . BitMap -> Depth;

			XEM_IO -> xem_sread		= (APTR)xpr_sread;
			XEM_IO -> xem_swrite		= (APTR)xem_swrite;
			XEM_IO -> xem_sflush		= (APTR)xpr_sflush;
			XEM_IO -> xem_sbreak		= (APTR)xem_sbreak;
			XEM_IO -> xem_squery		= (APTR)xpr_squery;
			XEM_IO -> xem_sstart		= (APTR)xem_sstart;
			XEM_IO -> xem_sstop		= (APTR)xem_sstop;

			XEM_IO -> xem_tbeep		= (APTR)xem_tbeep;
			XEM_IO -> xem_tgets		= (APTR)xem_tgets;
			XEM_IO -> xem_toptions		= (APTR)xpr_options;

			XEM_IO -> xem_process_macrokeys	= (APTR)xem_macrodispatch;

			return(TRUE);
		}
	}
	else
		return(FALSE);

	return(FALSE);
}

	/* CloseEmulator():
	 *
	 *	Close the emulation library.
	 */

VOID
CloseEmulator()
{
	if(XEmulatorBase)
	{
		if(XEM_IO)
		{
			XEmulatorMacroKeyFilter(XEM_IO,NULL);
			XEmulatorCloseConsole(XEM_IO);
			XEmulatorCleanup(XEM_IO);

			FreeVec(XEM_IO);

			XEM_IO = NULL;
		}

		CloseLibrary(XEmulatorBase);

		strcpy(EmulationName,LocaleString(MSG_TERMXEM_NO_EMULATION_TXT));

		XEmulatorBase	= NULL;
		XEM_Signal	= NULL;

		SetCursor();
	}
}

	/* OpenEmulator(UBYTE *Name):
	 *
	 *	Open an emulation library.
	 */

BYTE
OpenEmulator(UBYTE *Name)
{
	CloseEmulator();

	XEM_HostData . Source		= NULL;
	XEM_HostData . Destination	= NULL;
	XEM_HostData . InESC		= FALSE;
	XEM_HostData . InCSI		= FALSE;

	if(XEmulatorBase = OpenLibrary(Name,0))
	{
		Reset();

		ClearCursor();

		if(SetupEmulator())
		{
			SetWrMsk(RPort,(1 << Screen -> RastPort . BitMap -> Depth) - 1);

			if(XEmulatorSetup(XEM_IO))
			{
				SetEmulatorOptions(XEM_PREFS_LOAD);

				if(XEmulatorOpenConsole(XEM_IO))
				{
					UBYTE *LibName = FilePart(Name);

					strcpy(EmulationName,&LibName[3]);

					EmulationName[strlen(EmulationName) - 8] = 0;

					SetupXEM_MacroKeys(MacroKeys);

					return(TRUE);
				}
			}
		}

		SetCursor();

		CloseLibrary(XEmulatorBase);

		strcpy(EmulationName,LocaleString(MSG_TERMXEM_NO_EMULATION_TXT));

		XEmulatorBase	= NULL;
		XEM_Signal	= NULL;
	}

	return(FALSE);
}

	/* XOff():
	 *
	 *	Small local routine, complements XOn() in Serial.c
	 */

STATIC VOID
XOff()
{
	if(Status == STATUS_HOLDING)
	{
		UBYTE c = XOF;

		SerWrite(&c,1);

		Status = STATUS_READY;
	}
}

	/* SetupXEM_MacroKeys(struct MacroKeys *Keys):
	 *
	 *	Sets up the internal representation of the macro key
	 *	data to fit the XEM specification.
	 */

VOID
SetupXEM_MacroKeys(struct MacroKeys *Keys)
{
		/* Are we allowed to do what we want to do? */

	if(XEM_MacroKeys && XEmulatorBase && Config . Emulation == EMULATION_EXTERNAL)
	{
		WORD i,j,k = 0;

			/* Clear the macro list. */

		NewList(&XEM_MacroList);

			/* Run down the list of qualifiers. */

		for(i = XMKQ_NONE ; i <= XMKQ_CONTROL ; i++)
		{
				/* Run down the function keys. */

			for(j = 0 ; j < 10 ; j++)
			{
					/* If the key has no data attached,
					 * don't use it in the list.
					 */

				if(Keys -> Keys[i][j][0])
				{
					XEM_MacroKeys[k] . xmk_Type		= XMKT_RAWKEY;
					XEM_MacroKeys[k] . xmk_Qualifier	= i;
					XEM_MacroKeys[k] . xmk_Code		= 0x50 + j;
					XEM_MacroKeys[k] . xmk_UserData		= NULL;

					AddTail(&XEM_MacroList,(struct Node *)&XEM_MacroKeys[k++]);
				}
			}
		}

			/* Take care of the rest, add support for the xON key. */

		XEM_MacroKeys[k] . xmk_Type 		= XMKT_COOKED;
		XEM_MacroKeys[k] . xmk_Qualifier	= NULL;
		XEM_MacroKeys[k] . xmk_Code		= XON;
		XEM_MacroKeys[k] . xmk_UserData		= (APTR)DoxON;

		AddTail(&XEM_MacroList,(struct Node *)&XEM_MacroKeys[k++]);

			/* Take care of the xOFF key. */

		XEM_MacroKeys[k] . xmk_Type 		= XMKT_COOKED;
		XEM_MacroKeys[k] . xmk_Qualifier	= NULL;
		XEM_MacroKeys[k] . xmk_Code		= XOF;
		XEM_MacroKeys[k] . xmk_UserData		= (APTR)XOff;

		AddTail(&XEM_MacroList,(struct Node *)&XEM_MacroKeys[k]);

			/* Make the emulator notice the new settings. */

		XEmulatorMacroKeyFilter(XEM_IO,&XEM_MacroList);
	}
}
