/* RndPat.c
 *
 * Random Opus background picture selector.
 *
 * Public domain in 1996-97 by Magnus Holmgren.
 */

#include "RndPat.h"


/* ----- Global variables ------------------------------------------------- */


struct Library	*RexxSysBase;

TEXT	ProgramName[] = "OpusRndPat";


/* ----- Version string --------------------------------------------------- */


const STATIC TEXT Version[] = "$VER: OpusRndPat 1.0 (14.12.97)";


/* ----- ARexx stuff ------------------------------------------------------ */


/* Send the command to the named dest port. Ignores any RESULT.
 *
 * Returns the return code from the command, or, if the message couldn't be
 * sent, -1 to indicate allocation failure, and -2 that the dest message port
 * didn't exist.
 *
 * Note that this function does not need to allocate any signal to do its
 * job. It uses the special SINGLE bit, which can be used in this kind
 * of one-shot signalling.
 */
STATIC LONG
RexxExecute( STRPTR dest, STRPTR command )
{
	struct RexxMsg	*msg;
	struct MsgPort	port;
	LONG	rc = -1;

	/* Set up message port in a lazy way... */
	port.mp_Node.ln_Type	= NT_MSGPORT;
	port.mp_Flags		= PA_SIGNAL;
	port.mp_SigBit		= SIGB_SINGLE;
	port.mp_SigTask		= FindTask( NULL );
	NewList( &port.mp_MsgList );

	if( msg = CreateRexxMsg( &port, NULL, NULL ) )
	{
		msg->rm_Node.mn_Node.ln_Name = "REXX";
		msg->rm_Action = RXCOMM;

		if( ARG0( msg ) = CreateArgstring( command, ( ULONG ) strlen( command ) ) )
		{
			struct MsgPort	*destPort;

			/* Avoid spurios signals */
			SetSignal( 0, SIGF_SINGLE );

			/* FindPort()/PutMsg() must be an "atomic" operation, so Forbid() */
			Forbid();

			if( destPort = FindPort( dest ) )
			{
				PutMsg( destPort, ( struct Message * ) msg );
			} /* if */

			Permit();

			if( destPort )
			{
				/* We did send a message, so wait for it to return */
				WaitPort( &port );

				if( ( rc = msg->rm_Result1 ) == 0 )
				{
					/* We shouldn't be getting any result string, but
					 * check for it anyway, just to be sure. Not much
					 * code, so...
					 */
					if( msg->rm_Result2 )
					{
						DeleteArgstring( ( STRPTR ) msg->rm_Result2 );
					} /* if */
				} /* if */
			}
			else
			{
				rc = -2;
			} /* if */
		} /* if */

		/* Free returned string, if any */
		ClearRexxMsg( msg, 1 );

		/* And free the Rexx message */
		DeleteRexxMsg( msg );
	} /* if */

	return( rc );
} /* RexxExecute */


/* ----- Main ------------------------------------------------------------- */


STATIC VOID
SPrintf( STRPTR buf, STRPTR fmt, ... )
{
	RawDoFmt( fmt, &fmt + 1, ( VOID (*)() ) "\x16\xc0\x4e\x75", buf );
} /* SPrintf */


STATIC STRPTR Types[] = { "Desktop", "Window", "Requester" };


LONG
SetBackground( STRPTR port, STRPTR name, STRPTR type,
	STRPTR precision, LONG center, LONG verbose, LONG *delay )
{
	CONST STATIC UBYTE	Command[] = "Command SetAsBackground \"%s\" %s PRECISION %s %s";
	STATIC BYTE		cmdSent = FALSE;
	STRPTR	buf, file;
	LONG	rc = -1;

	if( !name )
	{
		return( 0 );
	} /* if */

	if( file = GetPattern( name ) )
	{
		if( buf = AllocVec( ( ULONG )
			( strlen( file ) + strlen( type ) + strlen( precision ) + sizeof( Command ) + 1 ), MEMF_ANY ) )
		{
			SPrintf( buf, Command, file, type, precision, center ? "CENTER" : "TILE" );

			if( cmdSent && delay && ( *delay > 1 ) )
			{
				Delay( *delay );
			}

			rc = RexxExecute( port, buf );
			cmdSent = TRUE;

			if( verbose && !rc )
			{
				Printf( "%s background set to '%s' with precision %s (%s)\n",
					type, file, precision, center ? "centered" : "tiled" );
			}

			FreeVec( buf );
		} /* if */

		FreeVec( file );
	} /* if */

	switch( rc )
	{
		case -2:
			Printf( "%s: Port '%s' not found\n", ProgramName, port );
			break;

		case -1:
			Printf( "%s: Not enough memory\n", ProgramName );
			break;

		case 0:
			break;

		default:
			Printf( "%s: Opus returned %ld\n", ProgramName, rc );
			break;
	} /* switch */

	return( rc );
} /* SetBackground */


struct Args
{
	STRPTR	Desktop;
	STRPTR	Window;
	STRPTR	Requester;
	STRPTR	Precision;
	LONG	Center;
	LONG	Verbose;
	STRPTR	Port;
	LONG	*Delay;
}; /* struct Args */

#define TEMPLATE	"DESKTOP,LISTER=WINDOW,REQUESTER,PRECISION/K,CENTER/S,VERBOSE/S,PORT/K,DELAY/K/N"


LONG
Main( VOID )
{
	struct RDArgs	*rda;
	struct Args	args;
	LONG	rc = RETURN_ERROR;

	memset( &args, 0, sizeof( args ) );
	args.Precision = "IMAGE";
	args.Port = "DOPUS.1";

	if( RexxSysBase = OpenLib( "rexxsyslib.library", 0 ) )
	{
		if( rda = ReadArgs( TEMPLATE, ( LONG * ) &args, NULL ) )
		{
			InitSeed();
			SetIoErr( 0 );

			if( args.Desktop || args.Window || args.Requester )
			{
				STRPTR	*patterns;
				LONG	i;

				patterns = ( STRPTR * ) &args;
				rc = RETURN_OK;

				for( i = 0; i < 3; ++i )
				{
					if( SetBackground( args.Port, patterns[ i ], Types[ i ],
						args.Precision, args.Center, args.Verbose, args.Delay ) )
					{
						rc = RETURN_WARN;
					}
				} /* if */
			}
			else
			{
				Printf( "%s: No pattern(s) specified\n", ProgramName );
				rc = RETURN_WARN;
			} /* if */

			FreeArgs( rda );
		}
		else
		{
			PrintfFault( IoErr(), "%s: Argument error", ProgramName );
		} /* if */

		CloseLib( RexxSysBase );
	} /* if */

	return( rc );
} /* Main */
