/*==========================================================================*
 * gport.c - gameport handling code for Discovery                           *
 *==========================================================================*/

#include "welcome.h"
#include <devices/gameport.h>

#define XMOVE 1
#define YMOVE 1

/* our functions */

void wrap_gameport(void);
void send_read_request(void);
void flush_gport(void);

extern struct Process		*myprocess;

struct InputEvent			game_event;   /* where input event will be stored */
struct IOStdReq				*game_io_msg = NULL;
struct MsgPort  			*game_msg_port = NULL;

/* trigger on all joystick key transitions */
struct GamePortTrigger joytrigger = {
    GPTF_UPKEYS+GPTF_DOWNKEYS,
    2000,
    XMOVE,
    YMOVE
};

BOOL		GUnitOpened = FALSE,
			GPortOpened = FALSE;

	/* init gameport specifically for relative joystick */
BOOL init_gameport(void)
{
	BYTE data = 0;

	game_msg_port = CreatePort(NULL,0);
	if (game_msg_port == NULL) return FALSE;

	game_io_msg = CreateStdIO(game_msg_port);
	if (game_io_msg == NULL) goto fail;

	if (OpenDevice("gameport.device",1,(struct IORequest *)game_io_msg,0)) goto fail;

	GPortOpened = TRUE;

	Forbid();    /*critical section start */
	game_io_msg->io_Command = GPD_ASKCTYPE;    /* inquire current status */
	game_io_msg->io_Length = 1; 
	game_io_msg->io_Flags = IOF_QUICK;
	game_io_msg->io_Data = (APTR)&data; /* put answer in here */
	DoIO((struct IORequest *)game_io_msg);

		/* No one is using this device unit, let's claim it */
	if (data == GPCT_NOCONTROLLER)
    {
		data = GPCT_ABSJOYSTICK;
	    game_io_msg->io_Command = GPD_SETCTYPE;
    	game_io_msg->io_Flags = IOF_QUICK;   
	    game_io_msg->io_Length = 1;
	    game_io_msg->io_Data = (APTR)&data;
	    DoIO((struct IORequest *)game_io_msg);
	    GUnitOpened = TRUE;
    }

	Permit(); /* critical section end */

	if (GUnitOpened == FALSE) goto fail;

	game_io_msg->io_Command = GPD_SETTRIGGER;   
   	game_io_msg->io_Flags = 0;
	game_io_msg->io_Length = sizeof(struct GamePortTrigger);   
	game_io_msg->io_Data = (APTR)&joytrigger;   
	DoIO((struct IORequest *)game_io_msg);

	flush_gport();

	send_read_request();

	return TRUE;

fail:
	wrap_gameport();
	return FALSE;
}

BOOL	last_mouse = 0,
		ticker = 0;

extern WORD skipped;

void gport1_handler(struct in_work *mydata)
{	short				nextput;

	if (GetMsg(game_msg_port))
	{
		last_mouse = 0;

		mydata->xjoy = game_event.ie_X;
		mydata->yjoy = game_event.ie_Y;

		nextput = (mydata->laydown + 1) & 127;
		if (nextput != mydata->pickup && (game_event.ie_Code == IECODE_LBUTTON || game_event.ie_Code == IECODE_RBUTTON))
		{
				/* if it's a right button click, then set skipped to 2, else
					set it to -1
				*/

			if (game_event.ie_Code == IECODE_RBUTTON) skipped = 2;
			else skipped = TRUE;

			Signal(&myprocess->pr_Task,SIGBREAKF_CTRL_C);

			mydata->keybuf[mydata->laydown] = RETURN;
			mydata->laydown = nextput;
		}

		send_read_request();
	}

	if (last_mouse == 1)
	{
		if (ticker == 1)
		{
			mydata->xjoy = mydata->yjoy = ticker = 0;
		}
		else ticker = 1;
	}
}

#define sign(a)			( ((a) > 0) - ((a) < 0) )

void gport0_handler(struct in_work *mydata,struct InputEvent *ev)
{	short				nextput;

	last_mouse = 1;
	mydata->xjoy = sign(ev->ie_X);
	mydata->yjoy = sign(ev->ie_Y);

	nextput = (mydata->laydown + 1) & 127;
	if (nextput != mydata->pickup && (ev->ie_Code == IECODE_LBUTTON || ev->ie_Code == IECODE_RBUTTON))
	{
		if (ev->ie_Code == IECODE_RBUTTON) skipped = 2;
		else skipped = TRUE;

		Signal(&myprocess->pr_Task,SIGBREAKF_CTRL_C);

		mydata->keybuf[mydata->laydown] = RETURN;
		mydata->laydown = nextput;
	}
}

void flush_gport(void)
{
	game_io_msg->io_Command = CMD_CLEAR;
	game_io_msg->io_Flags = IOF_QUICK;
	DoIO((struct IORequest *)game_io_msg);
}

void send_read_request(void)
{
	game_io_msg->io_Command = GPD_READEVENT;   
	game_io_msg->io_Length = sizeof(struct InputEvent); 
	game_io_msg->io_Data = (APTR)&game_event;
	SendIO((struct IORequest *)game_io_msg);  /* Asynchronous - message will return later */
}

void wrap_gameport(void)
{
	BYTE type = GPCT_NOCONTROLLER;

	if (GUnitOpened)
	{
		Forbid();
		if (GetMsg(game_msg_port) == NULL) AbortIO((struct IORequest *)game_io_msg);
		Permit();

		game_io_msg->io_Command = GPD_SETCTYPE;
		game_io_msg->io_Flags = IOF_QUICK;   
		game_io_msg->io_Length = 1;
		game_io_msg->io_Data = (APTR)&type;
		DoIO((struct IORequest *)game_io_msg);   
	}

	if (GPortOpened) CloseDevice((struct IORequest *)game_io_msg);
	if (game_io_msg) DeleteStdIO(game_io_msg);
	if (game_msg_port) DeletePort(game_msg_port);

	GUnitOpened = GPortOpened = FALSE;
	game_io_msg = NULL;
	game_msg_port = NULL;
}
