
/*
 * $VER: FAME DoorInclude 1.0
 *
 * DoorStartup for FIM Doors - can be compiled resident.
 *
 */

/*
 * Includes:
 */

#include <FAME/FAMEDoorProto.h>
#include <libraries/fame.h>

/*
 * FIM Defines:
 */

#define FIM_MINBUFSIZE				1024L

/*
 * Global variables:
 */

struct MsgPort			*DoorControlPort	= NULL,
										*DoorReplyPort		= NULL;
struct FAMEDoorMsg	*MyFAMEDoorMsg		= NULL;

char					FAMEDoorPort[30],
							*GlobBuffer							= NULL,
							ErrorText[200];
unsigned long	Signals,
							PortSig									= 0UL,
							GlobUserSigs						= 0UL;

/*
 * Prototypes:
 */

long				FIMStart(long BufSize);
long				FIMHandlePort(long FIMCommand, ULONG UserSigs);
void				FIMEnd(long ReturnCode);
STATIC void	FIMFree(long ReturnCode);
STATIC void	FIMPrintError(long Error);

/*
 * Prototypes for Support-Functions
 */

long GetString(char*,long);
long PutString(char*,long);
long PutStringFormat(char *ctl, ...);
long PutCommand(char*,long,long,ULONG,long);
long GetCommand(char*,long,long,ULONG,long);

void Center(char *stri,long lf,long col);
void SPrintf(char *Buffer,char *ctl, ...);
long FAMEAtol(char *Buffer);

/*
 * FUNCTION: long FIMStart(long BufSize);
 *
 *  PURPOSE: Allocates Memory for DoorStruct and start Doorport communication
 *
 *    INPUT: BufSize = Memory used for Global String Pointer, 1024 bytes is
 *                     the minimum amount for this pointer.
 *
 *   RETURN:  0 = If no error occures during initializing.
 *           -1 = No memory for Global String Pointer
 *           -2 = No memory for FAMEDoorMsg
 *           -3 = DoorReplyPort couldn't be created
 *           -4 = Communication with FAME failed
 *
 * See FIMHandlePort() for more informations about errorcode -4!
 *
 * If any error occure you may repeat the initialization process as all vars
 * used by this function are freed !
 */

long FIMStart(long BufSize)
{
	*ErrorText = '\0';

	if(BufSize < FIM_MINBUFSIZE)
		BufSize = FIM_MINBUFSIZE;

	if( ! (GlobBuffer = AllocVec(BufSize,MEMF_PUBLIC | MEMF_CLEAR)))
		return(-1);

	if( ! (MyFAMEDoorMsg = (struct FAMEDoorMsg *)FAMEAllocObject(FOBJ_FAMEDoorMsg)))
	{
		FIMFree(0);
		return(-2);
	}

  if( ! (DoorReplyPort = CreatePort(NULL,0L)))
	{
		FIMFree(0);
		return(-3);
	}

	PortSig = 1<<DoorReplyPort->mp_SigBit;

	MyFAMEDoorMsg->fdom_Msg.mn_Length			= sizeof(struct FAMEDoorMsg);
	MyFAMEDoorMsg->fdom_Msg.mn_ReplyPort	= DoorReplyPort;
	MyFAMEDoorMsg->fdom_Command						= MC_DoorStart; /* Register Door */

	if(FIMHandlePort(0,NULL)<0)
	{
		FIMFree(-1);
		return(-4);
	}
	return(0);
}

/*
 * FUNCTION: void FIMEnd(long ReturnCode);
 *
 *  PURPOSE: Closes DoorPort Communication and also calls user supplied
 *           function 'ShutDown()' to allow the deallocation of all memory
 *           used by the door.
 *
 *    INPUT: Userdefined ReturnCode. Allowed range for usererrors are from
 *           (FIM_USERERROR + 1) to (ERROR_NO_FREE_STORE - 1), which means
 *           the range from 11 to 102. All values > 102 are for the DOS
 *           error codes and will be used to print the according error as
 *           localized errorstring (See include/dos/dos.h for further infos
 *           about DOS error codes).
 *
 *   RETURN: Nothing.
 */

void FIMEnd(long ReturnCode)
{
	if(ReturnCode)
  {
		if(ReturnCode > FIM_USERERROR && ReturnCode < ERROR_NO_FREE_STORE)
			SPrintf(ErrorText,"\n\r[37mDoor failed with returncode [35m%ld [m!\n\n\r",ReturnCode);
		else
		{
			Fault(ReturnCode,"\n\r",ErrorText,199);
			strcat(ErrorText,"\n\n\r");
		}
  }
	FIMFree(FIM_USERERROR);
}

/*
 * FUNCTION: STATIC void FIMFree(long ReturnCode);  !!! PRIVATE !!!
 *
 *  PURPOSE: Really shutdown the Doorport and free all allocated memory.
 *           This function will call the user supplied function 'ShutDown()'
 *           after freeing all allocated memory!
 *
 *    INPUT: Returncode which indicates if there is any doorport error.
 *
 *   RETURN: Nothing.
 *
 *     NOTE: THIS FUNCTION SHOULD NOT BE USED FROM DOORS, AS THIS WILL ONLY
 *           BE CALLED HERE INSIDE THIS DOORSTARTUP-CODE !!
 */

STATIC void FIMFree(long ReturnCode)
{
	if(ReturnCode > 0)
	{
		MyFAMEDoorMsg->fdom_Command = MC_ShutDownLastWords;
		strcpy(MyFAMEDoorMsg->fdom_IOString,ErrorText);
	}
	else if( ! ReturnCode)
		MyFAMEDoorMsg->fdom_Command = MC_ShutDown;

	if(ReturnCode > -1)
		FIMHandlePort(0,NULL);

  if(DoorReplyPort)
	{
		while(GetMsg(DoorReplyPort));

		DeletePort(DoorReplyPort);
		DoorReplyPort = NULL;
	}

	if(MyFAMEDoorMsg)
		FreeVec(MyFAMEDoorMsg);
	MyFAMEDoorMsg	= NULL;

	if(GlobBuffer)
		FreeVec(GlobBuffer);
	GlobBuffer		= NULL;

	ShutDown(ReturnCode);
}

/*
 * FUNCTION: long FIMHandlePort(long FIMCommand, ULONG UserSigs);
 *
 *  PURPOSE: This is the main communication routine, it handles all the stuff
 *           required to send commands to FAME and also interprets errorcodes
 *           and ENDS THE DOOR if the according error occure! See the
 *           DoorCommands.Guide for more informations about these errorcodes
 *           and how to handle them!
 *
 *    INPUT: FIMCommand to send to FAME. If this field is NULL, this function
 *           assumes the command to send in MyFAMEDoorMsg->fdom_Command. So
 *           make sure that you set the right command if you are using this
 *           function like FIMHandlePort(0,NULL); !
 *
 *   RETURN:  0 = Everything okay, Command successfully executed.
 *           -1 = DoorControlPort not found !
 *           >0 = 1-10 for FAME defined Errorcodes (see DoorCommands.guide).
 *           <0 = -1 to -3 for FAME DoorPort errors (see FAMEDefine.h).
 *
 *     NOTE: This function is mainly used in the support functions, see above
 *           for further infos.
 */

long FIMHandlePort(long FIMCommand, ULONG UserSigs)
{
	ULONG	CombSigs	= 0UL;
	long	FailFlag	= 0L;

	if(FIMCommand)
		MyFAMEDoorMsg->fdom_Command = FIMCommand;

	CombSigs		|= PortSig;

	if(UserSigs)
		CombSigs	|= UserSigs;
	else if(GlobUserSigs)
		CombSigs	|= GlobUserSigs;

	Forbid();
	if(DoorControlPort = FindPort((UBYTE *)FAMEDoorPort))
		PutMsg(DoorControlPort,(struct Message *)MyFAMEDoorMsg);
  Permit();

	if(DoorControlPort)
	{
		FOREVER
		{
			Signals = Wait(CombSigs);

			if(UserSigs || GlobUserSigs)
				UserSigHandle(Signals);

			if(Signals & PortSig)
			{
				while(GetMsg(DoorReplyPort))
				{
					if(MyFAMEDoorMsg->fdom_ReturnCode && FailFlag > -1)
						FailFlag = MyFAMEDoorMsg->fdom_ReturnCode;
				}
				break;
			}
		}
	}
	else
	{
		Printf("\nUnable to find %s !\n\n",FAMEDoorPort);
		FIMFree(-1);

		return(-1);
	}
	if(FailFlag)
	{
		if(FailFlag > 0)
    	FIMPrintError(FailFlag);
		FIMFree(FailFlag);

		return(FailFlag);
	}

	return(0);
}

/*
 * FUNCTION: STATIC void FIMPrintError(long Error);   !!! PRIVATE !!!
 *
 *  PURPOSE: Fills out global var 'ErrorText' with the supplied error number.
 *           The command which produces the error will be taken from the
 *           MyFAMEDoorMsg->fdom_Command field when a FIM_CDMDENIED error
 *           occures.
 *
 *    INPUT: Error indicates the errornumber from FAME (see FAMEDefines.h
 *           for further informations about these numbers).
 *
 *   RETURN: Nothing.
 *
 *     NOTE: This function is PRIVATE and will only be used inside this
 *           doorstartup-code from FIMHandlePort() in the case of an error!
 *
 */

STATIC void FIMPrintError(long Error)
{
	long		wrongcommand;
  char		*Button[] = {"NR","NC","CF","SR","SC","AR","AC","RD","UN"};
  USHORT	butnum = 0;

	wrongcommand = MyFAMEDoorMsg->fdom_Command;

  switch(Error)
	{
		case FIM_CMDABORTED:
			SPrintf(ErrorText,"\n\r[37mCommand [32m%ld [37maborted [m!\n\n\r");
		break;
		case FIM_CMDNOTIMPLEMENTED:
			SPrintf(ErrorText,"\n\r[37mCommand [32m%ld [37mnot implemented until now in this Version of FAME [m!\n\n\r",wrongcommand);
		break;
		case FIM_CMDDOESNOTEXISTS:
			SPrintf(ErrorText,"\n\r[37mCommand [32m%ld [37mdoesn't exist [m!\n\n\r",wrongcommand);
		break;
		case FIM_CMDNOTSUCCESSFULL:
			SPrintf(ErrorText,"\n\r[37mCommand [32m%ld [37mcouldn't be executed successfully [m!\n\n\r",wrongcommand);
		break;
		default: // FIM_CMDDENIED:
			if(wrongcommand > 999)
				butnum = 7; 							// RD
			else if(wrongcommand > 899)
				butnum = 6;								// AC
			else if(wrongcommand > 799)
				butnum = 5;								// AR
			else if(wrongcommand > 699)
				butnum = 4;								// SC
			else if(wrongcommand > 599)
				butnum = 3;								// SR
			else if(wrongcommand > 399)
				butnum = 2;								// CF
			else if(wrongcommand > 199)
				butnum = 1;								// NC
			else if(wrongcommand > 9)
				butnum = 0;								// NR
      else butnum=8;							// UN(used)

			SPrintf(ErrorText,"\n\r[37mDoor uses [32m%s [37mCommand, please allow it in your SystemEditor [m!\n\n\r",Button[butnum]);
		break;
	}
}

/*
 *  --- Support Functions (V1.0) ---
 */

/*
 * FUNCTION: long GetString(char text[], long Data);
 *
 *  PURPOSE: Request a String from the user with a specific length.
 *
 *    INPUT: text[] = The string to be edited by the user. It also could
 *                    contain a default string.
 *             Data = Max. length of chars to be entered/edited by the user.
 *
 *   RETURN: If TRUE DoorPort is closed and ShutDown() was called during an
 *           error !
 *
 */

long GetString(char text[],long Data)
{
	long	ReturnCode;

  MyFAMEDoorMsg->fdom_Command	= NR_PromptChars;
  MyFAMEDoorMsg->fdom_Data1		= Data;
  MyFAMEDoorMsg->fdom_Data2		= FPC_NORMAL;
  strcpy(MyFAMEDoorMsg->fdom_IOString,text);
	ReturnCode = FIMHandlePort(0,NULL);
	if(text)
	  strcpy(text,MyFAMEDoorMsg->fdom_IOString);

  return(ReturnCode);
}

/*
 * FUNCTION: long PutString(char text[], long lf);
 *
 *  PURPOSE: Prints a String via AR_SendStr, so unlimited Strings are
 *           supported!
 *
 *    INPUT: text[] = Text to display.
 *               lf = 0 -> No LineFeed.
 *                    1 -> Print Linefeed (\r\n) after text.
 *
 *   RETURN: If TRUE DoorPort is closed and ShutDown() was called during an
 *           error !
 *
 *     NOTE: If the user has switched off the ANSI Colors, the string to
 *           display will be cutted from all ansicolors contained inside
 *           your string! During this operation the original string will
 *           be modified, so if you require the original string containing
 *           the ANSI colors, make first a copy before using this function!
 */

long PutString(char text[],long lf)
{
	MyFAMEDoorMsg->fdom_Command		= AR_SendStr;
	if(lf)
		MyFAMEDoorMsg->fdom_Data1		= 1;
	else
		MyFAMEDoorMsg->fdom_Data1		= 0;
	MyFAMEDoorMsg->fdom_StringPtr	= text;

  return(FIMHandlePort(0,NULL));
}

/*
 * FUNCTION: long PutStringFormat(char *ctl, ...);
 *
 *  PURPOSE: Prints a printf() style formatted string using the GlobBuffer
 *           and RawDoFmt() from exec.library, see autodocs for more infos
 *           about the supported formatcodes. The GlobBuffer depends on the
 *           size supplied when starting your door and has a minimum size
 *           of 1024 bytes. See FIMStart() for further infos about this.
 *
 *    INPUT: *ctl = formatstring. See Autodocs 'exec.library/RawDoFmt()'
 *                  for a detailed list of all supported formatcodes.
 *           ...  = All parameters required to fit your format string.
 *
 *   RETURN: If TRUE DoorPort is closed and ShutDown() was called during an
 *           error !
 */

long PutStringFormat(char *ctl, ...)
{
	RawDoFmt(ctl, (long *)(&ctl + 1), (void (*))"\x16\xc0\x4e\x75",GlobBuffer);
	MyFAMEDoorMsg->fdom_Command		= AR_SendStr;
	MyFAMEDoorMsg->fdom_StringPtr = GlobBuffer;

  return(FIMHandlePort(0,NULL));
}

/*
 * FUNCTION: long PutCommand(char text[], long Data1, long Data2,ULONG Data3,long Command);
 *
 *  PURPOSE: Puts a command with specific parameters to the DoorPort to
 *           perform some action. The returnvalues from the according
 *           functions could be found in the MyFAMEDoorMsg structure fields.
 *
 *    INPUT:  text[] = This will be copied to fdom_IOString
 *             Data1 = This will be set to fdom_Data1
 *             Data2 = This will be set to fdom_Data2
 *             Data3 = This will be set to fdom_Data3
 *           Command = Command to perform (see FAMEDoorCommands.guide)
 *
 *   RETURN: If TRUE DoorPort is closed and ShutDown() was called during an
 *           error !
 *
 */

long PutCommand(char text[],long Data1,long Data2,ULONG Data3,long Command)
{
  MyFAMEDoorMsg->fdom_Command	= Command;
  MyFAMEDoorMsg->fdom_Data1		= Data1;
  MyFAMEDoorMsg->fdom_Data2		= Data2;
  MyFAMEDoorMsg->fdom_Data3		= Data3;
  strcpy(MyFAMEDoorMsg->fdom_IOString,text);

	return(FIMHandlePort(0,NULL));
}

/*
 * FUNCTION: long GetCommand(char text[], long Data1, long Data2,ULONG Data3,long Command);
 *
 *  PURPOSE: Puts a command with specific parameters to the DoorPort to
 *           perform some action. The returnvalues from the according
 *           functions could be found in the MyFAMEDoorMsg structure fields,
 *           but if you supply a textbuffer the returnvalue found in IOString
 *           (if any) will be copied to this buffer.
 *
 *    INPUT:  text[] = This will be copied to fdom_IOString, after
 *                     performing the command the IOString contents will be
 *                     copied back to this field, so don't supply here any
 *                     constant texts, instead supply a buffer with at least
 *                     202 Bytes in size or "" to supply no buffer.
 *             Data1 = This will be set to fdom_Data1
 *             Data2 = This will be set to fdom_Data2
 *             Data3 = This will be set to fdom_Data3
 *           Command = Command to perform (see FAMEDoorCommands.guide)
 *
 *   RETURN:  text[] = If you have supplied a buffer the contents of the
 *                     IOString will be copied to your buffer.
 *
 *            Function returns TRUE if DoorPort is closed and ShutDown()
 *            was called during an error !
 *
 */

long GetCommand(char text[],long Data1,long Data2,ULONG Data3,long Command)
{
	long	ReturnCode;

  MyFAMEDoorMsg->fdom_Command	= Command;
  MyFAMEDoorMsg->fdom_Data1		= Data1;
  MyFAMEDoorMsg->fdom_Data2		= Data2;
  MyFAMEDoorMsg->fdom_Data3		= Data3;
  strcpy(MyFAMEDoorMsg->fdom_IOString,text);
  ReturnCode = FIMHandlePort(0,NULL);
	if(text)
		strcpy(text,MyFAMEDoorMsg->fdom_IOString);

	return(ReturnCode);
}

/*
 * FUNCTION: void Center(char *stri, long lf, long col);
 *
 *  PURPOSE: Displays a string centered with given colors and additional
 *           linefeed if required.
 *
 *    INPUT: *stri = The String to be displayed centered, this string may
 *                   also contain ANSI codes. The string is limited to
 *                   the size of GlobBuffer, which you supply in FAMEStart()
 *                   and have a minimum of 1024 bytes.
 *              lf = 0 -> No LineFeed
 *                   1 -> Print Linefeed (\r\n) after the string
 *             col = The color to use for the string, but you may also
 *                   supply multicolor strings!
 *
 *   RETURN: Nothing.
 *
 *     NOTE: If any error occures the DoorPort will be closed and ShutDown()
 *           will be called !!
 */

void Center(char *stri,long lf,long col)
{
	long	Middle	= NULL;

  strcpy(GlobBuffer,stri);
	FAMECutANSI(GlobBuffer,FCAF_STYLECMDS);
	Middle = ((78 - strlen(GlobBuffer)) / 2);
	GlobBuffer[0] = '\0';
	SPrintf(GlobBuffer,"\r[%ldm[%ldC%s\0",col,Middle,stri);
	PutString(GlobBuffer,lf);
}

/*
 * FUNCTION: void SPrintf(char *Buffer, char *ctl, ...);
 *
 *  PURPOSE: Builds a RawDoFmt() like string to a buffer.
 *
 *    INPUT: *Buffer = The Buffer to recieve the formatted String.
 *              *ctl = The Formatstring to use (see exec.library/RawDoFmt()
 *                     for further informations!).
 *               ... = The arguments to fit your formatstring.
 *
 *   RETURN: Nothing.
 */

void SPrintf(char *Buffer,char *ctl, ...)
{
	RawDoFmt(ctl, (long *)(&ctl + 1), (void (*))"\x16\xc0\x4e\x75",Buffer);
}

/*
 * FUNCTION: long FAMEAtol(char *Buffer);
 *
 *  PURPOSE: Converts a textstring to a long value using StrToLong() from
 *           dos.library.
 *
 *    INPUT: *Buffer = The string to convert.
 *
 *   RETURN: The converted long value (0 is returned if you supply a text
 *           without any valid digits!)
 */

long FAMEAtol(char *Buffer)
{
	long	Dummy;

	StrToLong(Buffer,&Dummy);
	return(Dummy);
}

// ---EOF---
