/*
 *	Handler.c - Copyright © 1991 by Devil's child.
 *
 *	Created:	30 Jun 1991  19:44:45
 *	Modified:	20 Jul 1991  19:47:14
 *
 *	Make>> make
 */

#include "ParMBase.h"

/*#define DEBUG */

struct ParMEvent {
	struct ParMEvent *pe_Next;
	struct Window *pe_Owner;
	USHORT pe_Code;
	USHORT pe_Qual;
	USHORT pe_Flags;
};


static struct MsgPort	*InputDevPort;
static struct IOStdReq  *InputRequestBlock;
static struct Interrupt HandlerStuff;
static struct ParMEvent *ParMEventList;


#ifdef DEBUG

static char output_buffer[128];

static struct IntuiText IText1 = {
	3,0,JAM2,		/* front and back text pens, drawmode and fill byte */
	7,13,			/* XY origin relative to container TopLeft */
	NULL,			/* font pointer or NULL for default */
	(UBYTE *)output_buffer,	/* pointer to text */
	NULL			/* next IntuiText structure */
};

static struct NewWindow NWS = {
	40,30,			/* window XY origin relative to TopLeft of screen */
	240,60,			/* window width and height */
	0,1,			/* detail and block pens */
	NULL,			/* IDCMP flags */
	WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+SIMPLE_REFRESH+NOCAREREFRESH,	/* other window flags */
	NULL,			/* first gadget in gadget list */
	NULL,			/* custom CHECKMARK imagery */
	(UBYTE *)"Handler Window",	/* window title */
	NULL,			/* custom screen pointer */
	NULL,			/* custom bitmap */
	5,5,			/* minimum width and height */
	-1,-1,			/* maximum width and height */
	WBENCHSCREEN	/* destination screen type */
};

static struct Window *DebugW;

#endif


static struct ParMEvent *FindParMEvent(USHORT Code, USHORT Qual)
{
	struct ParMEvent *ParMEvent;

	ParMEvent = ParMEventList;
	while(ParMEvent) {
		if (ParMEvent->pe_Code == Code && ParMEvent->pe_Qual == Qual)
			return ParMEvent;
		ParMEvent = ParMEvent->pe_Next;
	}
	return NULL;
}


BOOL AddParMEvent(struct Window *Win, USHORT Code, USHORT Qual, USHORT Flags)
{
	struct ParMEvent *ParMEvent;

	Qual |= IEQUALIFIER_RELATIVEMOUSE;	/* All events have this flag set */
	if (!(Flags & PEF_NOCHECK) && FindParMEvent(Code, Qual))
		return FALSE;
	Forbid();
	if (ParMEvent = AllocMem(sizeof(struct ParMEvent), MEMF_PUBLIC|MEMF_CLEAR)) {	
		ParMEvent->pe_Code = Code;
		ParMEvent->pe_Qual = Qual;
		ParMEvent->pe_Owner = Win;
		ParMEvent->pe_Flags = Flags;
		ParMEvent->pe_Next = ParMEventList;
		ParMEventList = ParMEvent;
	}
	Permit();
	return TRUE;
}


void RemParMEvents(struct Window *Win)
{
	struct ParMEvent *ParMEvent = ParMEventList, *LastEv;

	Forbid();
	LastEv = (struct ParMEvent *)&ParMEventList;
	while(ParMEvent) {
		if (ParMEvent->pe_Owner == Win) {
			LastEv->pe_Next = ParMEvent->pe_Next;
			FreeMem(ParMEvent, sizeof(struct ParMEvent));
		}
		else
			LastEv = ParMEvent;
		ParMEvent = LastEv->pe_Next;
	}
	Permit();
}


void HandlerInterface(void);

void InstallHandler(void)
{

#ifdef DEBUG
	DebugW = OpenWindow(&NWS);
#endif

	InputDevPort = CreatePort(0,0);
	InputRequestBlock = (struct IOStdReq *)CreateExtIO(InputDevPort, sizeof(struct IOStdReq));
	OpenDevice("input.device", 0, (struct IORequest *)InputRequestBlock, 0);
	HandlerStuff.is_Code = HandlerInterface;
	HandlerStuff.is_Node.ln_Name = "ParM Handler";
	HandlerStuff.is_Node.ln_Pri = 60;
	InputRequestBlock->io_Command = IND_ADDHANDLER;
	InputRequestBlock->io_Data = (APTR)&HandlerStuff;
	DoIO((struct IORequest *)InputRequestBlock);
}


void RemoveHandler(void)
{
	InputRequestBlock->io_Command = IND_REMHANDLER;
	InputRequestBlock->io_Data = (APTR)&HandlerStuff;
	DoIO((struct IORequest *)InputRequestBlock);
	CloseDevice((struct IORequest *)InputRequestBlock);
	FreeMem(InputRequestBlock, sizeof(struct IOStdReq));
	DeletePort(InputDevPort);

#ifdef DEBUG
	Forbid();
	CloseWindow(DebugW);
	DebugW = NULL;
	Permit();
#endif
}


static struct InputEvent *InputHandler(struct InputEvent *EventList, APTR data)
{
	struct Window *Win;
	struct ParMEvent *ParMEvent;
	struct InputEvent *ev = EventList, *LastEvent;
	BOOL SkipEvent;

	Forbid();
	LastEvent = (struct InputEvent *)&EventList;
	while (ev) {

#ifdef DEBUG
		if (DebugW && ev->ie_Class != IECLASS_TIMER) {
			SPrintf(output_buffer, "%lx    %lx    %lx    %lx",
					(long)ev->ie_Class,
					(long)ev->ie_SubClass,
					(long)ev->ie_Code,
					(long)ev->ie_Qualifier );
			PrintIText(DebugW->RPort, &IText1, 0, 0);
		}
#endif

		SkipEvent = FALSE;
		switch (ev->ie_Class) {
		case IECLASS_RAWMOUSE:
		case IECLASS_RAWKEY:
			if (ev->ie_Code == IECODE_NOBUTTON)	/* leave mouse moves */
				break;
			if (ParMEvent = FindParMEvent(ev->ie_Code, ev->ie_Qualifier)) {
				Win = ParMEvent->pe_Owner;
				if (ParMEvent->pe_Flags & PEF_SCREENTOFRONT)
					ScreenToFront(Win->WScreen);
				if (!(ParMEvent->pe_Flags & PEF_PASSTHROUGH))
					SkipEvent = TRUE;
				ActivateWindow(Win);
			}
			break;
		}
		if (SkipEvent)
			LastEvent->ie_NextEvent = ev->ie_NextEvent;
		else
			LastEvent = ev;
		ev = ev->ie_NextEvent;
	}
	Permit();
	return EventList;
}


#asm

	public	_geta4

_HandlerInterface:
	move.l	a4,-(sp)		; save a4
	movem.l	a0/a1,-(sp)		; push args
	jsr		_geta4			; get our private a4 to access global data
	jsr		_InputHandler	; call handler stuff
	addq.l	#8,sp			; pop args
	move.l	(sp)+,a4		; restore a4
	rts

#endasm

