/*--------------------------------------------------------------*/
/*	DecWindows Driver 1.0 , for GLE V3.0	         	*/
/*--------------------------------------------------------------*/
/*  	NOTE: MUST be run from a DECwindow (vt100 window, or curses) 	*/
/*---------------------------------------------------------------------------*/
#include "all.h"
#include <math.h>
#include "core.h"
#include "mygraph.h"
#include "mydev.h"
extern int gunit;
extern struct gmodel g;
/*---------------------------------------------------------------------------*/
/* 		XWindows stuff here 		*/
/*-----------------------------------------------*/
#ifdef VMS
#include <decw$include/Xlib.h>
#include <decw$include/Xutil.h>
#else
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#endif
#define FontName "-ADOBE-NEW CENTURY SCHOOLBOOK-MEDIUM-R-NORMAL--*-140-*-*-P-*"
#define WindowName "CGLE Output"
int maxxsize = 800;
int maxysize = 800;
int window1W;
int window1H;
Display *dpy;
Window window1;
GC gc,gcf;
Screen *screen;
static void doInitialize( );
static int doDefineColor(int n);
static void doCreateWindows( );
static void doCreateGraphicsContext( );
static void doLoadFont( );
static void doExpose( );
static void doWMHints( );
static void doMapWindows( );
static void doHandleEvents( );
static void doButtonPress( );

/***************** doInitialize **************************/
int color_table[9];
static void doInitialize( )
{
	int i;
    dpy = XOpenDisplay(0);
    if (!dpy){
        printf("Display not opened!\n");
	scr_end();
        exit(-1);
    }
    screen = XDefaultScreenOfDisplay(dpy);
    doCreateWindows( );

    for (i=0;i<=9; i++) {
	color_table[i] = doDefineColor(i);
    }

    doCreateGraphicsContext( );

    XSync(dpy,False);
    save_focus();

    doLoadFont( );

    doWMHints( );

    doMapWindows( );
}

/******* doCreateWindows *********/
static void doCreateWindows( )
{
    int window1X = (XWidthOfScreen(screen)-window1W);
    int window1Y = 1;
      XSetWindowAttributes xswa;

    /* Create the window1 window   width and height are global variables*/

    xswa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask
			| VisibilityChangeMask;
		   /*  | ButtonPressMask; */
    xswa.background_pixel = doDefineColor(0);

    window1 = XCreateWindow(dpy, XRootWindowOfScreen(screen),
	window1X, window1Y, window1W, window1H, 0,
	XDefaultDepthOfScreen(screen), InputOutput,
	XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa);
}


/******** Create the graphics context *********/
static void doCreateGraphicsContext( )
{
    XGCValues xgcv;

    /* Create graphics context. */

    xgcv.background = doDefineColor(0);
    xgcv.foreground = doDefineColor(1);

    gc = XCreateGC(dpy, window1, GCForeground | GCBackground, &xgcv);
    gcf = XCreateGC(dpy, window1, GCForeground | GCBackground, &xgcv);
}
setcolor(i)
{
    XGCValues xgcv;
    xgcv.foreground = color_table[i];
    XChangeGC(dpy, gc, GCForeground , &xgcv);
}
setfillcolor(i)
{
    XGCValues xgcv;
    xgcv.foreground = color_table[i];
    XChangeGC(dpy, gcf, GCForeground , &xgcv);
}

/******* Load the font for text writing ******/
static void doLoadFont( )
{
    Font font;

    font = XLoadFont(dpy, FontName);
    XSetFont(dpy, gc, font);
}

/******* Create color ************************/
static int doDefineColor(int i)
{
    int pixel;
    char *colors[] = {
	"white",
	"black",
	"red",
	"green",
	"blue",
	"yellow",
	"magenta",
	"cyan",
	"light grey",
	"black"
	};
    XColor exact_color,screen_color;
    if ((XDefaultVisualOfScreen(screen))->class == PseudoColor
        ||  (XDefaultVisualOfScreen(screen))->class == DirectColor)
        if (XAllocNamedColor(dpy, XDefaultColormapOfScreen(screen),
            colors[i], &screen_color, &exact_color))
                return screen_color.pixel;
            else
	        printf("Color not allocated! {%s}\n",colors[i]);
     else
        switch (i) {
	    case 1:		return XWhitePixelOfScreen(screen); break;
            case 2:		return XBlackPixelOfScreen(screen); break;
            default:		return XBlackPixelOfScreen(screen); break;
        }
}

/******** do WMHints *************/
static void doWMHints( )
{
    XSizeHints xsh;

    /* Define the size and name of the window1 window */

    xsh.x = (XWidthOfScreen(screen)-window1W);
    xsh.y = 1;
    xsh.width = window1W;
    xsh.height = window1H;
    xsh.flags = PPosition | PSize;

    XSetNormalHints(dpy, window1, &xsh);

    XStoreName(dpy, window1, WindowName);
}
/******** doMapWindows ***********/
static void doMapWindows( )
{
	set_expose();
	XMapWindow(dpy, window1);
}
/****************** doHandleEvents ***********************/
static wwinit=0;
static void doHandleEvents( )
{
    XEvent event;

    for ( ; ; ) {
	if (XPending(dpy) == 0 && wwinit!=0) return;
	XNextEvent(dpy, &event);
	switch (event.type) {
            case Expose:		break;
	    case ButtonPress: 		doButtonPress(&event); break;
        }
    }
}

/***************** doShutdown ***************************/
static void doButtonPress(eventP)
XEvent *eventP;
{
/*
    if (eventP->xexpose.window != window1) {
       	XDrawImageString(dpy, window1, gc, 75, 75, message[state], strlen(message[state]));
	return;
    }
*/
}

getmaxx()
{
	return maxxsize;
}
getmaxy()
{
	return maxysize;
}
getmaxcolor()
{
	return 9;
}
/*---------------------------------------------------------------------------*/

#define DASHED_LINE 2
#define SOLID_LINE 1
#define pi 3.141592653
#define BLACKANDWHITE 1
#define false 0
#define true (!false)
#define dbg if ((gle_debug & 64)>0)

double savexsize,saveysize;
extern int gle_debug;
int gle_nspeed = 2; /* text mode = slow and fast */
int incap=true;
/*---------------------------------------------------------------------------*/
/* The global variables for the PC screen driver */
/*-----------------------------------------------*/
int i,l,j,ix,iy;
double f;
double xsizecm,ysizecm;
#define sx(v) ( (int) ((v) * d_xscale))
#define sy(v) ( d_maxy - ((int) ((v) * d_yscale)))
#define rx(v) ( (int) ((v) * d_xscale))
#define ry(v) ( d_maxy - ((int) ((v) * d_yscale)))

double d_scale, d_xscale, d_yscale;
int d_graphmode;
int d_fillstyle=1,d_fillcolor;
int d_lstyle,d_lwidth;
int d_maxy;

d_devcmd(char *s)
{}
dxy(double x, double y, int *dx, int *dy)
{
	static double fx,fy;
	g_dev(x,y,&fx,&fy);
	*dx = sx(fx);
	*dy = sy(fy);
}
rxy(double x, double y, int *dx, int *dy)
{
	static double fx,fy,zx,zy;
	g_dev(x,y,&fx,&fy);
	g_dev(0.0,0.0,&zx,&zy);
	*dx = (int) ( (fx-zx) * d_xscale);
	*dy = (int) ( (fy-zy) * d_yscale);
}
/*---------------------------------------------------------------------------*/
d_dfont(char *c)
{
	/* only used for the DFONT driver which builds fonts */
}
/*---------------------------------------------------------------------------*/
static char lastline[80];
d_message(char *s)
{
	w_message(s);
}
/*---------------------------------------------------------------------------*/
d_source(char *s)
{
	s=s;
}
/*---------------------------------------------------------------------------*/
d_get_type(char *t)
{
	strcpy(t,"INTERACTIVE, X, DECWINDOWS, XWINDOWS");
}
/*---------------------------------------------------------------------------*/
d_set_path(int onoff)
{}
/*---------------------------------------------------------------------------*/
d_newpath()
{
}
/*---------------------------------------------------------------------------*/
d_open(double width, double height)
{
	gle_nspeed = 2; /* text mode = slow and fast */
	xsizecm = 16;
	ysizecm = 16;
	/* Get largest rectangle we can fit on the screen */
	d_scale = xsizecm / width;
	f = ysizecm / height;
	if (f<d_scale) d_scale = f;
	d_xscale = d_scale * (getmaxx()) / xsizecm; /* Device Scale X, Device Scale y */
	d_yscale = d_scale * (getmaxy()) / ysizecm;
    	window1W = width*d_xscale;
    	window1H = height*d_yscale;
	d_maxy = window1H;
	if (dpy==0 || savexsize != width || saveysize != height) {
		if (dpy!=NULL) {
			XUnmapWindow(dpy, window1);
			XDestroyWindow(dpy, window1);
			XCloseDisplay(dpy);
		}
		doInitialize( ); 
		set_expose(); 
		XRaiseWindow(dpy, window1); 
		wait_expose();
	} else {
		set_expose(); 
		XRaiseWindow(dpy, window1); 
		wait_expose();
	}
    	XClearWindow(dpy, window1);
	XSync(dpy,False);
	savexsize = width;
	saveysize = height;
}
/*---------------------------------------------------------------------------*/
d_tidyup()
{
}
d_close()
{
	long emask;
	XEvent ereturn;
	g_flush();
	lastline[0] = 0;
	get_focus();
	XSync(dpy,False);
	fner("Picture completed, press RETURN to continue                    (Press any key)");
	scr_refresh();

	/* Wait till he presses key or clicks mouse */
	emask = ButtonPressMask | KeyPressMask;
	XWindowEvent(dpy, window1, emask, &ereturn);

	/* (use this if event's don't work)  	text_inkey(); */
	XLowerWindow(dpy, window1);
	/* restore input focus to terminal screen, and return */
	restore_focus();XSync(dpy,True);
}
Window f_window;
int f_return;
save_focus()
{
	XGetInputFocus(dpy, &f_window, &f_return);
}
restore_focus()
{
	int i;
	i = XSetInputFocus(dpy, f_window, f_return, CurrentTime);
}
get_focus()
{
	XSetInputFocus(dpy, window1, RevertToPointerRoot, CurrentTime);
}
/*---------------------------------------------------------------------------*/
d_set_line_cap(int i)
{
	i++;
}
/*---------------------------------------------------------------------------*/
d_set_line_join(int i)
{
	i++;
}
/*---------------------------------------------------------------------------*/
d_set_line_miterlimit(double d)
{
	i++;
}
/*---------------------------------------------------------------------------*/
d_set_line_width(double w)
{
	int xa,xb;
	XGCValues xgcv;
	rxy(w,w,&xa,&xb);
/*	if (xa<=2) xa = 0; */
    	xgcv.line_width = xa;
    	XChangeGC(dpy, gc, GCLineWidth , &xgcv);
}
/*---------------------------------------------------------------------------*/
d_set_line_styled(double dd)
{}
d_set_line_style(char *s)
{
	XGCValues xgcv;
	static char *defline[] = {"","","12","41","14","92",
	"1282","9229","4114","54"};
	int i, dashoff=0;
	char dashlist[64];

	if (strlen(s)==1)  s = defline[*s-'0'];
	if (strcmp(s,"")==0) {
	    xgcv.line_style  = LineSolid;
	    XChangeGC(dpy, gc, GCLineStyle , &xgcv);
	} else {
	    xgcv.line_style  = LineDoubleDash;
	    XChangeGC(dpy, gc, GCLineStyle , &xgcv);
	    for (i=0; *s!=0; s++,i++)
		dashlist[i] = *s-'0' ? *s-'0' : 1;
	    XSetDashes(dpy, gc, dashoff, dashlist, i);
	}
}
/*---------------------------------------------------------------------------*/
d_fill()
{
}
/*---------------------------------------------------------------------------*/
d_fill_ary(int nwk,double (*wkx)[],double (*wky)[])
{
	int i;
/*	fprintf(psfile,"%g %g moveto \n",(*wkx)[0],(*wky)[0]);
	for (i=1;i<nwk;i++)
		fprintf(psfile,"%g %g l \n",(*wkx)[i],(*wky)[i]);
*/
}
d_line_ary(int nwk,double (*wkx)[],double (*wky)[])
{
	int i;
	dxy( (*wkx)[0], (*wky)[0], &ix, &iy);
/*	moveto(ix,iy); */
	for (i=1;i<nwk;i++) {
		dxy( (*wkx)[i], (*wky)[i], &ix, &iy);
	}
}
/*---------------------------------------------------------------------------*/
d_stroke()
{
}
/*---------------------------------------------------------------------------*/
d_clip()
{
}
/*---------------------------------------------------------------------------*/
d_set_matrix(double newmat[3][3])
{
}
/*---------------------------------------------------------------------------*/
d_move(double zx,double zy)
{
}
/*---------------------------------------------------------------------------*/
d_reverse() 	/* reverse the order of stuff in the current path */
{
}
/*---------------------------------------------------------------------------*/
d_closepath()
{
	g_line(g.closex,g.closey);
}
/*---------------------------------------------------------------------------*/
d_line(double zx,double zy)
{
	static int ux,uy;
	dxy(g.curx,g.cury,&ux,&uy);
	dxy(zx,zy,&ix,&iy);
    	XDrawLine(dpy,window1,gc,ux,uy,ix,iy);
}
/*---------------------------------------------------------------------------*/
d_clear()
{
}
/*---------------------------------------------------------------------------*/
d_flush()
{
}
/*---------------------------------------------------------------------------*/
int polar_xy(double r, double angle, double *dx, double *dy);
int xy_polar(double dx,double dy,double *radius,double *angle);
d_arcto(dbl x1,dbl y1,dbl x2,dbl y2,dbl rrr)
{
	double x0,y0,r1,a1,r2,a2,r3,a3,a4,r5,ssx,ssy,ex,ey;
	double bx1,by1,bx2,by2,dist,neg;
	g_get_xy(&x0,&y0);
	xy_polar(x1-x0,y1-y0,&r1,&a1);
	xy_polar(x2-x1,y2-y1,&r2,&a2);
	neg = 1;
	a4 = (180-a2+a1);
	a3 = a2 + (a4/2);
	if ((a4/2)>90 && (a4/2)<180 ) neg = -1;
	if ((a4/2)<0 && (a4/2)>-90 ) neg = -1;
	r3 = neg*rrr/(tan((pi/180)*a4/2));
	dbg gprint("rrr %g a4/2 %g t=%g a2=%g a1=%g r1=%g r2=%g r3=%g \n",rrr,a4/2,tan(a4/2),a2,a1,r1,r2,r3);
	polar_xy(-r3,a1,&ssx,&ssy); ssx += x1; ssy += y1;
	polar_xy(r3,a2,&ex,&ey); ex += x1; ey += y1;
	g_line(ssx,ssy);
	dist = sqrt((ex-ssx) * (ex-ssx) + (ey-ssy)*(ey-ssy));
	polar_xy(r1+ dist/2.5-r3,a1,&bx1,&by1); bx1 += x0; by1 += y0;
	polar_xy(-r2+ -dist/2.5+r3,a2,&bx2,&by2); bx2 += x2; by2 += y2;
	g_bezier(bx1,by1,bx2,by2,ex,ey);
	g_line(x2,y2);
}
/*---------------------------------------------------------------------------*/
d_arc(dbl r,dbl t1,dbl t2,dbl cx,dbl cy)
{
	static int ixr,iyr,icx,icy,a1,a2;
	double ux,uy,z;
	dxy(cx,cy,&icx,&icy);
	rxy(r,r,&ixr,&iyr);
	if (t1>t2) {z = t1; t1 = t2; t2 = z;}
	a1 = t1*64; a2 = t2*64 - a1;
    	XDrawArc(dpy,window1,gc,icx-ixr,icy-iyr,ixr*2,iyr*2,a1,a2);
}
/*---------------------------------------------------------------------------*/
d_narc(dbl r,dbl t1,dbl t2,dbl cx,dbl cy)
{
	static int ixr,iyr,icx,icy,a1,a2;
	double ux,uy,z;
	dxy(cx,cy,&icx,&icy);
	rxy(r,r,&ixr,&iyr);
	if (t1>t2) {z = t1; t1 = t2; t2 = z;}
	a1 = t1*64; a2 = t2*64 - a1;
    	XDrawArc(dpy,window1,gc,icx-ixr,icy-iyr,ixr*2,iyr*2,a1,a2);
}
/*---------------------------------------------------------------------------*/
d_box_fill(dbl x1, dbl y1, dbl x2, dbl y2)
{
	static int ix1,iy1,ix2,iy2;
	static int ii;
	dxy(x1,y1,&ix1,&iy1);
	dxy(x2,y2,&ix2,&iy2);
	if (ix1>ix2) { ii = ix1; ix1 = ix2; ix2 = ii; }
	if (iy1>iy2) { ii = iy1; iy1 = iy2; iy2 = ii; }
    	XFillRectangle(dpy,window1,gcf,ix1,iy1,ix2-ix1,iy2-iy1);
}
d_box_stroke(dbl x1, dbl y1, dbl x2, dbl y2)
{
	g_move(x1,y1);
	g_line(x2,y1);
	g_line(x2,y2);
	g_line(x1,y2);
	g_line(x1,y1);
}
/*---------------------------------------------------------------------------*/
d_circle_stroke(double zr)
{
	static int ixr,iyr;
	int ux,uy;
	rxy(zr,zr,&ixr,&iyr);
	ixr =(fabs(ixr)+fabs(iyr))/2;
	dxy(g.curx,g.cury,&ux,&uy);
    	XDrawArc(dpy,window1,gc,ux-ixr,uy-ixr,ixr*2,ixr*2,0,64*360);
}
d_circle_fill(double zr)
{
	static int ixr,iyr;
	int rr;
	int ux,uy;
	rxy(zr,zr,&ixr,&iyr);
	rr = (fabs(ixr)+fabs(iyr))/2;
	dxy(g.curx,g.cury,&ux,&uy);
    	XFillArc(dpy,window1,gcf,ux-rr,uy-rr,rr*2,rr*2,0,64*360);
}
/*---------------------------------------------------------------------------*/
d_bezier(dbl x1,dbl y1,dbl x2,dbl y2,dbl x3,dbl y3)
{
	double ax,bx,cx,ay,by,cy,dist;
	double xxx,yyy,i,t,nstep,x0,y0;
	g_get_xy(&x0,&y0);
	dist = fabs(x3-x0) + fabs(y3-y0);
	nstep = 12;
	if (dist<1) nstep = 7;
	if (dist<.5) nstep = 3;
	if (dist<.1) {
		g_line(x3,y3);
		return;
	}
	cx = (x1-x0)*3;
	bx = (x2-x1)*3-cx;
	ax = x3-x0-cx-bx;
	cy = (y1-y0)*3;
	by = (y2-y1)*3-cy;
	ay = y3-y0-cy-by;
	for (i=0;i<=nstep;i++) {
		t = i/nstep;
		xxx = ax*pow(t,3.0) + bx*t*t + cx*t + x0;
		yyy = ay*pow(t,3.0) + by*t*t + cy*t + y0;
		g_line(xxx,yyy);
	}
}
/*---------------------------------------------------------------------------*/
d_set_color(long f)
{
	int i;
	colortyp  cc;
	cc.l = f;
	i = 1;
	if (cc.b[B_R]>1 && cc.b[B_G]>1 && cc.b[B_B]>1) i = 9;
	if (cc.b[B_R]>60 && cc.b[B_G]>60 && cc.b[B_B]>60)  i = 8;
	if (cc.b[B_R]>100) i = 2;
	if (cc.b[B_B]>100) i = 4;
	if (cc.b[B_G]>100) i = 3;
	if (cc.b[B_R]>100 && cc.b[B_G]>100) i = 5;
	if (cc.b[B_G]>100 && cc.b[B_B]>100) i = 7;
	if (cc.b[B_R]>100 && cc.b[B_G]>100 && cc.b[B_B]>100) i = 8;
	if (cc.b[B_R]>250 && cc.b[B_G]>250 && cc.b[B_B]>250) i = 0;
	setcolor(i);
}
d_set_fill(long f)
{
	int i;
	colortyp  cc;
	cc.l = f;
	i = 1;
	if (cc.b[B_R]>1 && cc.b[B_G]>1 && cc.b[B_B]>1) i = 9;
	if (cc.b[B_R]>60 && cc.b[B_G]>60 && cc.b[B_B]>60)  i = 8;
	if (cc.b[B_R]>100) i = 2;
	if (cc.b[B_B]>100) i = 4;
	if (cc.b[B_G]>100) i = 3;
	if (cc.b[B_R]>100 && cc.b[B_G]>100) i = 5;
	if (cc.b[B_G]>100 && cc.b[B_B]>100) i = 7;
	if (cc.b[B_R]>100 && cc.b[B_G]>100 && cc.b[B_B]>100) i = 8;
	if (cc.b[B_R]>250 && cc.b[B_G]>250 && cc.b[B_B]>250) i = 0;
	setfillcolor(i);
}
/*---------------------------------------------------------------------------*/
d_beginclip()
{
}
d_endclip()
{
}
struct char_data {float wx,wy,x1,y1,x2,y2; };
int font_get_chardata(struct char_data **cd, int ff, int cc);
/*---------------------------------------------------------------------------*/
int safnt;
int simple_char(int cc);
d_char(int font, int cc)
{
	static struct char_data cd;
	static int ix1,ix2,iy1,iy2;
	static int ux,uy;
	char ss[2];

	ss[0] = cc;
	ss[1] = 0;
	if (safnt==0) safnt = pass_font("PLSR");
	if (font_get_encoding(font)>2) {
		my_char(font,cc);
		return;
	}
	my_char(safnt,cc);
}

/*
int XDrawImageString(dpy, window1, gc, 75, 75, message[state], strlen(message[state]));
*/





int wait_expose()
{
	/* Wait till he presses key or clicks mouse */
	XEvent ereturn;
	long emask;

/*	for (;;) {
		XNextEvent(dpy,&ereturn);
		wprintf("Event %d  %d %d %d\n",ereturn.type,Expose,ButtonPress,
			VisibilityNotify);
		scr_refresh();
	}
*/
	/* XSync(dpy,True);	 */
    	emask = ExposureMask;
	XWindowEvent(dpy, window1, emask, &ereturn);
	

}
int set_expose()
{
	XEvent ereturn;
	long emask;
	
    emask = ExposureMask | ButtonPressMask | KeyPressMask
			| VisibilityChangeMask;
	XSelectInput(dpy, window1, emask, &ereturn);
}
