#include <exec/types.h>
#include <dos/dos.h>
#include <stdio.h>
#include <string.h>
#include <intuition/intuition.h>

#include <clib/exec_protos.h>
#include <clib/Intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/alib_protos.h>

#include "/include/GTDriverMPC.h"

#define NOPUBPORT 	-1

void PrintMsg(struct TabletMessage *Tmsg);
void CloseAll(char *msg);
short SendCommand(ULONG comm, ULONG data);

struct Library *IntuitionBase = NULL;
struct Library *GfxBase = NULL;
struct MsgPort *myport = NULL,*port = NULL,*repport = NULL;
struct Window *wnd = NULL;
struct TabletCommand Tcmd;
ULONG  Temp;
short  xb,yb,fontheight;
struct RastPort *rp;
struct GTDPrefs PData;

main()
{
	struct TabletMessage *Tmsg;
	char stayin = TRUE;
	ULONG WaitMask;
	short ret;

	/*
	 * Open Intuition and Graphics library
	 */
    IntuitionBase = OpenLibrary("intuition.library",36L);
 	if (! IntuitionBase) CloseAll("Unable to open V36 Inuition Library\n");

	GfxBase = OpenLibrary("graphics.library",36L);
 	if (! GfxBase) CloseAll("Unable to open V36 Gfx Library\n");

	/*
	 * Now let's open the window to display data
	 */
	wnd = OpenWindowTags(NULL, WA_Left,0, WA_Top,0, WA_Width,200, WA_Height,100,
	 			WA_DragBar,TRUE, WA_SmartRefresh,TRUE, WA_NoCareRefresh,TRUE,
	 			WA_CloseGadget, TRUE, WA_IDCMP, IDCMP_CLOSEWINDOW,
			 	WA_Title,"ShowCoords", TAG_END);
	if (!wnd) CloseAll("Unable to open window\n");

	rp = wnd->RPort;
	xb = wnd->BorderLeft + 4;
	yb = wnd->BorderTop + rp->Font->tf_Baseline + 4;
	fontheight = rp->Font->tf_YSize;
	SetAPen(rp,1);

	/*
	 * Create message port to get messages from driver
	 */
	myport = CreateMsgPort();
	if (! myport) CloseAll("Unable to create message port\n");

	/*
	 * Create Msg port to receive replies to command sent to the driver
	 */
	repport = CreateMsgPort();
	if (! repport) CloseAll("Unable to create message port\n");

	/*
	 * Send command to driver: Get driver preferences: Prefs will be
	 * filled with driver settings
	 */

	ret  = SendCommand(MPC_GETPREFS,(ULONG )&PData);
	if(ret == NO_PUBPORT) CloseAll("Unable to find "GTDPUBPORTNAME".\n");
	else if (ret == COMMAND_FAILED) CloseAll("Unable to get driver prefs.\n");
	printf("Driver version: %2f\n",PData.Version);
	printf("Working mode:   %s\n",(PData.Mode == MODE_SERVER) ? "server" : "driver");
	printf("Emulation:      %s\n",PData.Emulation);
	printf("Init string:    %s\n",PData.InitString);
	printf("Baud Rate:      %d\n",PData.Baud);
	printf("Priority:       %d\n",PData.Priority);
	printf("DPI:            %d\n",PData.DPI);
	printf("Metric:         %s\n",(PData.Metric == METRIC_CM)? "centimeters" : "inches");
	printf("Dimensions:     %.2f %.2f\n",PData.XDim,PData.YDim);
	printf("Clip region:    (%.2f,%.2f)-(%.2f,%.2f)\n",PData.ULC_x,PData.ULC_y,PData.LRC_x,PData.LRC_y);
	if (PData.SwapXY) printf("X and Y axes swapped\n");
	if (PData.MirrorX) printf("X axis mirrored\n");
	if (PData.MirrorY) printf("Y axis mirrored\n");

	/*
	 * Send command to driver: switch to server mode
	 */
	ret = SendCommand(MPC_SERVERMODE,(ULONG )myport);
	if(ret == NO_PUBPORT) CloseAll("Unable to find "GTDPUBPORTNAME".\n");
	else if (ret == COMMAND_FAILED) CloseAll("Unable to switch to server mode\n");
	/*
	 * Main event loop
	 */
	WaitMask = (SIGBREAKF_CTRL_C | (1L << myport->mp_SigBit) | (wnd->UserPort->mp_SigBit));
	do{
		/*
		 * Now wait for a CTRL-C,the close gadget or a message from GTDriver; if
		 * is a CTRL-C or the close gadget exit, else print the message data in the
		 * window
	 	*/
		Temp = Wait(WaitMask);
		if (Temp & SIGBREAKF_CTRL_C)
			stayin = FALSE;
		if (Temp & (wnd->UserPort->mp_SigBit)) {
			WaitPort(wnd->UserPort);
			stayin = FALSE;
		}
		if (Temp & (1L << myport->mp_SigBit)){
			while(Tmsg = (struct TabletMessage *)GetMsg(myport)){
				PrintMsg(Tmsg);
				ReplyMsg((struct Message *)Tmsg);
				Temp = SetSignal(0,0);
				if (Temp & SIGBREAKF_CTRL_C){
					stayin=FALSE;
					SetSignal(0,SIGBREAKF_CTRL_C);
					break;
				}
			}
		}
	}while(stayin);
	/*
	 * switch again to driver mode this can't fail because we own
	 * the driver!.
	 */

	ret = SendCommand(MPC_DRIVERMODE,0L);
	if(ret == NO_PUBPORT) CloseAll("Unable to find "GTDPUBPORTNAME". Someone already closed GTDriver ?\n");
	else if (ret == COMMAND_FAILED) CloseAll("Unable to switch to server mode.\n");


	while (Tmsg = (struct TabletMessage *)GetMsg(myport))
		ReplyMsg((struct Message *)Tmsg);

	CloseAll("Program ended. All right\n");
}

void CloseAll(char *msg)
{
	printf(msg);
	if (wnd) CloseWindow(wnd);
	if (repport) DeleteMsgPort(repport);
	if (myport) DeleteMsgPort(myport);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
	if (GfxBase) CloseLibrary(GfxBase);
	exit(0);
}


void PrintMsg(struct TabletMessage *Tmsg)
{
	char buff[32];

	switch(Tmsg->type){
		case TMTYPE_COORDS:
			sprintf(buff,"Coords:  (%d,%d)   ",Tmsg->x,Tmsg->y);
			Move(rp,xb,yb);
			if (Tmsg->x < PData.ULC_x || Tmsg->x > PData.LRC_x || Tmsg->y < PData.ULC_y || Tmsg->y > PData.LRC_y)
				SetAPen(rp,2);
			else
				SetAPen(rp,1);
			Text(rp,buff,strlen(buff));
			sprintf(buff,"Buttons: %X        ",Tmsg->buttons);
			Move(rp,xb, yb+fontheight*1);
			Text(rp,buff,strlen(buff));
			break;
		case TMTYPE_PBUTTON:
			sprintf(buff,"Pbutton: %c       ",Tmsg->key);
			SetAPen(rp,1);
			Move(rp,xb, yb+fontheight*2);
			Text(rp, buff, strlen(buff));
			break;
	}
}

short SendCommand(ULONG comm, ULONG data)
{
	/*
	 * Initialize the TabletCommand structure to set GTDriver to
	 * work sending data to this program (to myport).
	 */
	Tcmd.msg.mn_Node.ln_Type = NT_MESSAGE;
	Tcmd.msg.mn_ReplyPort = repport;
	Tcmd.msg.mn_Length = sizeof(struct TabletCommand);
	Tcmd.Command = comm;
	Tcmd.Data = (void *)data;

	/*
	 * Search the GTDriver message port and set it to use my message port
	 */
	Forbid();
	port = FindPort(GTDPUBPORTNAME);
	if (! port){
		Permit();
		return NO_PUBPORT;
	}
	PutMsg(port,(struct Message *)&Tcmd);
	Permit();
	WaitPort(repport);
	GetMsg(repport);
	return (short )Tcmd.Command;
}