/* routines to graph points to the screen */
/*   entries:
**	make_graph_window(width, height)
**	clear_graph_window()
**	refresh_graph_window()
**	graph_line(xint, last_y, y, min_val, max_val)
**	   int xint;  = current pixel pos.; line is from xint-1 to xint
** 	   float last_y, y, min_val, max_val;
**	graph_long_line(last_xint, last_y, xint, y, min_val, max_val)
**	   int last_xint, xint;  = pixels (0...width)
** 	   float last_y, y, min_val, max_val;
** 
*/

#include<X11/Xlib.h>
#include<stdio.h>
#include<X11/X.h>
#include<X11/Xutil.h>
#include<strings.h>
#include<math.h>
#include<ctype.h>
#include<vis/vislib.h>
#include "fileio.h"

extern int show_results;

#define border_width (unsigned int)5
#define border       (unsigned long)1
#define background   (unsigned long)1

#define round(n)        (((n)-(int)(n) > .5) ? (int)(n) + 1 : (int)(n))
#define max(x, y)	(((x) > (y)) ? (x) : (y))
#define min(x, y)	(((x) < (y)) ? (x) : (y))

int win_width, win_height;
Window big_window;
Pixmap big_pixmap;

unsigned char verbose=0;

unsigned int   
  data_sets=0,
  channels=0,
  screen_depth;
unsigned long  *plane_masks,pixels[256];

Display       *dpy=NULL;
Window         root;
Colormap       colormap=0;
XVisualInfo    *vlist;
GC             gc;
Visual         *pseudocolor_visual;
int            screen;

void error_hook (display, err)
Display *display;
XErrorEvent *err;
  {
  char msg[80];
  XGetErrorText (display, err->error_code, msg,80);
  printf ("X WINDOW ERROR !!! \n %s\n", msg);
  }

setup_x_stuff()
 {
  int            num_matched;
  XVisualInfo    template;

  if (dpy) return;

 dpy = XOpenDisplay (NULL); 
 if (dpy==NULL) 
     {
     fprintf (stderr,"can't open display\n");
     exit(1);
     }
 
  screen = DefaultScreen(dpy);

  root = DefaultRootWindow(dpy);
  screen_depth = (unsigned int)DefaultDepth(dpy,screen);
  if (verbose != 0) fprintf (stderr,"using screen %d -- depth of %d\n",screen,screen_depth);

  template.depth = screen_depth;
  
  vlist = XGetVisualInfo (dpy, VisualDepthMask , &template, &num_matched);
  if (num_matched == 0)
      {
      fprintf (stderr,"can't match visual\n");
      exit (1);
      }
  
  pseudocolor_visual = vlist[0].visual;
  gc = DefaultGC (dpy,screen);
  XSetForeground(dpy, gc, BlackPixel(dpy, screen));
  XSetBackground(dpy, gc, WhitePixel(dpy, screen));
  XSetFunction(dpy, gc, GXcopy);
  XSetErrorHandler ((void *)error_hook);
 }

Window make_window(width, height)
int width, height;
  {
  Window win;
  XSetWindowAttributes attributes;
  XSizeHints sizehints;
  char *argv[1];
  int argc;
  
  argv[0] = (char *) malloc(1);
  argv[0][0] = 0;
  argc = 1;

  win = XCreateWindow (dpy, root, 0, 0, width, height, 
		       border_width, screen_depth, InputOutput, pseudocolor_visual, 0, &attributes);
  if (verbose != 0) fprintf (stderr,"the window id is %d\n", win);
  XSetWindowBorder (dpy,win,border);
  XSelectInput(dpy,win,KeyPressMask|ExposureMask);
  XMapWindow(dpy,win);
  XSetWindowColormap (dpy,win,DefaultColormap(dpy, screen));
  sizehints.flags = 0;
  XSetStandardProperties(dpy, win, "Graph",
			 "Graph", None, argv, argc, &sizehints);   
  return win;
}

/*****************************************************************************/

clear_graph_window()
{
  XSetFunction(dpy, gc, GXclear);
  XFillRectangle(dpy, big_pixmap, gc, 0, 0, win_width, win_height);
  XSetFunction(dpy, gc, GXcopy);
  XCopyArea(dpy,big_pixmap,big_window,gc,0,0,win_width,win_height,0,0);
  XFlush(dpy);
}

make_graph_window(width, height)
     int width, height;
{
  XImage *image;
  int w,h;

  win_width = width;
  win_height = height;
  
  setup_x_stuff();
  big_window = make_window(win_width, win_height);
  big_pixmap = XCreatePixmap(dpy,root,win_width,win_height,screen_depth);
  image = XGetImage(dpy, big_pixmap, 0,0,win_width,win_height, -1, ZPixmap);
  XFlush(dpy);
  for(h=0 ; h<win_height ; h++)
    for(w=0 ; w<win_width ; w++)
      (image->data)[(w + h*win_width)] = WhitePixel(dpy, screen);
  XPutImage(dpy, big_pixmap, gc, image, 0,0,0,0,win_width, win_height);
  /* XFillRectangle(dpy,big_pixmap,gc,0,0,win_width,win_height); */
  XCopyArea(dpy,big_pixmap,big_window,gc,0,0,win_width,win_height,0,0);
  XDestroyImage(image);
  XFlush(dpy);
}

refresh_graph_window()
{
  XEvent event;
  XImage *image;
  FILE *fd;
  char string[10], winfile[100];
  float **vis_image;
  int h,w;

  if (XEventsQueued(dpy, QueuedAfterFlush))
    {
      XNextEvent(dpy, &event);
      switch (event.type)
	{
	case Expose:
	  XCopyArea(dpy,big_pixmap,big_window,gc,0,0,win_width,win_height,0,0);
	  XFlush(dpy);
	  break;
	  
	case MappingNotify:
	  XRefreshKeyboardMapping(&event);
	  break;
	  
	case KeyPress:
	  XLookupString(&event, string, 10, 0, 0);
	  if (string[0] == 'p' || string[0] == 'P')
	    {
	      image = XGetImage(dpy, big_pixmap, 0,0,win_width,win_height,
				-1, ZPixmap);
	      XFlush(dpy);
	      printf("output file for window data: ");
	      scanf("%s", winfile);
	      fd = open_file(winfile, "w");
	      vis_image = fialloc(win_width,win_height);
	      for(h=0 ; h<win_height ; h++)
		for(w=0 ; w<win_width ; w++)
		  vis_image[w][(win_height-h-1)] 
		    = (float) (image->data)[(w + h*win_width)];
	      fiequalize(vis_image, win_width, win_height);
	      fifwrite(fd, vis_image, win_width, win_height);
	      /*
	      fprintf(fd, "ITYPE=vis\nETYPE=unsigned char\nDIMS=%d %d\n\n",
		      win_height, win_width);
	      write_image(image->data, win_width*win_height, fd);
	      */
	      fifree(vis_image);
	      fclose(fd);
	      XDestroyImage(image);
	    }
	  else if (string[0] == 'c' || string[0] == 'C')
	    show_results = 1;

	  break;
	}
    }
}
  
graph_line(xint, last_y, y, min_val, max_val)
     int xint;
     float last_y, y, min_val, max_val;
{
  int yint, last_yint;

  yint = floor((max_val - y) * win_height / (max_val - min_val));
  if (xint == 0)
    {  
      XDrawPoint(dpy, big_pixmap, gc, xint, yint);
      XDrawPoint(dpy, big_window, gc, xint, yint);
    }
  else
    {
      last_yint = floor((max_val - last_y) * win_height / (max_val - min_val));
      XDrawLine(dpy, big_pixmap, gc, xint-1, last_yint, xint, yint);
      XDrawLine(dpy, big_window, gc, xint-1, last_yint, xint, yint);
    }
  XFlush(dpy);
}

graph_long_line(last_xint, last_y, xint, y, min_val, max_val)
     int last_xint, xint;
     float last_y, y, min_val, max_val;
{
  int yint, last_yint;

  yint = floor((max_val - y) * win_height / (max_val - min_val));
  if (xint == 0)
    {  
      XDrawPoint(dpy, big_pixmap, gc, xint, yint);
      XDrawPoint(dpy, big_window, gc, xint, yint);
    }
  else
    {
      last_yint = floor((max_val - last_y) * win_height / (max_val - min_val));
      XDrawLine(dpy, big_pixmap, gc, last_xint, last_yint, xint, yint);
      XDrawLine(dpy, big_window, gc, last_xint, last_yint, xint, yint);
    }
  XFlush(dpy);
}
