/********************************************************************
 ** REALLY SLOPPY TEST SERVER - BUT IT GIVES AN IDEA ON THE EASE
 **
 ** (c) Spak Inc, Darrell Tam, c9107253@ee.newcastle.edu.au (1994)
 ** phone (Australia) 049-829-710
 **                   +49-829-710
 **
 ** (c) SST Scientific Endeavours 1994
 **
 ** LITTLE TEST CLIENT (A "SERVER") FOR RECEIVING & SENDING
 **
 ** BE CAREFUL TO THOROUGHLY TEST YOUR PROGRAMS BECAUSE BADLY FORMED
 ** OR PACKETS BEING USED TWICE AT THE SAME TIME WILL CAUSE THE
 ** SERVER TO PROBABLY DIE - MAKESURE A PACKET IS NOT IN USE BEFORE
 ** SENDING IT (IE WAIT FOR THE REPLY!!!!) AND ALWAYS USE THE SUPPLIED
 ** CALLS (actually #define's) TO INIT THE PACKETS
 **
 **
 ** TABS to 4
 ********************************************************************/

#include "/snd/everything.h"
#include "/snd/gfxthings_protos.h"
#include <st/st_proto.h>
#include <st/gadsetup.h>
#include "/par/parstuff.h"
#include "gfxstuff_protos.h"



long out;
struct	IntuitionBase *IntuitionBase = NULL;
struct	GfxBase *GfxBase = NULL;
short	destmachine;
short	running = 1;
short	ourserviceport = SERV_TEST;
struct MsgPort *port = NULL, *theport = NULL, *repport = NULL, *pktport = NULL;

short	pressed;

short lx, ly;



/** SOME PACKET STUFF */
struct Req {
	/** from here on must be < 118 bytes if it is to fit with the header */
#define REQ_SIZE(a) (sizeof(struct StdReq)+4+1+1+(((a)->n)<<1))

	struct	StdReq sr;
	long	type;
	char	lobotomy;
	char	n;							/* number of shorts following */
	short	xy[20];						/* number of coords (up to 10)*/
};

struct WhatchaPkt {
	struct	PktMsg pm;
	struct	Req sr;
}  wp[2];								/* double buffered */
short which_wp = 0;
short sent_wp = 0;						/* if any packet is sent out */
short lastx, lasty;


/********************************************************************/
	void MaybeSendCurrentPkt(void)
/********************************************************************/
{
struct WhatchaPkt *p = &wp[which_wp];

/** SEND OUT THE PACKET IF THE OTHERONE ISN'T OUT, AND THERE IS SOMETHING
 ** IN THIS PACKET */

	if(!sent_wp && p->sr.n) {
		sent_wp = 1;
		PREP_PKTMSG_ORIGINAL(&p->pm, destmachine, ourserviceport,
			&p->sr, sizeof(struct Req), /*REQ_SIZE(&p->sr),*/
			NULL, 0,
			NULL, 0,
			NULL, 0);

		PutMsg(pktport, p);

				{
				struct Req *r = &p->sr;
				short	i;
					SetAPen(win1->RPort, 1);
					for(i = 0,
						Move(win1->RPort, r->xy[i++]-1, r->xy[i++]-1); i < r->n;
							Draw(win1->RPort,  r->xy[i++]-1, r->xy[i++]-1));
				}

		which_wp ^= 1;					/* swap packets */
		wp[which_wp].sr.n = 0;			/* and start it off at 0 */
	}
}

/********************************************************************/
	void NewCoordSeries(short x, short y)
/********************************************************************/
{
struct Req *r = &wp[which_wp].sr;
	r->n = 0;		/* we may lose coords off the last pkt.... fix later */
	r->xy[r->n++] = x; r->xy[r->n++] = y;
	r->xy[r->n++] = x; r->xy[r->n++] = y;
	lastx = x; lasty = y;
	MaybeSendCurrentPkt();
}

/********************************************************************/
	short AddCoord(short x, short y)
/********************************************************************/
{
struct Req *r = &wp[which_wp].sr;
short ret = 1;
	if(r->n == 0) {
		r->xy[r->n++] = lastx; r->xy[r->n++] = lasty;
	}
	if(r->n < 20) {
		r->xy[r->n++] = x; r->xy[r->n++] = y;
		lastx = x; lasty = y;
	}
	else ret = 0;

	MaybeSendCurrentPkt();
	return(ret);
}


/********************************************************************/
						long HandleWin1(void)
/********************************************************************/
{
struct	IntuiMessage *im;
long	last;
	while (im = (struct IntuiMessage *)GetMsg(win1->UserPort)) {
		switch(last = DoGadgets(&win1gadhold, im)) {
			case 0:
			case -1: break;

			case IDCMP_CLOSEWINDOW:
				LoadRGB4(&(win1->WScreen->ViewPort), savecols, 4);
				ReplyMsg((struct Message *)im);
				running = 0;
				return last;

			case IDCMP_NEWSIZE:
				break;

			case IDCMP_ACTIVEWINDOW:
				WindowToFront(win1);
				SaveCols(win1, savecols, 32);
				LoadRGB4(&(win1->WScreen->ViewPort), win1cols, 4);
				break;

			case IDCMP_INACTIVEWINDOW:
				LoadRGB4(&(win1->WScreen->ViewPort), savecols, 4);
				break;

			case IDCMP_MOUSEBUTTONS:    /* pass back if no gadget was held */
				if(im->Code & IECODE_LBUTTON) {
					if(im->Code & IECODE_UP_PREFIX) {
						pressed = 0;
						SetAPen(win1->RPort, 2);
						Move(win1->RPort, lx, ly);
						Draw(win1->RPort, im->MouseX, im->MouseY);
						AddCoord(im->MouseX, im->MouseY);
						ReportMouse(0, win1);
					}
					else {
						pressed = 1;
						ReportMouse(1, win1);
						NewCoordSeries(lx = im->MouseX, ly = im->MouseY);
					}
				}
				break;

			case IDCMP_MOUSEMOVE:
				if(pressed) {
					SetAPen(win1->RPort, 2);
					Move(win1->RPort, lx, ly);
					Draw(win1->RPort, im->MouseX, im->MouseY);
					AddCoord(im->MouseX, im->MouseY);
					lx = im->MouseX; ly = im->MouseY;
				}
				break;

			default:
				break;
		}
		ReplyMsg((struct Message *)im);
	}
	return last;
}




/********************************************************************/
	int main(int argc, char *argv[])
/********************************************************************/
{
	out = Output();

	destmachine = argv[1][0];

	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0))
	|| !(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0)) )
			goto nomore;

	if(!OpenGfx()) goto nomore;

	if(!(port = CreatePort(0,0)) ||			/* service port */
	   !(repport = CreatePort(0,0))) {		/* reply port */
		fpf(out, "No ports\n");
		goto nomore;
	}

	if(!(theport = FindPort("ParRegister")) ||
		!(pktport = FindPort("ParServer"))) {
		fpf(out, "Couldn't find par port packet thingy\n");
		goto nomore;
	}

/** REGISTER WITH THE PARALLEL THING */
{
struct RegisterMsg rm;
	INIT_REGISTERMSG(&rm, port, RM_ADD_SERVER, ourserviceport, port, NULL); 
	PutMsg(theport, &rm); WaitPort(port); GetMsg(port);
	if(rm.smsg.result != (long)port) {
		fpf(out, "Another service already has this port\n");
		goto nomore;
	}
	fpf(out, "Registered ok as port service (%ld)\n", ourserviceport);
}



	fpf(out, "network Window server: commands sent to '%lc'\n", destmachine);


	dbzero(wp, sizeof(wp));
	INIT_MSG(&wp[0].pm.smsg.msg, port, sizeof(struct PktMsg));
	INIT_MSG(&wp[1].pm.smsg.msg, port, sizeof(struct PktMsg));


/** SIT IN A LOOP ON OUR PORT OR DIE ON CTRL C */
{
long mask, waitmask, pmask, rmask, winmask;
struct PktMsgRecv *pmr;

	waitmask =	(pmask = 1<<port->mp_SigBit) |
				(rmask = 1<<repport->mp_SigBit) |
				(winmask = 1<<win1->UserPort->mp_SigBit) |
				SIGBREAKF_CTRL_C;

/** CAN'T QUIT WITH PACKETS ROAMING AROUND */
	while(sent_wp != 0 || running) {

		mask = Wait(waitmask);

		if(mask & pmask) {
			while(pmr = (struct PktMsgRecv *)GetMsg(port)) {

			/** WE GOT SOMETHING SENT TO US */
				if(pmr->pm.smsg.type == TYPE_RECEIVED) {
				struct Req *r = (void *)pmr->req_body;
				short	i;
					SetAPen(win1->RPort, 1);
					for(i = 0,
						Move(win1->RPort, r->xy[i++], r->xy[i++]); i < r->n;
							Draw(win1->RPort,  r->xy[i++], r->xy[i++]));

				/*	INIT_MSG(&pmr->pm.smsg.msg,  repport, sizeof(*pmr)); */
					FREE_PKTMSGRECV(pmr);
				}

			/** WE GOT ONE OF OUR OWN BACK */
				else if(pmr->pm.smsg.type == TYPE_RETURN) {
					if(((long)pmr == (long)&wp[0]) || ((long)pmr == (long)&wp[1])) {
						sent_wp = 0;
						MaybeSendCurrentPkt();
					}
				}

			/** SERVER IS SHUTTING DOWN */
				else if(pmr->pm.smsg.type == TYPE_QUIT) {
					running = 0;
					ReplyMsg(pmr);
				}
			}
		}

		if(mask & rmask) {
			while(pmr = (struct PktMsgRecv *)GetMsg(repport)) {
				fpf(out, "Done: %lx\n", pmr);
			}
		}

		if(mask & winmask) HandleWin1();
		if(mask & SIGBREAKF_CTRL_C) running = 0;
	}
}


endourpain:

/** REMOVE US AS A SERVER FROM THE THING */
	fpf(out,"Quitting... (telling server) ");
{
struct RegisterMsg rm;
struct Message *maj;

	INIT_REGISTERMSG(&rm, port, RM_REMOVE_SERVER, ourserviceport, NULL, NULL); 
	for(PutMsg(theport, &rm); (WaitPort(port), (maj = GetMsg(port)) != &rm);)
					ReplyMsg(maj); /* important to return all messages but ours */
}
	fpf(out,"Done\n");

nomore:
	CloseGfx();
	if(port) DeletePort(port);
	if(repport) DeletePort(repport);
	if(GfxBase) CloseLibrary((struct Library *)GfxBase);
	if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
	return(0);
}

