#include <X/Xlib.h>      /* X window display function for CSOUND      DISPX.C*/
#include <stdio.h>       /* written by Al Tervalon, Fall 1986 */
#include "sysdep.h"

#define XINIT    0       /* set default window location */
#define YINIT    400     /* width and height for use */
#define WIDTH    400     /* by XCreate if neccessary */
#define HEIGHT   300
#define BDR      2  

extern int  dsploption;

dsplXgraph(array,npts,label, windowid)
 float *array;
 int npts;
 char *label;
 Window *windowid;
{
  Vertex *vlisthead;
  Font font;
  OpaqueFrame frame;
  WindowInfo info;
  XEvent event;
  short xmin, ymin, newwidth, newheight;
  short axis_height, minwidth, minheight, winwidth, winheight;
  char *fontname, string[65];
  char prompt[50], defaultgeom[20];     /* for XCreate */
  float xscale, yscale, yrange, yfactor, absmax;
  int points, max_pts, length;


  /* create the window here so that the info will be obtained for later
     use in all the graphics computations. If there is no window with the 
     specified window id, one will be created. In either case, the width 
     and height of the window will then be placed into "winwidth" and 
     "winheight". This is so cumbersome because XCreate and XQueryWindow 
     do NOT use the same structure for window information - What a Drag!!! */

  if (*windowid == 0)  /* there is no window for this signal yet, so */
    {                  /* use XCreate, and get info through "frame" */

      minwidth = 200;                    /* min width and height of */
      minheight = 100;                   /* window made by XCreate */

      frame.border = BlackPixmap;        /* the window frame array */
      frame.background = WhitePixmap;    /* to store window info in */
      frame.bdrwidth = BDR;
                             /* Prompt for window creation */
      sprintf(prompt, "Create Window for %s", label);
                             /* Default geometry specs for the window */
      sprintf(defaultgeom, "=%dx%d+%d+%d", WIDTH, HEIGHT, XINIT, YINIT);

      *windowid = XCreate(prompt, "", "", defaultgeom, 
			  &frame, minwidth, minheight);
      
      winwidth = frame.width;
      winheight = frame.height;
    }
  else          /* this signal already has a window to draw to, so */
    {           /* just re-use the window, and get the info via XQuery */

      XQueryWindow(*windowid, &info);
      
      winwidth = info.width;
      winheight = info.height;
    }

  /* set new width and height so we leave a 20% border around the plot */

  newwidth = (int) (0.8 * winwidth);  /* new width is 80% of window width */
  max_pts = newwidth;                 /* max points are one per pixel! */
  newheight = (int) (0.8 * winheight);/* new height is 80% of window height */
  xmin = (int) (.1 * winwidth);       /* border width around the plot */
  ymin = (int) (.1 * winheight);      /* border width around the plot */


  {  
    register float *ptr, *maxptr, min, max;
    min = 0.;
    max = 0.;
    
    maxptr = array + npts;                     /* set maxptr to end of array */
    for ( ptr = array ; ptr < maxptr ; ptr++)  /* find max and min of array */
      {
	if (*ptr > max)
	  max = *ptr;
	else if (*ptr < min)
	  min = *ptr;
      }
    if (max >= -min)                           /* and absolute max */
      absmax = max;        
    else 
      absmax = -min;
    /*    printf("max = %f, min = %f, absmax = %f\n", max, min, absmax); */
  

    /* how to draw the x-axis and subsequently, how to scale the y-values. 
       Case 1 - all y-values positive, axis at bottom of window 
       Case 2 - all y-values negative, axis at top of window 
       Case 3 - y-values positive AND negative, axis in center of window 
       The appropriate 'yfactor' will be added to the y-values to allow all 
       plotting to be done by the same function call in the for-loop, which
       assumes that all y-values are positive */
    
    if (min >= 0) 
      {    /* CASE 1 */
	axis_height = ymin + newheight;
	yfactor = 0;
	yrange = max; 
      }
    else if (max <= 0) 
      {    /* CASE 2 */
	axis_height = ymin;
	yfactor = -min;
	yrange = -min;
      }
    else 
      {    /* CASE 3 */
	axis_height = ymin + (int) (newheight / 2);
	if (max >= -min)
	  {
	    yrange = 2 * max;
	    yfactor = max;
	  }
	else
	  {
	    yrange = 2 * -min; 
	    yfactor = -min;
	  }
      }
    /*  printf("yrange = %f, yfactor = %f\n",yrange, yfactor); */
  }

  /* determine if there are too many points, and if not, remove the sampling
     factor (npts / max_pts) in the for-loop. Also set the number of points
     to be plotted (points) for use by XDraw */

  if (npts < max_pts)
    {
      max_pts = npts;
      points = npts;
    }
  else
    points = max_pts;

  {
    /* take scale factors out of for-loop for faster run-time */

    register float xscale = newwidth / (float) (max_pts - 1);   
    register float yscale = newheight / yrange; 
    register short yzero = winheight - ymin;
    register Vertex *vlistptr;
    register short i;
    register float yaddfactor = yfactor;

    vlistptr = (Vertex *)mmalloc((long)npts * 6);  /* alloc no. of vertices */
    vlisthead = vlistptr;          /* remember beginning of array for XDraw */

    /* put x-y pairs into a vertex list for use by XDraw via a for-loop */

    /* printf("going into loop, max_pts = %d\n",max_pts); */
    for( i = 0 ; i < max_pts; i++, vlistptr++)
      {
	vlistptr->x = xmin + (short) ((float) i * xscale);
	vlistptr->y = yzero  - (short)
	              ((array[i * npts / max_pts] + yaddfactor) * yscale);
	vlistptr->flags = 0;
	/* printf("i = %d, x = %d, y = %d, inm = %d\n", 
	     i, vlistptr->x, vlistptr->y, i * npts / max_pts); */
      }
  }

  /* set up font info... */

  fontname = "6x10";
  font = XGetFont(fontname);
  sprintf(string, "%s  %d points, scalemax %5.3f", label, npts, absmax);
  length = strlen(string);

  if (dsploption == 2) {
	printf("To continue, place cursor on background and press any key.\n");
	XSelectInput(RootWindow, KeyPressed);
	XWindowEvent(RootWindow, KeyPressed, &event);
	do{
	} while (event.type != KeyPressed);
  }

  /* ...map the window to the screen... */

  XMapWindow(*windowid);

  /* ...clear the window and draw the curve... */

  XClear(*windowid);
  XDraw(*windowid, vlisthead, points, 1, 1, BlackPixel, GXcopy, AllPlanes);

  /* ...draw axes... 
     y-axis is always on the left edge, and the x-axis height 
     will be in the position determined by the case we're in */

  XLine(*windowid, xmin, axis_height, (xmin + newwidth), 
	   axis_height, 1, 1,BlackPixel, GXcopy, AllPlanes); /* X axis */
  XLine(*windowid, xmin, ymin, xmin,  (ymin + newheight),
	                1, 1,BlackPixel, GXcopy, AllPlanes); /* Y axis */

  /* ...and draw the label under the curve */

  XText(*windowid, xmin, (ymin + newheight + (ymin / 2)),
	           string, length, font, BlackPixel, WhitePixel);

  XFlush();      /* flush output to the screen */


}
