/*
**
**	$Id: arexx.c,v 1.1 1995/10/07 02:48:56 amiga Exp $
**	$Revision: 1.1 $
**
**	$Filename: answeringmachine/arexx.c $
**	$Author: amiga $
**	$Date: 1995/10/07 02:48:56 $
**	$Portability: AMIGADOS $
**
**	ARexx interface
**
**	COPYRIGHT (C) 1991, 1992 BY CHRISTIAN A. WEBER, ZUERICH.
**	COPYRIGHT (C) 1992-1995 BY RELOG AG, ZUERICH. ALL RIGHTS RESERVED.
**	NO PART OF THIS SOFTWARE MAY BE COPIED, REPRODUCED, OR TRANSMITTED
**	IN ANY FORM OR BY ANY MEANS,  WITHOUT THE PRIOR WRITTEN PERMISSION
**	OF RELOG AG.
**
*/

#include "os.h"

#include <proto/exec.h>
#include <clib/rexxsyslib_protos.h>
#include <pragmas/rexxsyslib_pragmas.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/utility.h>

#include <string.h>
#include <stdio.h>

#define  _AREXX
#include "arexx.h"

#include "am.h"

#define MYREXXSUFFIX	"amrx"


static struct Library		*RexxSysBase;


/****************************************************************************
**	ASCII String holen, Anführungszeichen interpretieren.
**	Der Char*-Zeiger wird auf den Text nach dem String gesetzt.
**	Gibt FALSE zurück, wenn kein Argument mehr vorhanden ist.
*/

BOOL ARexx_GetString( char **strptr, char *dest, int destsize )
{
	char	*s = *strptr;
	BOOL	result = FALSE;

	/*
	**	Führende Spaces überlesen
	*/
	while (*s == ' ')
		s++;


	/*
	**	Text kopieren
	*/
	if (*s == '"')		/* Anführungszeichen --> plain copy */
	{
		s++;
		while (*s != '\0')
		{
			result = TRUE;
			if (*s == '\\')		/* Escape-Sequenz */
			{
				s++;
				if (*s == '\0')
					break;

				switch (*s)
				{
					case 'n':
						if (destsize > 0)
						{
							*dest++ = '\n';
							destsize--;
						}
						break;

					default:
						if (destsize > 0)
						{
							*dest++ = *s;
							destsize--;
						}
						break;
				}
				s++;
			}
			else if (*s == '"')
			{
				s++;
				break;
			}
 			else
 			{
 				if (destsize > 0)
 				{
					*dest++ = *s;
					destsize--;
				}
				s++;
			}
		}
	}
	else				/* Keine Anführungszeichen --> bis Space */
	{
		while (*s != '\0')
		{
			result = TRUE;
			if (*s == '\\')		/* Escape-Sequenz */
			{
				s++;
				if (*s == '\0')
					break;

				switch (*s)
				{
					case 'n':
						if (destsize > 0)
						{
							*dest++ = '\n';
							destsize--;
						}
						break;

					default:
						if (destsize > 0)
						{
							*dest++ = *s;
							destsize--;
						}
						break;
				}
				s++;
			}
			else if(*s == ' ')
			{
				break;
			}
 			else
 			{
 				if (destsize > 0)
 				{
					*dest++ = *s;
					destsize--;
				}
				s++;
			}
		}
	}
	*dest = '\0';

	/*
	**	Spaces am Schluss überlesen
	*/
	while (*s == ' ')
		s++;

	*strptr = s;

	return result;
}


/****************************************************************************
**	ASCII nach Integer wandeln, Nachkommastellen werden unterdrückt.
**	Der Char*-Zeiger wird auf den Text nach der Zahl gesetzt.
**	Gibt FALSE zurück, wenn keine Zahl erkannt wurde.
*/

BOOL ARexx_GetInteger( char **strptr, S32 *pInt )
{
	char	*s = *strptr;
	S32		zahl = 0;
	S8		sign = 1;
	BOOL	result = FALSE;

	while (*s == ' ')
		s++;

	if (*s == '-')
	{
		sign = -1;
		s++;
	}
	else if(*s == '+')
		s++;

	while ((*s >= '0') && (*s <= '9'))
	{
		zahl = zahl * 10 + (*s++ - '0');
		result = TRUE;
	}

	while (*s == ' ')
		s++;

	*strptr = s;
	*pInt = (sign > 0) ? zahl : -zahl;

	return result;
}


/****************************************************************************
**	Ein Rexx-Kommando auswerten, geht auch wenn ARexx NICHT läuft
*/

static S32 PerformRexxCommand( char *commandline, struct AnsweringMachine *am )
{
	static struct MyRexxCmd
	{
		char	*Name;
		S32		(*Func)( char *, struct AnsweringMachine * );
	}
	rexxcmdtab[] =
	{
		"BACKGROUND",			RXFunc_Background,
		"FADE",					RXFunc_Fade,
		"HANGUP",				RXFunc_HangUp,
		"PLAY",					RXFunc_Play,
		"RECORD",				RXFunc_Record,
		"WAITKEY",				RXFunc_WaitKey,
		NULL,					NULL
	};

	struct MyRexxCmd *cptr;

	printf( "PerformRexxCommand( \"%s\" )\n", commandline );

	rexx_resultstring[0] = '\0';		/* Resultat löschen */

	for (cptr = rexxcmdtab; cptr->Name; cptr++)
	{
		char *s, *d;
		for (s = commandline, d=cptr->Name; *d; s++, d++)
		{
			if(ToUpper( (ULONG)*s ) != *d )
				break;
		}

		if (*s <= ' ')							/* Kommandoname fertig: das richtige */
		{
			S32 result;

			while (*s == ' ')					/* Spaces überhüpfen */
				s++;

			/* arexxflag = TRUE; */
			result = (*cptr->Func)( s, am );	/* Funktion aufrufen */
			/* arexxflag = FALSE; */

			return result;
		}
	}

	printf( "Unknown command!\n" );
	return RC_ERROR;
}


/****** ARexx_Init **********************************************************
*
*   NAME
*       ARexx_Init -- Initialize ARexx
*
*   SYNOPSIS
*       sigmask = ARexx_Init()
*
*       BOOL ARexx_Init( VOID );
*
*   FUNCTION
*       Opens the required libraries (rexxsyslib)
*
*   INPUTS
*
*   RESULTS
*
*   SEE ALSO
*       ARexx_Exit()
*
****************************************************************************/

BOOL ARexx_Init( VOID )
{
	if (RexxSysBase = OpenLibrary( RXSNAME, 0 ))
	{
		return TRUE;
	}

	ARexx_Exit();
	return 0;
}


/****** ARexx_Exit **********************************************************
*
*   NAME
*       ARexx_Exit -- Close our ARexx port
*
*   SYNOPSIS
*       ARexx_Exit()
*
*       VOID ARexx_Exit( VOID );
*
*   FUNCTION
*       Tries to close down our ARexx port and all associated resources.
*       Will wait until all running scripts have terminated.
*
*   INPUTS
*
*   RESULTS
*
*   SEE ALSO
*       ARexx_Init()
*
****************************************************************************/

VOID ARexx_Exit( VOID )
{
	if (RexxSysBase != NULL)
	{
		CloseLibrary( RexxSysBase );
		RexxSysBase = NULL;
	}
}


/****** ARexx_HandleMessages ************************************************
*
*   NAME
*       ARexx_HandleMessages -- Handle ARexx messages
*
*   SYNOPSIS
*       ARexx_HandleMessages( port, userdata )
*
*       VOID ARexx_HandleMessages( struct MsgPort *, VOID * );
*
*   FUNCTION
*       Handles all ARexx messages which are currently waiting on our
*       message port. This function is usually called after the ARexx
*       signal has been received.
*
*   INPUTS
*       port     - Port to get messages from
*       userdata - User data, will be forwarded to all functions
*
*   RESULTS
*       none
*
*   SEE ALSO
*
****************************************************************************/

VOID ARexx_HandleMessages( struct ARexxPort *ap )
{
	struct RexxMsg *msg;

	/* printf( "ARexx_HandleMessages( 0x%08lx )\n", ap ); */

	if (ap == NULL)		/* Sofort zurück falls ARexx nicht läuft */
		return;

	while (msg = (struct RexxMsg *)GetMsg( ap->Port ))
	{
		if (msg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG)
		{
			/*
			**	Es ist eine gültige Message und nicht eine Antwort.
			*/
			if (IsRexxMsg( msg ))
			{
				/* Sollen wir ein Kommando auführen ? */
				if ((msg->rm_Action & RXCODEMASK) == RXCOMM)
				{
					msg->rm_Result1 = 0;
					msg->rm_Result2 = 0;

					if (msg->rm_Result1 = PerformRexxCommand( msg->rm_Args[0], ap->UserData ))
					{
						/* Func returned an error */
					}
					else if((*rexx_resultstring)	&& (msg->rm_Action & RXFF_RESULT))
					{
						msg->rm_Result2 = (LONG)
							CreateArgstring( rexx_resultstring, (ULONG)strlen( rexx_resultstring ) );
					}
				}
			}

			ReplyMsg( &msg->rm_Node );
		}
		else
		{
			/*
			**	Diese Message ist ein reply auf eine Message welche wir
			**	früher mal geschickt haben
			*/
			DeleteArgstring( msg->rm_Args[0] );
#if 0
			if (msg->rm_Stdin)
				Close( msg->rm_Stdin );
#endif
			DeleteRexxMsg( msg );
			ap->MsgCount--;
		}
	}
}


/****************************************************************************
**	Eine RexxMessage schicken (Speicher wird von RexxMsgHandler freigegeben)
**	Parameter: Kommando-String
*/

BOOL
ARexx_LaunchScript( struct ARexxPort *ap, char *command )
{
	struct MsgPort *masterport;

	if (masterport = FindPort( "REXX" ))
	{
		struct RexxMsg *msg;

		if (msg = CreateRexxMsg( ap->Port, MYREXXSUFFIX, ap->Port->mp_Node.ln_Name ))
		{
			if(msg->rm_Args[0] = CreateArgstring( command, (ULONG)strlen( command ) ))
			{
				msg->rm_Action	= RXCOMM | RXFF_TOKEN;
				msg->rm_Stdin	= Input();
				msg->rm_Stdout	= Output();
				PutMsg( masterport, &msg->rm_Node );
				ap->MsgCount++;

				return  TRUE;
			}

			printf( "ARexx_LaunchScript(): CreateArgString failed\n" );
			DeleteRexxMsg( msg );
		}

		printf( "ARexx_LaunchScript(): CreateRexxMsg failed\n" );
	}

	printf( "ARexx_LaunchScript(): Can't find REXX port\n" );

	return FALSE;
}


/*
**	ARexx-Port erzeugen
*/
struct ARexxPort *ARexx_CreatePort( char *name, VOID *userdata )
{
	struct ARexxPort *ap;

	if (ap = (struct ARexxPort *)OS_Malloc( sizeof( *ap ) ))
	{
		if (ap->Port = CreatePort( name, 0 ))
		{
			ap->UserData = userdata;
/*			ap->UseCount = 0; */
		}
		else
		{
			OS_Free( ap );
			ap = NULL;
		}
	}

	return ap;
}


/*
**	ARexx-Port freigeben
*/
VOID ARexx_DeletePort( struct ARexxPort *ap )
{
	if (ap != NULL)
	{
		if (ap->MsgCount > 0)
		{
			printf( "Port %s: UseCount = %ld, waiting ...\n", ap->Port->mp_Node.ln_Name, ap->MsgCount );
			ARexx_HandleMessages( ap );
			WaitPort( ap->Port );
		}

		DeletePort( ap->Port );
		OS_Free( ap );
	}
}
