/* oscan.c -- overscan demo
 * 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 "oscan.h"

#include "getargs.h"

struct Screen *getScreen();
struct Window *getWindow();
struct BitMap *getHugeBitMap();

extern struct IntuitionBase	*IntuitionBase;

struct BitMap	*bmap = NULL;
struct Screen	*screen = NULL;
struct Window	*window = NULL;
struct View		*view;

SHORT			viewdx;		/* original values found in view Dx/yOffset	*/
SHORT			viewdy;

/* gadget stuff from oscreen.c	*/
extern UBYTE	oribuff0[];
extern UBYTE	oribuff1[];
extern struct StringInfo	mysi[];
#define OSCAN_VIEWX		(mysi[0].LongInt)
#define OSCAN_VIEWY		(mysi[1].LongInt)

/* cheat: won't work beyond V1.3	*/
#define MAXXMOUSE	(700)
#define MAXYMOUSE	(470)
SHORT orig_maxx;
SHORT orig_maxy;

/* idcmp flags */
ULONG	iflags = 
		GADGETUP| INTUITICKS| MENUPICK| MENUVERIFY|
		INACTIVEWINDOW| NEWPREFS| RAWKEY;

/* window flags */
ULONG	flags =
		ACTIVATE | NOCAREREFRESH | SIMPLE_REFRESH | BACKDROP | BORDERLESS ;

/* some extreme values for View.Dx/DyOffset	*/
#define	REASONABLE_DX	(96)
#define	REASONABLE_DY	(21)

/* tricky stuff */
#define NO_TRICK		(0)	/* means standard screen, standard position */
#define VIEWSHIFT_TRICK	(2)	/* shift the view, but don't poke Intuition	*/
#define CHEAT_TRICK		(1)	/* perform hack that won't be supported in future */

/* current and previous view states */
int		trick	=		NO_TRICK;	
int		lasttrick =		NO_TRICK;

int		numplanes = 1;

struct Arg myargs[] = {
	{'p', ARG_TINT, &numplanes, "number of bitplanes [1-4]"},
};

main(argc, argv)
char	**argv;
{
	struct IntuiMessage	*imsg;

    if ( getargs( argv, myargs, NUMARGS( myargs ), NULL) < 0 ) cleanup( NULL );

	/* --- open libraries ---								*/
	if (!OpenI( 33 )) cleanup( "no intuition\n");
	if (!OpenGfx( 33 )) cleanup("no graphics\n");

	view = ViewAddress();		/* for later tricks			*/
	viewdx = view->DxOffset;
	viewdy = view->DyOffset;

	/* initialize string gadgets 	*/
	mysi[0].LongInt = REASONABLE_DX;
	mysi[1].LongInt = REASONABLE_DY;

	sprintf( mysi[0].Buffer, "%ld", mysi[0].LongInt);
	sprintf( mysi[1].Buffer, "%ld", mysi[1].LongInt);
	sprintf( oribuff0, "orig. %d (0x%x)", viewdx, viewdx);
	sprintf( oribuff1, "orig. %d (0x%x)", viewdy, viewdy);

	/* --- allocate huge bitmap ---							*/
	if ( ! ( bmap = getHugeBitMap( numplanes ) ) ) cleanup( "no bitmap\n" );

	/* --- open "standard" screen/window on huge bitmap ---	*/
	if (!( screen = getScreen( bmap ) ) ) cleanup( "no screen\n" );

	if (!( window = getWindow( screen ) ) ) cleanup( "no window\n" );
	drawHugeBitMap( &screen->RastPort );

	/* --- top-level input processing ---					*/
	for (;;)
	{
		WaitPort( window->UserPort );
		imsg = (struct IntuiMessage *) GetMsg( window->UserPort );

		switch ( imsg->Class )
		{
		case GADGETUP:
			/* i guess i don't really care after all */
			break;

		case MENUPICK:
			/* using a single, simple menu	*/
			switch ( ITEMNUM( imsg->Code ) )
			{
			case 0:
				dotrick( VIEWSHIFT_TRICK );		/* view shift	*/
				break;

			case 1:
				dotrick( CHEAT_TRICK );		/* cheat, too.	*/
				break;

			case 2:
				printf("menupick untrick\n");
				untrick();
				break;

			case 3:		/* exit */
				ReplyMsg( imsg );
				cleanup( "all done\n" );

			default:				/* return to tricky mode	*/
				dotrick( lasttrick );
			}
			break;

		case INTUITICKS:
			/* thanks to David Joiner (talin) for this (un-)trick	*/
			if ( (trick != NO_TRICK) && (IntuitionBase->FirstScreen != screen) )
			{
				printf("tick untrick trick = %d\n", trick);
				untrick();
			}
			break;

		case MENUVERIFY:
			printf("menuverify untrick\n");
			untrick();
			break;

		case INACTIVEWINDOW:
			printf("inactive untrick\n");
			untrick();
			break;

		case NEWPREFS:
			/* be careful: untrick() causes another NEWPREFS message!	*/
			if ( trick != NO_TRICK )
			{
				printf("newprefs untrick\n");
				untrick();	/* haven't tested this too much	*/
			}
			break;

		default:
			break;
		}

		ReplyMsg( imsg );	/* must follow menuverify */
	}
}

dotrick( tr )
{
	if ( trick != NO_TRICK )
	{
		printf("dotrick untrick\n");
		untrick();
	}

	if ( IntuitionBase->FirstScreen != screen ) return;

	switch ( tr )
	{
	case CHEAT_TRICK:		/* cheap unsupportable hacks	*/
		/*
		 * save and change values of data fields which will
		 * not be used under V1.4
		 */
		orig_maxx = IntuitionBase->MaxXMouse;
		orig_maxy = IntuitionBase->MaxYMouse;

		IntuitionBase->MaxXMouse =			MAXXMOUSE;
		IntuitionBase->MaxYMouse =			MAXYMOUSE;
		IntuitionBase->MaxDisplayWidth =	MAXXMOUSE;
		IntuitionBase->MaxDisplayRow =		MAXYMOUSE;
		IntuitionBase->MaxDisplayHeight =	IntuitionBase->MaxDisplayRow + 1;

		/* fall through	*/

	case VIEWSHIFT_TRICK:		/* shifted view trick	*/
		view->DxOffset = OSCAN_VIEWX;
		view->DyOffset = OSCAN_VIEWY;
		RemakeDisplay();
		break;

	default:
		printf("bad dotrick untrick\n");
		untrick();
		tr = NO_TRICK;
	}

	/* ClearPointer will get Intuition to ChangeSprite(),
	 * and keep the pointer sync'd with display position.
	 *
	 * In a real application, I would use the address of my
	 * window within the large screen, and would try to insure
	 * that my window was active when I do this trick.
	 * It's not a big problem if this operation doesn't succeed:
	 * it corrects itself as soon as the user moves the mouse.
	 *
	 * This Forbid() stuff is because I'm not sure that I can
	 * pass a NULL to ClearPointer()
	 */
	Forbid();
	if (IntuitionBase->ActiveWindow) ClearPointer( IntuitionBase->ActiveWindow );
	Permit();

	lasttrick = trick = tr;
}

untrick()
{
	LONG	dummy;

	switch ( trick )
	{
	case CHEAT_TRICK:
		IntuitionBase->MaxXMouse =			orig_maxx;
		IntuitionBase->MaxYMouse =			orig_maxy;
		IntuitionBase->MaxDisplayWidth =	orig_maxx;
		IntuitionBase->MaxDisplayRow =		orig_maxy;
		IntuitionBase->MaxDisplayHeight =	IntuitionBase->MaxDisplayRow + 1;

		/* fall through	*/

	case NO_TRICK:
	case VIEWSHIFT_TRICK:
#if 0
		view->DxOffset = viewdx;
		view->DyOffset = viewdy;
#else
		/* this method intereracts less with other tricksters */
		GetPrefs( &dummy, (LONG) sizeof dummy );
		SetPrefs( &dummy, (LONG) sizeof dummy );
#endif
		RemakeDisplay();			/* fix up everybody	*/
		break;
	}
	trick = NO_TRICK;
}


cleanup( string )
char	*string;
{
	if ( string ) printf("%s", string);

	if ( window ) CloseWindow( window );
	if ( screen ) CloseScreen( screen );
	if ( bmap )	freeHugeBitMap( bmap );

	CloseI();
	CloseGfx();

	exit ( string? 1: 0 );		/* should I have said !!string ?	*/
}
