/* --------------------------------------------------------------------
 *
 *  Module:     X.c
 *
 *  Purpose:    X Windows device driver for X workstations.
 *              It allows output to an X win 
 *
 * ----------------------------------------------------------------- */


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "X.h"

#define borderwidth 5
#define TRUE 1
#define FALSE 0
#define grey 1
#define XRGBColour(r,g,b) (long)((b) << 16) | ((g) << 8) | (r)
#define BadX(x) ( ((x)<0) || ((x)>userResX) )
#define BadY(y) ( ((y)<0) || ((y)>userResY) )


/* Define variables for win's dpy and screen */

static Display      *dpy;
static Window        win;
static GC            gc;
static Colormap      cmap;
static Visual       *vis;
static int           screen;
static int	     BW;	/* colour or black and white display? */

#define NUMCOLOURS 11
static unsigned long colours[NUMCOLOURS];
static Colour        cmap_colours[NUMCOLOURS] = {
        { 0, 0, 0 },
        { 255, 255, 255 },
        { 255, 0, 0 },
        { 0, 255, 0 },
        { 0, 0, 255 },
        { 255, 255, 0 },
        { 0, 255, 255 },
        { 255, 0, 255 },
        { 250, 130, 80 },
        { 30, 230, 250 },
        { 230, 30, 250 },
};

/* Variables for height and width of Xwindow */

static unsigned heightm1;
static unsigned height;
static unsigned width;
static unsigned widthreal;
static unsigned pixelSize;
static unsigned screenSize;
static unsigned userResX;
static unsigned userResY;

/* ------------------------------------------ Local Prototypes ----- */

static void          SetCmap();
static unsigned long GetCmapColour();
 
/* ------------------------------------------ Global Functions ----- */

/* XOpen, open an XWindow or update window when a size change occurs */

void XOpen(int resx, int resy, int gargc, char *gargv[])
{
	char *dpyname;
	XSizeHints size_hints;
	int x=0,y=0,x_hot,y_hot,foo;
	XSetWindowAttributes xswa;
	XGCValues gcValue;
	XVisualInfo   vTemplate, *visualList;
	int          visualsMatched;
	unsigned long valuemask=0;

	if ( (resx > 0) && (resx <= MAXX) )
		userResX = resx;
	else {
		fprintf(stderr, "Bad X resolution: %d.  Defaulting to %d.\n",
			resx, MAXX);
		userResX = DEFAULTX;
	}

	if ( (resy > 0) && (resy <= MAXY) )
		userResY = resy;
	else {
		fprintf(stderr, "Bad Y resolution: %d.  Defaulting to %d.\n",
			resy, MAXY);
		userResY = DEFAULTY;
	}
		
        height=resy;
        heightm1=height-1;
        width=resx;
        widthreal=((width+7)/8)*8;
        dpyname=getenv("DISPLAY");
	/*
	printf("opening %d x %d display for %s using display %s\n",
		width, height, gargv[0], dpyname);
	*/

        if (dpyname==NULL)
            dpy=XOpenDisplay(":0");
        else
            dpy=XOpenDisplay(dpyname);

        if (dpy==NULL) {
            fprintf(stderr,"I can't open the dpy.\n\n"); 
            fprintf(stderr,"Is the DISPLAY environment variable set?.\n"); 
            fprintf(stderr,"Do you own the dpy?\n\nExiting\n\n"); 
            exit(-1);
        }

        /* Get the default screen */

        screen = DefaultScreen(dpy);
	win    = XDefaultRootWindow(dpy);

	vTemplate.screen = screen;
	vTemplate.depth = 8;
	vTemplate.class = PseudoColor;
	visualList = XGetVisualInfo(dpy, 
		VisualScreenMask|VisualClassMask|VisualDepthMask,
		&vTemplate, &visualsMatched);
	if ( visualsMatched == 0 ) {
		BW  = TRUE;				/* assume BW display */
		vis = DefaultVisual( dpy, screen );
	} else {
		BW  = FALSE;				/* assume colour */
		vis = visualList[0].visual;
	}
	XFree((char *)visualList);

        SetCmap();

        /* Set the X Event mask so that an exposure event is generated when
           the window is "uncovered" */

        xswa.event_mask=ExposureMask;

        /* Set background pixel */

        xswa.background_pixel= BlackPixel(dpy,screen);

        /* Set the colourmap */

        /* xswa.colormap=cmap; */
        xswa.colormap= cmap;


        size_hints.flags= PPosition | PSize | PMinSize;
        size_hints.x=x;
        size_hints.y=y;
        size_hints.width=width;
        size_hints.height=height;
        size_hints.min_width=8;
        size_hints.min_height=8;

        win=XCreateWindow(dpy,RootWindow(dpy,screen),
            x,y,width,height,borderwidth,
            CopyFromParent,InputOutput,vis,
            CWEventMask  | CWBackPixel | CWBorderPixel |
            CWColormap,&xswa);

        XSetStandardProperties(dpy,win,gargv[0],gargv[0],None,
            gargv,gargc,&size_hints);

        /* Select event types wanted */

        XSelectInput(dpy,win,ExposureMask | KeyPressMask |
            ButtonPressMask | StructureNotifyMask);

	gcValue.line_style = LineSolid;
	gcValue.function   = GXcopy;
	gcValue.background = BlackPixel(dpy,screen);
	gcValue.foreground = WhitePixel(dpy,screen);

        gc=XCreateGC(dpy,win,
		GCForeground | GCBackground | GCFunction | GCLineStyle,
		&gcValue);

        XMapWindow(dpy,win);
	/* GetEvent(); */
	XSync(dpy,TRUE);
}


DisplayScreen()
{
	_XFlushGCCache(dpy, gc);
	XFlush(dpy);
}

ClearScreen()
{
	XClearWindow(dpy, win);
}


/* Sets the default colourmap. */

static void SetCmap()
{
	int i;

	/* Inherit the default colourmap */
        cmap= XDefaultColormap(dpy,screen);

	/* Set up a translation table to go from our colours to X's */
        for (i=0;i<NUMCOLOURS;++i) {
		colours[i] = GetCmapColour(cmap_colours[i]);
        }
}





/* Point set for colour */ 

void    XSetRGBpixel(unsigned x,unsigned y,unsigned r, unsigned g, unsigned b)
{
    /* XPutPixel(mainscreen,(int) x,(int) (heightm1-y), XRGBColour(r,g,b)); */
}


void  setpixel(int x, int y, int c)
{
	XSetForeground(dpy, gc, colours[c%(NUMCOLOURS-1)]);
	XDrawLine(dpy, win, gc, x, y, x, y);
}





/* Point set for black and white */ 

void    XSetCLTpixelBW(unsigned x,unsigned y,unsigned c)
{
    /* XPutPixel(mainscreen,(int) x,(int) (heightm1-y),c); */
}






void    XClose()
{
	XCloseDisplay(dpy);
}




void drawoval(int x, int y, int w, int h, int c)
{
	if (BadX(x) || BadX(y)) return;
	XSetForeground(dpy, gc, colours[c%(NUMCOLOURS-1)]);
	XDrawArc(dpy, win, gc, x, y, w, h, 1, 7);
	printf("oval: (%d,%d), (%d,%d)\n", x,y,w,h);
}



void  drawline(int x1, int y1, int x2, int y2, int c)
{
	if (BadX(x1) || BadY(y1)) return;
	if (BadX(x2) || BadY(y2)) return;
	XSetForeground(dpy, gc, colours[c%(NUMCOLOURS-1)]);
	XDrawLine(dpy, win, gc, x1, y1, x2, y2);
}


void drawbox(int blx, int bly, int trx, int try, int c)
{
	if (BadX(blx) || BadY(bly)) return;
	if (BadX(trx) || BadY(try)) return;
	XSetForeground(dpy, gc, colours[c%(NUMCOLOURS-1)]);
	XDrawLine(dpy, win, gc, blx, bly, blx, try);
	XDrawLine(dpy, win, gc, trx, try, blx, try);
	XDrawLine(dpy, win, gc, trx, try, trx, bly);
	XDrawLine(dpy, win, gc, blx, bly, trx, bly);
}





unsigned long GetCmapColour(c)
    Colour c;
{
    XColor   colour;

    colour.red   = c.r * 256;
    colour.green = c.g * 256;
    colour.blue  = c.b * 256;

    if (BW)
        return(WhitePixel(dpy, screen));

    if(XAllocColor(dpy, cmap, &colour)) {
        return(colour.pixel);
    }
    else {
        return(WhitePixel(dpy, screen));
    }
}

/*
 *	Wait (i.e., poll) for a button event and return it.
 */
XButtonEvent *GetEvent()
{
    XEvent	event;
    XButtonEvent *button;
    int done = FALSE;

   if (dpy==NULL) {
	fprintf(stderr, "Hey!  You haven't opened a window yet but here\n");
	fprintf(stderr, "you are asking for an event.  Sorry.  No go.\n");
	exit(1);
   }

   do   {
	XNextEvent ( dpy, &event );
	if (event.type == ButtonPress) {
	     button = (XButtonEvent *) &event;
	     done = TRUE;
        }
    } while (!done);
    return(button);
}
