/* A program to plot UNIX plot files on an Amiga screen */
/*
/* Richard Gerber 5/5/92  gerber@sirius.astro.uiuc.edu */
/* Do with this what you wish (like add error checking! and proper font
   support) */
/* Compiled with SAS/C 5.10b w/ 2.04 include files (I think it should 
   work with 1.3) */

#include <stdio.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <graphics/gfxmacros.h>

typedef short int INT16;

void readplot(char *);
void opengraphics();
void myexit(char *);
UBYTE handleIDCMP( struct Window *);
void erase();
void line(INT16, INT16, INT16, INT16);
void lineto(INT16, INT16);
void move(INT16, INT16);
void dotext(INT16, INT16, char *);
void reverse(char *, int);
void setlinemode(char *);
void circle(INT16, INT16, INT16);
void arc(void);


INT16 scale = 1;
char text[81], linemod[40];
struct Window *window=NULL;
struct GfxBase *GfxBase=NULL;
struct IntuitionBase *IntuitionBase=NULL;
struct Screen screen;
int wdth,ht;
int zeroy;
char fname[40];

struct NewWindow newwindow = 
{
	0,0,0,0,   /* filled in later */
	-1,-1,
	CLOSEWINDOW|NEWSIZE,
	WINDOWCLOSE|WINDOWDEPTH|SMART_REFRESH|WINDOWDRAG
	|WINDOWSIZING,
	NULL, NULL,
	"UNIX Plot",
	NULL, NULL,
	100,50,
	~0,~0,
	WBENCHSCREEN
};	

main(int argc, char *argv[])
{
	ULONG signalmask, signals;
	UBYTE done = 0;

	if(argc!=2) {printf("Usage: %s plot_file.\n",argv[0]); exit(1);}

	opengraphics();

	strcpy(fname,argv[1]);	
	readplot(argv[1]); 

	signalmask = 1L << window->UserPort->mp_SigBit;
	while ( !done )
	{
		signals = Wait(signalmask);
		if (signals & signalmask)
			done = handleIDCMP(window);
	};		
	
	myexit(NULL);
}

void
readplot(char *filename)
{
	FILE *fp=NULL;
	int n;
	INT16 curx, cury;
	unsigned char com;
	INT16 pts[6];
	

	fp = fopen(filename,"rb");
	if(fp==NULL) myexit("Can't open file");


	while(!feof(fp))
	{
		n = fscanf(fp,"%c",&com);
		if(n==EOF) break;
		switch(com) {
			case 'e':
				erase();
				break;
			case 's':
				fread((char *)pts,8,1,fp);
				reverse((char *)pts,4);
				scale = pts[2];
				if(scale!=pts[3]) 
					printf("Error: scale not square!\n");
				break;
			case 'l':
				fread((char *)pts,8,1,fp);
				reverse((char *)pts,4);
				curx = pts[2]; cury = pts[3];
				line(pts[0],pts[1],pts[2],pts[3]);
				break;
			case 'n':
				fread((char *)pts,4,1,fp);
				reverse((char *)pts,2);
				lineto(pts[0],pts[1]);
				curx = pts[0]; cury = pts[1];
				break;
			case 'm':
				fread((char *)pts,4,1,fp);
				reverse((char *)pts,2);
				curx = pts[0]; cury = pts[1];
				move(curx,cury);
				break;
			case 't':
				fgets(text,80,fp);
				dotext(curx,cury,text);
				break;	
			case 'f':
				fgets(linemod,40,fp);
				setlinemode(linemod);
				break;	
			case 'c':
				fread((char *)pts,6,1,fp);
				reverse((char *)pts,3);
				circle(pts[0],pts[1],pts[2]);
				break;	
			case 'a':
				fread((char *)pts,12,1,fp);
				arc();
				break;
			default:
				printf("Unknown commnd %c,\n",com);
				myexit("Error in data file?");
				break;
			break;
		}
	}
	fclose(fp);
}

void
opengraphics(void)
{
	IntuitionBase = (struct IntuitionBase *)OpenLibrary(
			"intuition.library",33L);
	if(IntuitionBase==NULL) myexit("Intuition Library");

	GfxBase = (struct GfxBase *)OpenLibrary(
			"graphics.library",33L);
	if(GfxBase==NULL) myexit("Graphics Library");

	GetScreenData((CPTR *)&screen, sizeof(struct Screen),
			WBENCHSCREEN, NULL);
	
	newwindow.LeftEdge = 0;
	newwindow.TopEdge = 0;
	newwindow.Width = screen.Width;
	newwindow.Height = screen.Height;
	ht =  screen.Height - 2*screen.BarHeight;
	wdth = screen.Width - 2*screen.BarHeight;
	zeroy = screen.Height - 5;

	window = (struct Window *)OpenWindow(&newwindow);
	if(window==NULL) myexit("OpenWindow()");
}

void myexit(char *message)
{
	if(message!=NULL) printf("Program ending: %s error\n",message);

	if(window) CloseWindow(window);
	if(GfxBase) CloseLibrary((struct Library *)GfxBase);
	if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
	exit(1);
}
UBYTE handleIDCMP( struct Window *w)
{
	UBYTE flag = 0;
	struct IntuiMessage *message = NULL;
	ULONG class;

	while(message = (struct IntuiMessage *)GetMsg(w->UserPort) )
	{
		class = message->Class;
		ReplyMsg( (struct Message *)message);

		switch (class)
		{
			case CLOSEWINDOW:
				flag = 1;
				break;
			case NEWSIZE:
				wdth = window->Width - 2*screen.BarHeight;
				ht = window->Height - 2*screen.BarHeight;
				zeroy = window->Height - 5;
				erase();
				readplot(fname);
				break;
			default:
				break;
		}
	}
	return(flag);
}

void erase(void)
{
	SetAPen(window->RPort,0);
	RectFill(window->RPort,0,0,
		window->Width,window->Height);	
	RefreshWindowFrame(window);	
}

void
line(INT16 x0, INT16 y0, INT16 x1, INT16 y1)
{
	int xa, ya, xb, yb;
	xa = (x0*wdth)/scale ;
	xb = (x1*wdth)/scale ;
	ya = -(y0*ht)/scale + zeroy;
	yb = -(y1*ht)/scale + zeroy;
	SetAPen(window->RPort, 1);
	Move(window->RPort,xa,ya);
	Draw(window->RPort,xb,yb);
}

void lineto(INT16 x1, INT16 y1)
{
	int xa, ya;
	xa = (x1*wdth)/scale ;
	ya = -(y1*ht)/scale + zeroy;
	
	SetAPen(window->RPort, 1);
	Draw(window->RPort,xa,ya);
}
 
void move(INT16 x0, INT16 y0)
{
	int xa, ya;
	xa = (x0*wdth)/scale ;
	ya = -(y0*ht)/scale + zeroy;
	Move(window->RPort,xa,ya);
}

void circle(INT16 x0, INT16 y0, INT16 radius)
{
	int xa,ya,rx,ry;
	xa = (x0*wdth)/scale;
	ya = -(y0*ht)/scale + zeroy;
	ry = radius*ht/scale;
	rx = radius*wdth/scale;
	DrawEllipse(window->RPort,xa,ya,rx,ry);
}

void arc(void)
{
	printf("Arc command not implemented.\n");
}


void dotext(INT16 x0, INT16 y0, char *txt)
{
	int length;
	char strip[80];
	int xa, ya;
	int i;
	int textheight = 8;
	struct IntuiText it = {
	2,0,  JAM1, 1,1, NULL, NULL, NULL };
	USHORT holdptrn;

 	holdptrn = window->RPort->LinePtrn;	
	window->RPort->LinePtrn = 0xFFFF;	

	for(i=0;i<80;i++) strip[i]='\0';

	xa = (x0*wdth)/scale ;
	ya = -(y0*ht)/scale + zeroy - textheight/2;
	length = strlen(txt);
	strncpy(strip,txt,length-1);

	it.IText = strip;	
	PrintIText(window->RPort, &it, xa, ya);

	window->RPort->LinePtrn = holdptrn;
}

void
reverse(char array[], int i)
/*  99% of the time spent writing this program */
/* was spent figuring out that the bytes are reversed in the plot file */
/* This routine puts them back */
/* i is the actual number of short ints passed */
{
	int j;

	char fix[12];

	for(j=0;j<2*i;j++) fix[j] = array[j];

	for(j=0;j<2*i;j+=2)
	{
		array[j] = fix[j+1];
		array[j+1] = fix[j];
	}
}

void
setlinemode(char *t)
{
	int result, length;
	char strip[20];

        length = strlen(t);
        strncpy(strip,t,length-1);
	strip[length-1] = '\0';

	if(0==(result=strcmp(strip,"solid")))
	{
		window->RPort->LinePtrn = 0xFFFF;
	}
	
	if(0==(result=strcmp(strip,"longdashed")))
	{
		window->RPort->LinePtrn = 0xFF00;
	}

	if(0==(result=strcmp(strip,"dotted")))
	{
		window->RPort->LinePtrn = 0xCCCC;
	}
	
	if(0==(result=strcmp(strip,"shortdashed")))
	{
		window->RPort->LinePtrn = 0xF0F0;
	}

	if(0==(result=strcmp(strip,"dotdashed")))
	{
		window->RPort->LinePtrn = 0xF6F6;
	}
}	
