/*
     plot2am.c : Plot Unix plot files on an Amiga HIRES Screen.

	 By Joel Swank April, 1988

	 */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <intuition/intuition.h>
#include <stdio.h>
/*  The header files needed for gadget definitions  */ 
#include <intuition/intuitionbase.h> 
#include <libraries/dosextens.h> 
#include <graphics/gfxbase.h> 
#include <graphics/gfx.h> 
#include <graphics/gfxmacros.h> 
#include <graphics/display.h> 

#include <graphics/text.h> 
#include <devices/printer.h> 
#include <ctype.h> 

#include "plotview.h" 
#include "fileio.h"

#ifdef NULL
#undef NULL
#endif
#define NULL ((void *)0)

#define INTUITION_REV 1L

struct	TextAttr stdattr = {
    (STRPTR)("topaz.font"),
    8,
    0,
    FPB_DISKFONT};
struct	TextFont *stdfont = NULL;

struct	TextAttr myattr = {
    (STRPTR)("puny.font"),
    7,
    0,
    FPB_DISKFONT};
struct	TextFont *myfont = NULL;

 
/*
 * GLOBAL data definitions
 */
static struct Window	*Wind = NULL ;
static struct Screen	*MyScreen = NULL ;
struct FileIOSupport *FIOSupp = NULL;
extern struct IntuitionBase	*IntuitionBase ;
extern struct DosLibrary *DosBase ;
extern struct GfxBase *GfxBase ;
struct RastPort *rp;	/* Main window rastport */
struct RastPort *Srp;	/* Scale window rastport */
struct Library *DiskfontBase = NULL;
FILE *input;	/* input file pointer */

struct MsgPort	*CreatePort() ;
struct TextFont *OpenDiskFont() ;
struct TextFont *OpenFont() ;

/* scaling factors */

long xscale, yscale;    /* width, height of output device */
long xmult, ymult;      /* width, height on Amiga Screen */
long xoff, yoff;	    /* offset to lower left corner  */
long xscaleu, yscaleu;  /* user specified width, height of output device */
long xoffu, yoffu;	    /* user specified offset to lower left corner  */
int override = FALSE;   /* TRUE for use user specified */

/* linemode constants */

char *lmodestr[] = { "dotted",
                     "solid",
                     "longdashed",
                     "shortdashed",
                     "dotdashed" };

USHORT lmode[] = { 0xaaaa, 0xffff, 0xff00, 0xf0f0, 0xf2f2 };

char reqtitle[] = "Select an Input Plot File";

main(argc,argv)
int argc;
char *argv[];
{
long menunum;
char *p;

struct IntuiMessage	*msg;
 
/*************************************************
     Init defaults
*************************************************/

xscaleu = 3120;
yscaleu = 3120;
xmult = 550;
ymult = 400;
xoffu = 0;
yoffu = 0;

 
/*************************************************
     OPEN everything
*************************************************/

 
if ((IntuitionBase = (struct IntuitionBase *)
    OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
	done(21);

GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", NULL);
if (GfxBase == NULL) done(22);

DiskfontBase = (struct Library *)OpenLibrary("diskfont.library", NULL);
if (DiskfontBase == NULL) {
	fprintf(stderr,"plot2am:cannot open font library - using default font\n");
	}

if ((DosBase = (struct DosLibrary *)OpenLibrary("dos.library", 0)) == NULL)
	done(27);

if ((MyScreen = (struct Screen *) OpenScreen(&NewScreenStructure)) == NULL)
	done(23);

New_Window.Screen = MyScreen;

if ((Wind = (struct Window *) OpenWindow(&New_Window)) == NULL)
	done(25);
rp = Wind->RPort;

if (DiskfontBase != NULL) {
	if ((myfont = (struct TextFont *)OpenDiskFont(&myattr)) == NULL) {
		fprintf(stderr,"plot2am:cannot find puny font - using default\n");
	} else  SetFont(rp,myfont);
}

if (NULL == (FIOSupp = GetFileIOSupport()))
	done(26);



LoadRGB4(&(MyScreen->ViewPort),&Palette,PaletteColorCount);

/*************************************************
     Interrogate command line 
*************************************************/



while (argc > 1)
	{
	if ((input = fopen(argv[1],"r")) == NULL)
		fprintf(stderr,"plot2am: %s: open failed\n",argv[1]);
	else {
		strcpy(filename,argv[1]);
		draw_file(input);
		}
	argc--;
	argv++;
	}


SetMenuStrip(Wind,&MenuList1);
 
/*************************************************
     WAIT for Close Gadget or Menu Pick
*************************************************/

while (1)
	{
	Wait( 1L << Wind->UserPort->mp_SigBit);	/* wait on mesg */
	while(msg = (struct IntuiMessage *) GetMsg(Wind->UserPort)) {
		switch(msg->Class) {
			case MENUPICK:
				menunum = msg->Code;
				ReplyMsg(msg);
				if (menunum != MENUNULL) do_pick(menunum);
				continue;
			case CLOSEWINDOW:
				ReplyMsg(msg);
				done(0);
			}
			ReplyMsg(msg);
		}
	}
}

/*************************************************
     Parameter input routines
*************************************************/


/*
 * input a pair of 16 bit ints, scale
 * and return them as longs
 *
 */

get_xy(x,y)
register long *x, *y;
{
	get_int(x);
	*x = (*x-xoff)*xmult/xscale;
	get_int(y);
	*y = (YSIZE-1)-(*y-yoff)*ymult/yscale;
}

/*
 * input a 16 bit int and return as a long
 */

get_int(num)
long *num;
{
	register long hi, lo;
	lo = (long) getc(input);
	hi = ( (long) getc(input)) << 8;
	*num = lo + hi;
}

/*
 * input a text string delinited by newline,
 * return to buffer delimited by a null.
 */

get_txt(str)
char *str;
{
	register int cmd;
	while ((cmd = getc(input)) != '\n')
		*str++ = cmd;
	*str = '\0';
}

/*
 * done - just clean up that which is open, and then leave.
 */
done(how)
int how;
    {
    if (Wind) CloseWindow(Wind) ;
    if (MyScreen) CloseScreen(MyScreen) ;
    if (IntuitionBase) CloseLibrary(IntuitionBase) ;
    if (GfxBase) CloseLibrary(GfxBase) ;
    if (DiskfontBase) CloseLibrary(DiskfontBase) ;
	if (myfont   != NULL) CloseFont( myfont );
 
    OpenWorkBench() ;		/* As requested */
    exit(how) ;
    }

/*
 * arc and integer sqrt routines.
 * lifted from sunplot program by:

Sjoerd Mullender
Dept. of Mathematics and Computer Science
Free University
Amsterdam
Netherlands

Email: sjoerd@cs.vu.nl
If this doesn't work, try ...!seismo!mcvax!cs.vu.nl!sjoerd or
...!seismo!mcvax!vu44!sjoerd or sjoerd%cs.vu.nl@seismo.css.gov.

 *
 */

long
isqrt(n)
long n;
{
	long a, b, c;

	a = n;
	b = n;
	if (n > 1) {
		while (a > 0) {
			a = a >> 2;
			b = b >> 1;
		}
		do {
			a = b;
			c = n / b;
			b = (c + a) >> 1;
		} while ((a - c) < -1 || (a - c) > 1);
	}
	return b;
}


#define setcir(x, y, a1, b1, c1, a2, b2, c2) \
	{if (a1 * (y) - b1 * (x) >= c1 && a2 * (y) - b2 * (x) <= c2) \
	WritePixel(rp,x, y);}

arc(x, y, x1, y1, x2, y2)
long x, y, x1, y1, x2, y2;
{
	register long a1 = x1 - x, b1 = y1 - y, a2 = x2 - x, b2 = y2 - y;
	register long c1 = a1 * y - b1 * x, c2 = a2 * y - b2 * x;
	register long r2 = a1 * a1 + b1 * b1;
	register long i, sqrt;

	for (i = isqrt(r2 >> 1); i >= 0; i -= 1) {
		sqrt = isqrt(r2 - i * i);
		setcir(x + i, y + sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x + i, y - sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x - i, y + sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x - i, y - sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x + sqrt, y + i, a1, b1, c1, a2, b2, c2);
		setcir(x + sqrt, y - i, a1, b1, c1, a2, b2, c2);
		setcir(x - sqrt, y + i, a1, b1, c1, a2, b2, c2);
		setcir(x - sqrt, y - i, a1, b1, c1, a2, b2, c2);
	}
}


/*
 * do_print : dump the window to the printer
 */

union printerIO {
	struct IOStdReq ios;
	struct IODRPReq iodrp;
	struct IOPrtCmdReq iopc;
	};

extern union printerIO *CreateExtIO();
extern struct MsgPort *CreatePort();

do_print()
{
union printerIO *request;
struct MsgPort *printerPort;
struct ViewPort *vp;
struct Screen *sc;

	ClearMenuStrip(Wind);
	SetWaitPointer(Wind);

	/* set up for dump rastport request */
	printerPort = CreatePort("myprport",0L);
	request = CreateExtIO(printerPort, sizeof(union printerIO));
	if (OpenDevice("printer.device",0L,request,0L) !=0)
		{
		AutoRequest(Wind,&prfailtxt,0L,&oktxt,0L,0L,300L,75L);
		goto cleanup;
		}

	request->iodrp.io_Command = PRD_DUMPRPORT;
	request->iodrp.io_RastPort = rp;
	sc = Wind->WScreen;
	vp = &sc->ViewPort;
	request->iodrp.io_ColorMap = vp->ColorMap;
	request->iodrp.io_Modes = vp->Modes;
	request->iodrp.io_RastPort = rp;
	request->iodrp.io_SrcX= (UWORD) 0;
	request->iodrp.io_SrcY= (UWORD) 0;
	request->iodrp.io_SrcWidth= (UWORD) XSIZE;
	request->iodrp.io_SrcHeight= (UWORD) YSIZE;
	request->iodrp.io_DestCols=0L;
	request->iodrp.io_DestRows=0L;
	request->iodrp.io_Special=SPECIAL_ASPECT | SPECIAL_FULLCOLS;
	DoIO(request);
	CloseDevice(request);
  cleanup:
	DeleteExtIO(request, sizeof(union printerIO));
	DeletePort(printerPort);
	SetMenuStrip(Wind,&MenuList1);
	ClearPointer(Wind);
}

/*
 * do_pick : handle chain of menu selections
 */

do_pick(menunum)
long menunum;
{
struct MenuItem *item, *ItemAddress();
	while (menunum != MENUNULL)
		{
		switch(ITEMNUM(menunum))
			{
			case 0:
				get_file();
				break;
			case 1:
				clr_grf();
				break;
			case 2:
				set_xy();
				break;
			case 3:
				do_print();
				break;
			case 4:
				do_help();
				break;
			case 5:
				DoColorWindow(MyScreen,100L,100L,0L,TRUE);
				break;
			case 6:
				done(0);
				break;
			}
		item = ItemAddress(&MenuList1,menunum);
		menunum = item->NextSelect;
		}
}

/*
 * do_help - display help text
 */

do_help()
{
	int i;
	clr_grf();

	if (myfont)	/* if puny font in use, switch to topaz */
		if ((stdfont = (struct TextFont *)OpenFont(&stdattr)) != NULL)
			SetFont(rp,stdfont);

	for (i=0; i<40; i++)	/* dump the whole help text array */
		{
		if (!HelpText[i]) break;
		Move(rp,50L,(long) (i+1)*9+20);
		Text(rp,HelpText[i], (long) strlen(HelpText[i]));
		}

	if (myfont)	
		{
		SetFont(rp,myfont); /* back to puny */
		if (stdfont) CloseFont(stdfont);
		}
}

/*
 * clr_grf - clear the grafics area
 */

clr_grf()
{
	SetAPen(rp,0L);
	RectFill(rp,0L,0L,(long) (XSIZE-1),(long) (YSIZE-1));
	SetAPen(rp,1L);
}

/*
 * draw_file - read in a file and draw on screen
 */

draw_file()
{
register short cmd, i;
long x,y, r;
long r1, r2;
long x1,y1,x2,y2;
char textbuf[100];
 
xscale = xscaleu;
yscale = yscaleu;
xoff = xoffu;
yoff = yoffu;

/*************************************************
     MAIN Drawing loop
*************************************************/

while ((cmd = getc(input)) != EOF)
	{
	switch (cmd)
		{
		case 'm':	/* move x,y */
			get_xy(&x,&y);
			Move(rp,x,y);
			break;
		case 'n':	/* draw x,y */
			get_xy(&x,&y);
			Draw(rp,x,y);
			break;
		case 'p':	/* point x,y */
			get_xy(&x,&y);
			WritePixel(rp,x,y);
			break;
		case 'l':	/* line xs,ys, xe,ye */
			get_xy(&x,&y);
			Move(rp,x,y);
			get_xy(&x,&y);
			Draw(rp,x,y);
			break;
		case 'a':	/* arc xc,yc, xs,ys, xe,ye */
			get_xy(&x,&y);    /* get center */
			get_xy(&x2,&y2);  /* get end point */
			get_xy(&x1,&y1);  /* get start point */
			arc(x, y, x1, y1, x2, y2);  /* draw counterclockwise  */
			Move(rp,x1,y1);
			break;
		case 't':	/* Text string\n   */
			get_txt(textbuf);
			if (rp->cp_y == 0) break;
			Text(rp,textbuf, (long) strlen(textbuf));
			break;
		case 'c':	/* circle xc,yc, r */
			get_xy(&x,&y);
			get_int(&r);
			r1 = r*xmult/xscale;
			r2 = r*ymult/yscale;
			DrawEllipse(rp,x,y,r1,r2);
			break;
		case 'f':	/* linemode string\n   */
			get_txt(textbuf);
			for (i=0; i<5; i++)
				{
				if (0 == strcmp(textbuf,lmodestr[i]))
					{
					SetDrPt(rp,lmode[i]);
					break;
					}
				}
			break;
		case 's':	/* space xlo,ylo, xhi,yhi */
			get_int(&x1);
			get_int(&y1);
			get_int(&x2);
			get_int(&y2);
			if (!override) /* is user is not overriding */
				{
				xoff = x1;
				yoff = y1;
				xscale = x2;
				yscale = y2;
				xscale = xscale - xoff;
				yscale = yscale - yoff;
				}
			break;
		case 'e':	/* erase */
			clr_grf();
			break;
		default:
		AutoRequest(Wind,&ffmtmsg,0L,&oktxt,0L,0L,300L,75L);
		goto getout;
		}
	}
  getout:
	fclose(input);

}

/*
 * get_file - request a filename with fileio and draw it
 */

get_file()
{
struct Window	*FWind = NULL ;

   FIOSupp->ReqTitle = (UBYTE *) reqtitle;
   NewFileioWindow.Screen = MyScreen;
   if ((FWind = (struct Window *) OpenWindow(&NewFileioWindow)) == NULL)
	done(25);

   Retry:
   if (GetFileIOName(FIOSupp,FWind))
		BuildFileIOPathname(FIOSupp,filename);
   else {
   	CloseWindow(FWind);
   	return;
	}
 
   while ((input = fopen(filename,"r")) == NULL)
		{
		if (AutoRequest(Wind,&openfimsg,&retrytxt,&cantxt,0L,0L,300L,75L))
			continue;
		goto Retry;
		}

   CloseWindow(FWind);

   SetWaitPointer(Wind);
   draw_file();
   ClearPointer(Wind);
}

/*
 * set_xy - get x/y scaling via string gadgets
 */

set_xy()
{
	struct Window	*SWind = NULL ;
	struct IntuiMessage	*msg;
	UWORD code;
	ULONG class;
	APTR object;
	long tmp;

	sprintf(XscaleGadSIBuff,"%ld",xscaleu);
	sprintf(YscaleGadSIBuff,"%ld",yscaleu);
	sprintf(XoffGadSIBuff,"%ld",xoffu);
	sprintf(YoffGadSIBuff,"%ld",yoffu);

	NewScaleWindow.Screen = MyScreen;
	if ((SWind = (struct Window *) OpenWindow(&NewScaleWindow)) == NULL)
		done(25);
	Srp = SWind->RPort;
	PrintIText(Srp,&IWinText,0L,0L);

	while (1) {
	Wait(1L<<SWind->UserPort->mp_SigBit );
	while(msg = (struct IntuiMessage *) GetMsg(SWind->UserPort)) {
		code = msg->Code;  /* MENUNUM */
		object = msg->IAddress;  /* Gadget */
		class = msg->Class;
		switch(class) {
			case CLOSEWINDOW:
				ReplyMsg(msg);
				done(0);
			case GADGETUP:
				clr_msg();
				if (OverrideGad.Flags & SELECTED) override = TRUE;
					else override = FALSE;
				if (XoffGadSIBuff[0] == '\0') 
						{
						sprintf(XoffGadSIBuff,"%ld",xoffu);
						RefreshGadgets(SWind->FirstGadget,SWind,NULL);
						}
					else
					if ((tmp = val_off(XoffGadSIBuff)) == -1)
						{
						lite_msg();
						PrintIText(Srp,&ErrText3,0L,0L);
						break;
					}else 
						{
						xoffu = tmp;
						}
				if (YoffGadSIBuff[0] == '\0') 
						{
						sprintf(YoffGadSIBuff,"%ld",yoffu);
						RefreshGadgets(SWind->FirstGadget,SWind,NULL);
						}
					else
					if ((tmp = val_off(YoffGadSIBuff)) == -1)
						{
						lite_msg();
						PrintIText(Srp,&ErrText4,0L,0L);
						break;
					}else  {
						yoffu = tmp;
						}
				if (XscaleGadSIBuff[0] == '\0') 
						{
						sprintf(XscaleGadSIBuff,"%ld",xscaleu);
						RefreshGadgets(SWind->FirstGadget,SWind,NULL);
						}
					else
					if ((tmp = val_sc(XscaleGadSIBuff)) == -1)
						{
						lite_msg();
						PrintIText(Srp,&ErrText1,0L,0L);
						break;
					}else 
						{
						xscaleu = tmp;
						}
				if (YscaleGadSIBuff[0] == '\0') 
						{
						sprintf(YscaleGadSIBuff,"%ld",yscaleu);
						RefreshGadgets(SWind->FirstGadget,SWind,NULL);
						}
					else
					if ((tmp = val_sc(YscaleGadSIBuff)) == -1)
						{
						lite_msg();
						PrintIText(Srp,&ErrText2,0L,0L);
						break;
					}else  {
						yscaleu = tmp;
						}
				if (msg->IAddress == &OKGad) goto Dun;  /* OK button */
			case REFRESHWINDOW:
				break;
		}
		ReplyMsg(msg);
	}
	}	/* end while(Wait())    */
  Dun:
	CloseWindow(SWind);
}

/*
 * val_off : validate an offset string gadget contents and return
 *          -1 if invalid or offset if valid.
 */

val_off(buffer)
char *buffer;
{
	int sc;
	char *bufp;
	bufp = buffer;
	while (*bufp != '\0')
		{
		if (!isdigit(*bufp) && *bufp != '-') return -1;
		bufp++;
		}
	sc = atoi(buffer);
	return sc;
}

/*
 * val_sc : validate a scale string gadget contents and return
 *          -1 if invalid or scale if valid.
 */

val_sc(buffer)
char *buffer;
{
	int sc;
	char *bufp;
	bufp = buffer;
	while (*bufp != '\0')
		{
		if (!isdigit(*bufp)) return -1;
		bufp++;
		}
	sc = atoi(buffer);
	if (sc >100 && sc < 10000) return sc;
	return -1;
}

/*
 * lite_msg : Set the err-message area of the window to white
 *
 */
lite_msg()
{
	SetAPen(Srp,1L);
	RectFill(Srp, XOPT+4L, YOPT+3L,XOPT+140L,YOPT+13L);
	SetAPen(Srp,3L);
	DisplayBeep(MyScreen);
}

/*
 * clr_msg : clear the err-message area of the screen
 *
 */
clr_msg()
{
	SetAPen(Srp,0L);
	RectFill(Srp, XOPT+4L, YOPT+3L,XOPT+140L,YOPT+13L);
	SetAPen(Srp,3L);
}

