/* dvdemo.c -- devcon demo test main loop
 * Copyright (c) 1988, I and I Computing, and Commodore-Amiga, Inc.
 *
 * Executables based on this information may be used in software
 * for Commodore Amiga computers.  All other rights reserved.
 *
 * This information is provided "as is"; no warranties are made.
 * All use is at your own risk, and no liability or responsibility is assumed.
 */

#include "sysall.h"
#include "dview.h"
#include "spr.h"
#include "getargs.h"

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;

struct Screen *screen = NULL;
struct DoubleView	DV = {0};

/* command line argument: what method of display synchonization is
 * to be demonstrated?
 */
int		wait_type = 0;		/* default waitDV()	*/

struct Arg myargs[] = {
	{'w', ARG_TINT, &wait_type, "0-waitDV, 1-WaitTOF, 2-no wait, 3-WaitBOVB"},
};

/* these globals, plus the single signal SIGF_SINGLE, are the
 * communication between the input handler and the 
 * main task.
 */
int	hdlr_wants_out;
int	hdlr_should_steal;
struct InputEvent *Mintuition();

/* for cleanup purposes	*/
int	handler_installed = 0;

/* alternate mouse sprite and its position */
struct SpritePortRast	myspr;
int		mousex;			/* view-relative mouse coords and limits	*/
int		mousey;
int		maxxmouse;
int		maxymouse;

main(argc, argv)
char	**argv;
{
	int				cc;
	struct RastPort	*rp;

	if (!OpenI( 33 )) cleanup( "no intuition\n");
	if (!OpenGfx( 33 )) cleanup("no graphics\n");

    if (getargs( argv, myargs, NUMARGS( myargs ), NULL) < 0) cleanup("-\n");

	/* 
	 * initialize input theft scheme
	 */
	hdlr_should_steal = 0;			/* don't fire him up yet	*/
	hdlr_wants_out = 0;
	if ( installInputHandler( Mintuition, 51) ) cleanup("can't install hdlr.\n");
	handler_installed = 1;
	printf("handler installed (not stealing).\n");

	/*
	 * initialize double view setup
	 */
	if (! (screen = IntuitionBase->FirstScreen)) cleanup("can't find screen\n");
	if ( ! initDV( &DV, screen ) ) cleanup("initDV failed!\n");
	dumpDV( &DV );

	/*
	 * set up to steal Intuition's pointer when the input is
	 * being stolen
	 */
	if ( ! setupSprite( &myspr) ) cleanup( "no sprite\n" );

	/* set up mouse limits and current position */
	maxxmouse = screen->Width - 1;
	if ( screen->ViewPort.Modes & HIRES ) maxxmouse /= 2;
	maxymouse = screen->Height - 1;
	mousey = mousex = 0;		/* you could probably pick up where 
								 * Intuition's pointer is.  too lazy.
								 */

	printf("mouselimits: %d/%d\n", maxxmouse, maxymouse );
	printf("wait_type: %d\n\n", wait_type );
	printf("press return to start,\n");
	printf(" ... and press MENUBUTTON to pause: ");fflush( stdout ); getchar();

	do 
	{
		/* tell the handler to start stealing input	*/
		ChangeSprite( NULL, &myspr.spr_SSprite, myspr.spr_Data );
		MoveSprite(  NULL, &myspr.spr_SSprite, (LONG ) mousex, (LONG ) mousey );

		hdlr_should_steal = 1;

		fflush( stdin );				/* my cheezy user interface		*/

		rp = selectDV( &DV, 0 );		/* get one of my views loaded	*/

		while ( ! hdlr_wants_out )
		{
			variousWait();

			/* only position differs in code for different buffers	*/
			if ( DV_CURRENT( &DV ) == 0 )
			{
				/* fill with a color that should never be seen	*/
				SetAPen( rp, 1L );
				RectFill( rp, 120L, 20L, 240L, 180L );

				SetAPen( rp, 2L );
				RectFill( rp, 120L, 20L, 240L, 180L );
			}
			else
			{
				/* fill with a color that should never be seen	*/
				SetAPen( rp, 1L );
				RectFill( rp, 340L, 20L, 460L, 180L );

				SetAPen( rp, 2L );
				RectFill( rp, 340L, 20L, 460L, 180L );
			}

			rp = swapDV( &DV );
		}

		/* I am here because input handler has told me (via 'hdlr_wants_out')
		 * that he is turning on the input stream again.
		 * Although we don't really need to, we demonstrate a
		 * method of syncronizing with the handler.
		 * He is frozen, waiting for me to signal him.
		 */
		hdlr_should_steal = 0;
		hdlr_wants_out = 0;
		Signal( (long) FindTask("input.device"), (long) SIGF_SINGLE );

		/* give back view to intuition	*/

		RethinkDisplay();
		WaitTOF();

		/* make sure Intuition re-establishes its pointer.
		 * it's possible here to tell Intuition to move its
		 * pointer to where mine ended up, but this demo
		 * is crowded enough.
		 */
		Forbid();	/* not sure that I can pass a NULL window pointer */
		if (IntuitionBase->ActiveWindow)
		{
			ClearPointer( IntuitionBase->ActiveWindow );
		}
		Permit();

		/* did I tell you about the bug in MoveSprite()?	*/
		printf("mousex/y: %d/%d\n", mousex - 1, mousey );
		printf("pause mode.  Press return to continue ('q' to quit).: ");
		fflush( stdout );

	} while ( (cc = getchar()) != 'q' );

	cleanup("success.\n");
}

/* 
 * there are several things you might try, besides the method
 * of waitDV().  This function supports command line
 * switching between some of the methods
 */
variousWait()
{
	switch ( wait_type )
	{
	case 0:
		waitDV( &DV );
		break;
	case 1:
		WaitTOF();
		break;
	case 2:
		return;
	case 3:
		WaitBOVP( DV.dv_Views[ DV_CURRENT( &DV ) ]->ViewPort );
		break;
	default:
		waitDV( &DV );
		printf("BAD WaitType\n");
	}
}

cleanup(str)
char	*str;
{
	if (str)				printf( str );
	if (handler_installed)	extractInputHandler();
	freeSPR( &myspr );
	if ( IntuitionBase )	CloseLibrary( IntuitionBase );
	if ( GfxBase )			CloseLibrary( GfxBase );
	freeDV( &DV );
	exit( 1 );
}


/* 
 * input handler
 * note that it decides for the application that menus are about
 * to happen.
 */
struct InputEvent *
Mintuition( ie )
struct InputEvent *ie;
{
	extern int	hdlr_should_steal;
	extern int	hdlr_wants_out;

	while (ie && hdlr_should_steal )
	{
		/* ... check for terminating events	... */
		if ( ie->ie_Class == IECLASS_RAWMOUSE ) 
		{
			/* ... track and handle the input you need ... */
			movePointer( ie );		/* as an example	*/

			if ( ie->ie_Code == IECODE_RBUTTON )
			{
				/* let the poller know I've got an issue */
				hdlr_wants_out = 1;

				/* synchronize with him	*/
				Wait( (long) SIGF_SINGLE );

				/* let the event through */
				if (! hdlr_should_steal ) break;
			}
		}

		ie = ie->ie_NextEvent;
	}
	return ( ie );		/* remants, if any , back to intuition 	*/
}

/* only called with class RAWMOUSE	*/
movePointer( ie )
struct InputEvent *ie;
{
	mousex += ie->ie_X;
	mousey += ie->ie_Y;

	if ( mousex < 0 ) mousex = 0;
	if ( mousey < 0 ) mousey = 0;

	if ( mousex > maxxmouse ) mousex = maxxmouse;
	if ( mousey > maxymouse ) mousey = maxymouse;

	/* did I tell you about the bug in MoveSprite()?	*/
	MoveSprite(  NULL, &myspr.spr_SSprite, (LONG) mousex - 1, (LONG) mousey );

	return ;
}

#define SPRTEXTTOP		(7)

/* returns 0 if failure	*/
setupSprite( spr )
struct SpritePortRast 	*spr;
{
	int	text_skip;
	int	sprheight;
	register struct RastPort	*rp;
	long	baseline;

	sprheight = 2 * SPRTEXTTOP + 3 * GfxBase->DefaultFont->tf_YSize;

	if ( initSPR( spr, sprheight, 0, 1 ) == -1 )  return ( 0 );

	rp = &spr->spr_RPort;

	text_skip = spr->spr_RPort.TxHeight;

	/* some rendered sprite visuals 	*/
	SetAPen( rp, ( LONG ) 1);
	Move( rp, 0L, 0L );
	Draw( rp, 15L, 0L );
	Move( rp, 0L, (LONG) sprheight - 1 );
	Draw( rp, 15L,(LONG) sprheight - 1 );
	SetAPen( rp, ( LONG ) 3);
	RectFill( rp, 0L, 1L, 15L, (LONG) sprheight - 2 );

	/* oops: I should set the font	*/
	SetAPen( rp, ( LONG ) 0);
	SetBPen( rp, ( LONG ) 1);

	baseline = SPRTEXTTOP + text_skip;
	Move( rp, 1L, baseline );
	Text( rp, "I", 1L );

	baseline += text_skip;
	Move( rp, 3L,  baseline );
	Text( rp, "&", 1L );

	baseline += text_skip;
	Move( rp, 7L,  baseline );
	Text( rp, "I", 1L );

	return ( 1 );
}
