#include <exec/types.h>
#include <exec/io.h>
#include <intuition/intuition.h>
#include <devices/conunit.h>

#define EOF -1
#define GRAPHICS_OLDREV  29
#define INTUITION_OLDREV 29
#define GRAPHICS_REV	 33
#define INTUITION_REV	 33

#define INTUITION_OPEN 1
#define GRAPHICS_OPEN  INTUITION_OPEN << 1
#define WINDOW_OPEN    GRAPHICS_OPEN  << 1
#define TMPRAS_OPEN    WINDOW_OPEN    << 1
#define READPORT_OPEN  TMPRAS_OPEN    << 1
#define CONREADER_OPEN READPORT_OPEN  << 1
#define CONDEVICE_OPEN CONREADER_OPEN << 1

#define RP mywindow->RPort	/* make life easy, since I use it a lot */

void myexit(), mysetup(), myprintf(), queueread();
int mygetc(), myscanf();
char *mygets();

extern struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

static struct IOStdReq *conreader, conrequest;
static struct MsgPort *conreadport;
struct Window *mywindow;
static struct TmpRas TRas;
static PLANEPTR TBuf;
extern char WindowTitle[];
extern char FillFlag;
static char buff[513];
static char conchar;
static int myflags;

char FillFlag;			/* whether or not to fill graphic objects */
static char Color;		/* drawing/filling color */
static char OldFlag;		/* using graphics.library before 1.2 */

static struct NewWindow NewWindow = {
   0,1,640,199,-1,-1,		/* left, top, width, height, detail, block pen */
   CLOSEWINDOW,
   WINDOWDEPTH | WINDOWDRAG | ACTIVATE,
   NULL, NULL, WindowTitle,
   NULL, NULL, 0, 0, 0, 0,	/* Min & Max size don't matter with no size gadget */
   WBENCHSCREEN };

/* initialize the window so we can read and write to it */
void mysetup()
{
   OldFlag = 0;

   if ((IntuitionBase = (struct IntuitionBase *)
      OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
	{
	if ((IntuitionBase = (struct IntuitionBase *)
	   OpenLibrary("intuition.library", INTUITION_OLDREV)) == NULL)
	   myexit(1);
	else OldFlag = 1;
	}

   myflags |= INTUITION_OPEN;

   if (OldFlag)
	{
	if ((GfxBase = (struct GfxBase *)
	   OpenLibrary("graphics.library", GRAPHICS_OLDREV)) == NULL)
	   myexit(2);
	}
   else
	{
	if ((GfxBase = (struct GfxBase *)
	   OpenLibrary("graphics.library", GRAPHICS_REV)) == NULL)
	   myexit(2);
	}

   myflags |= GRAPHICS_OPEN;

   if ((mywindow = (struct Window *)OpenWindow(&NewWindow)) == NULL)
      myexit(3);

   myflags |= WINDOW_OPEN;

/* create a TmpRas so we can do FloodFill calls */

   if ((TBuf = (PLANEPTR)AllocRaster(640,200)) == NULL)
      myexit(4);
   RP->TmpRas = (struct TmpRas *)InitTmpRas(&TRas,TBuf,RASSIZE(640,200));

   myflags |= TMPRAS_OPEN;

/* create a port to receive messages about completed operations */
   if ((conreadport = CreatePort("my.con.read", 0)) == NULL)
      myexit(5);

   myflags |= READPORT_OPEN;

/* construct a request for that port */
   if ((conreader = CreateStdIO(conreadport)) == NULL)
      myexit(6);

   myflags |= CONREADER_OPEN;

   conreader->io_Data = (APTR)mywindow;
   conreader->io_Length = sizeof(*mywindow);

   if (OpenDevice("console.device", 0, conreader, 0) != 0)
      myexit(7);

   myflags |= CONDEVICE_OPEN;

/* copy so we have a read request structure */
   conrequest.io_Device = conreader->io_Device;
   conrequest.io_Unit = conreader->io_Unit;

   queueread();
}

void myputc(c)	/* write a single character to our window */
char c;
{
   if (mywindow == NULL) mysetup();

   conrequest.io_Command = CMD_WRITE;
   conrequest.io_Data = (APTR)&c;
   conrequest.io_Length = 1;
   DoIO(&conrequest);
}

void queueread()
{
   conreader->io_Command = CMD_READ;
   conreader->io_Data = &conchar;
   conreader->io_Length = 1;
   SendIO(conreader);
}

int mygetc()
{
   struct IntuiMessage *GetMsg();
   char c = 0;

   if (mywindow == NULL) mysetup();

/* if there hasn't been a response to the last read request, wait for it */
   while((GetMsg(conreadport) == NULL)) WaitPort(conreadport);
/* get what the response character was */
   c = conchar;
/* and queue up for another one */
   queueread();
   return((c == 0x1c) ? EOF : c);
}

char *mygets()
{
   static char DELCHR[] = "\b \b";	/* String to DELete a CHaRacter */
   register char inchar;
   register int i,j;
   register int count = 0;
   register int ScrCount;
   int LnCount, MaxLnCount = 0;
   int InitCount = 0;

   if (mywindow == NULL) mysetup();

   myprintf("\x9b6n");			/* <CSI>6n - get current cursor pos */
   while (mygetc() != ';');		/*   returned as "<CSI>row;columnR" */
					/*   row & column returned as ASCII */
   while ((inchar = mygetc()) != 'R')
      InitCount = (InitCount * 10) + (inchar - '0');

   LnCount = ScrCount = InitCount;

   myprintf("\x9b q");			/* <CSI><space>q - window status request */
   for (i=0;i<3;i++)			/* returns window bounds in printable */
      while (mygetc() != ';');		/* characters, format:		     */
					/* <CSI>top line,first char,bottom line,last char<space>r */
   while ((inchar = mygetc()) != ' ')
      MaxLnCount = (MaxLnCount * 10) + (inchar - '0');

   mygetc();				/* throw away the 'r' */

   buff[0] = NULL;

   do {
      switch (inchar = mygetc()) {
	 case '\b' :			/* Backspace handling */
	    if (count == 0)
	       break;
	    if (buff[--count] == '\t') {
	       i = buff[--count];
	       ScrCount -= i;
	       LnCount = ((LnCount - i) >= 0) ? (MaxLnCount - i) : (LnCount - i);
	       for(j=i;j>0;j--)
		  myprintf("%s",DELCHR);
	    } else {
	       ScrCount--;
	       LnCount = ((LnCount - 1) >= 0) ? MaxLnCount : 0;
	       myprintf("%s", DELCHR);	/* Got to use myprintf to avoid newline */
	    }
	    break;
	 case '\t' :			/* tab character */
	    if (count < 256) {
	       i = 9-(LnCount%8);
	       if ((LnCount + i) > MaxLnCount) {
		  i = MaxLnCount - LnCount + 1;
		  LnCount = 1;
	       } else LnCount += i;
	       ScrCount += i;
	       buff[count++] = i;
	       buff[count++] = '\t';
	       for(j=0;j<i;j++) myputc(' ');
	    }
	    break;
	 case '\r' :
	    buff[count] = '\r';
	    myputc('\n');
	    break;
	 case 0x18 :			/* This is handling of ^X */
	    if (count == 0)
	       break;
	    myprintf("\x9b0 p");	/* turn cursor off */
	    for (; ScrCount > InitCount; ScrCount--)
	       myprintf("%s", DELCHR);
	    myprintf("\x9b p");		/* turn cursor on */
	    count = 0;
	    LnCount = InitCount;
	    buff[0] = NULL;
	    break;
	 default :
	    if ((count < 256) && (inchar > 31)) {
	       myputc(inchar);
	       ScrCount++;
	       LnCount = ((LnCount + 1) > MaxLnCount) ? 0 : (LnCount + 1);
	       buff[count++] = inchar;
	    }
      }
   } while (inchar != '\r');

   buff[count] = '\0';
   for(i=count-1;i>0;i--)
      if(buff[i] == '\t') {
	 for(j=i-1;j<count;j++)
	    buff[j] = buff[j+1];
         i--;
      }
   return(buff);
}

int myscanf(str,v1,v2,v3,v4,v5,v6,v7,v8,v9)
char *str;
long *v1,*v2,*v3,*v4,*v5,*v6,*v7,*v8,*v9;
{
   return(sscanf(mygets(),str,v1,v2,v3,v4,v5,v6,v7,v8,v9));
}

void myputs(str)	/* write a string to our window */
char *str;
{
   if (mywindow == NULL) mysetup();

   conrequest.io_Command = CMD_WRITE;
   conrequest.io_Data = (APTR)str;
   conrequest.io_Length = strlen(str);
   DoIO(&conrequest);
   myputc('\n');	/* don't forget the newline for the string */
}

/* write a formatted string to our window */
void myprintf(str,v1,v2,v3,v4,v5,v6,v7,v8,v9)
char *str;
long v1,v2,v3,v4,v5,v6,v7,v8,v9;
{
   char buff[256];

   if (mywindow == NULL) mysetup();

   conrequest.io_Command = CMD_WRITE;
   conrequest.io_Data = (APTR)buff;
   conrequest.io_Length = sprintf(buff,str,v1,v2,v3,v4,v5,v6,v7,v8,v9);
   DoIO(&conrequest);
}

/* close up everything and leave the program */
void myexit(code)
int code;
{
   if (myflags && CONDEVICE_OPEN) CloseDevice(conreader);
   if (myflags && CONREADER_OPEN) DeleteStdIO(conreader);
   if (myflags && READPORT_OPEN) DeletePort(conreadport);
   if (myflags && TMPRAS_OPEN) FreeRaster(TBuf,640,200);
   if (myflags && WINDOW_OPEN) CloseWindow(mywindow);
   if (myflags && GRAPHICS_OPEN) CloseLibrary(GfxBase);
   if (myflags && INTUITION_OPEN) CloseLibrary(IntuitionBase);
   _exit(code);
}

/****************************************************************
 *								*
 *		Utility Graphics Routines			*
 *	Copyright (C) 1986 by Limited Reality, Inc.		*
 *								*
 ****************************************************************/

Line(x1,y1,x2,y2,c)	/* draw a line from (x1,y1) to (x2,y2) */
int x1,y1,x2,y2;
char c;
{
	if(c != Color) SetAPen(RP,(Color = c));
	Move(RP,x1,y1);
	Draw(RP,x2,y2);
}

Circle(cx,cy,r,c)	/* draw a circle with center at (cx,cy), radius r */
int cx,cy,r;
char c;
{
	if(c != Color) SetAPen(RP,(Color = c));
	if (OldFlag)		/* if you're using something older than 1.2 */
		{
		int dx,dy,change,delta;

		dx = 0;
		dy = r;

		change = 2-2*dy;

		while (dy >= 0)
			{
			WritePixel(RP,cx+dx,cy-(dy/2));
			WritePixel(RP,cx+dy,cy+(dx/2));
			WritePixel(RP,cx-dx,cy+(dy/2));
			WritePixel(RP,cx-dy,cy-(dx/2));

			if (change <= 0)
				{
				delta = 2*change+2*dy-1;
				dx++;
				change = change+2*dx+1;
				if (delta > 0)
					{
					dy--;
					change = change-2*dy+1;
					}
				}
			else
				{
				delta = 2*change-2*dx-1;
				dy--;
				change = change-2*dy+1;
				if (delta <= 0)
					{
					dx++;
					change = change+2*dx+1;
					}
				}
			}
		}
		if (FillFlag) Fill(cx,cy,c);
	else
		{
		if (FillFlag)
			AreaEllipse(RP,cx,cy,r,r/2);
		else
			DrawEllipse(RP,cx,cy,r,r/2);
		}
}

Box(tlx,tly,brx,bry,c)	/* draw a box with top left corner at (tlx,tly) */
int tlx,tly,brx,bry;	/* 	   and bottom right corner at (brx,bry) */
char c;
{
	if(c != Color) SetAPen(RP,(Color = c));
	if (FillFlag)
		{
		RectFill(RP,tlx,tly,brx,bry);
		}
	else
		{
		Move(RP,tlx,tly);
		Draw(RP,tlx,bry);
		Draw(RP,brx,bry);
		Draw(RP,brx,tly);
		Draw(RP,tlx,tly);
		}
}

Fill(x,y,c)		/* flood fill an area with (x,y) as the center */
SHORT x,y;
char c;
{
	if(c != Color) SetAPen(RP,(Color = c));
	Flood(RP,1,x,y);
}

PSet(x,y,c)		/* set point at (x,y) */
int x,y;
char c;
{
	if(c != Color) SetAPen(RP,(Color = c));
	WritePixel(RP,x,y);
}

PReset(x,y)		/* reset a point at (x,y) to background color */
int x,y;
{
	SetAPen(RP,0);
	WritePixel(RP,x,y);
	Color = 0;
}
