/* graphics primitives */

#include "graph_primi.h"
#include "colors.h"
#include <stdio.h>

extern XFontStruct *font_big, *font_small;
extern GC staticgc;
extern GC gcplane;
extern Window staticwindow;
extern Display *display;
extern int screen_num;

int media = SCREEN;
extern FILE *ps;


void gp_drawline (int x1, int y1, int x2, int y2)
{
  switch (media) {
  case SCREEN:
    XDrawLine (display, staticwindow, staticgc, x1, y1, x2, y2);
    break;
  case POSTSCRIPT:
    fprintf (ps, "newpath\n%d %d moveto\n%d %d lineto\nstroke\n\n",
	     x1, y1, x2, y2);
    break;
  }
}


void gp_drawcircle (int x, int y, int radius)   /* radius or diameter? */
{
  switch (media) {
  case SCREEN:
    XDrawArc (display, staticwindow, staticgc, x-radius/2, y-radius/2,
	      radius, radius, 0, 360*64);
    
    break;
  case POSTSCRIPT:
    if (radius > 1)
      fprintf (ps, "newpath\n%d %d %d 0 360 arc\nstroke\n", x, y, (int) radius/2);
    else
      fprintf (ps, "newpath\n%d %d 1 0 360 arc\nfill\n", x, y);
    break;
  }
}


void gp_drawrect (int x1, int y1, int x2, int y2)
{
  switch (media) {
  case SCREEN:
    XDrawRectangle (display, staticwindow, staticgc, x1, y1, 
		    x2-x1, y2-y1);
    break;
  case POSTSCRIPT:
    fprintf (ps, "newpath\n%d %d moveto\n%d %d lineto\n", x1, y1, x1, y2);
    fprintf (ps, "%d %d lineto\n%d %d lineto\n", x2, y2, x2, y1);
    fprintf (ps, "closepath\nstroke\n");
    break;
  }
}


/* draw filled rectangle using polygon */

void gp_drawfilledrect (int x1, int y1, int x2, int y2)
{
  int x[4], y[4];

  x[0] = x1; y[0] = y1; 
  x[1] = x2; y[1] = y1;
  x[2] = x2; y[2] = y2;
  x[3] = x1; y[3] = y2;

  switch (media) {
  case SCREEN:
  case POSTSCRIPT:
    gp_drawarea (x, y, 4);
    gp_drawrect (x1, y1, x2, y2);
    break;
  }
}


/* draw polygon */

void gp_drawarea (int *x, int *y, int numpoints)
{
  XPoint points[200];
  int i;

  for (i=0; i<numpoints; i++)
    {
      points[i].x = x[i];
      points[i].y = y[i];
    }
  
  switch (media) {
  case SCREEN:
    XFillPolygon (display, staticwindow, staticgc, points, numpoints, Complex,
		  CoordModeOrigin);
    break;
  case POSTSCRIPT:
    fprintf (ps, "newpath\n%d %d moveto\n", points[0].x, points[0].y);
    for (i=1; i<numpoints; i++)
      fprintf (ps, "%d %d lineto\n", points[i].x, points[i].y);
    fprintf (ps, "closepath\nfill\n");

    break;
  }
}


void gp_setlinestyle (int width, int style)
{
  static char dash1[] = {12, 6};
  static char dash2[] = {1, 3};

  switch (media) {
  case SCREEN:
    if (style != DOT)
      {
	XSetLineAttributes (display, staticgc, width, style, CapButt, JoinMiter);
	XSetDashes (display, staticgc, 0, dash1, 2);
      }
    else
      {
	XSetLineAttributes (display, staticgc, width, DASH, CapButt, JoinMiter);
	XSetDashes (display, staticgc, 0, dash2, 2);
      }   
    break;
  case POSTSCRIPT:
    fprintf (ps, "%d setlinewidth\n", width);

    if (style == DOT)
      fprintf (ps, "[1 5] 0 setdash\n");
    if (style == DASH)
      fprintf (ps, "[20 10] 0 setdash\n");
    if (style == SOLID)
      fprintf (ps, "[] 0 setdash\n");
    break;
  }
}


void gp_setcolor (int color)
{
  unsigned long valuemask;
  unsigned long pixvalue;
  XGCValues values;
  Colormap cmap;
  XColor colordef;

  switch (media) {
  case SCREEN:
    cmap = DefaultColormap (display, screen_num);
    
    if (extendedcolor())
      {
	pixvalue = pixel (color);
      }
    else
      {
	/* find pixel value for desired color (default: black) */
	pixvalue = BlackPixel (display, screen_num);
	
	switch (color) {
	case BLACK:
	  pixvalue = BlackPixel (display, screen_num);
	  break;
	case WHITE:
	  pixvalue = WhitePixel (display, screen_num);
	  break;
	case NAVYBLUE:
	  if (XParseColor (display, cmap, "NavyBlue", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	  break;
	case SKYBLUE:
	  if (XParseColor (display, cmap, "DeepSkyBlue1", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	  break;
	case PINK:
	  if (XParseColor (display, cmap, "LightPink", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	  break;
	case RED:
	  if (XParseColor (display, cmap, "red1", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	  break;
	case LIGHTGREEN:
	  if (XParseColor (display, cmap, "OliveDrab2", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	  break;
	case YELLOW:
	  if (XParseColor (display, cmap, "yellow1", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	  break;
	case GRAY:
	  if (XParseColor (display, cmap, "Gray", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	case LIGHTGRAY:
	  if (XParseColor (display, cmap, "LightGray", &colordef))
	    if (XAllocColor (display, cmap, &colordef))
	      pixvalue = colordef.pixel;
	}
      }

    values.foreground = pixvalue;
    
    XChangeGC (display, staticgc, GCForeground, &values);
    break;

  case POSTSCRIPT:
    switch (color) {
    case WHITE:
      fprintf (ps, "1 setgray\n");
      break;
    case YELLOW:
      fprintf (ps, "0.8 setgray\n");
      break;
    case SKYBLUE:
      fprintf (ps, "0.6 setgray\n");
      break;
    default:
      fprintf (ps, "0 setgray\n");
    }
    break;
  }
}



void gp_smalltext (int x, int y, char *string)   /* center of string */
{
  int dummy, width, height, i, len;
  XCharStruct info;

  /* replace underscores with blanks */

  len = strlen(string);
  for (i=0; i<len; i++)
    if (string[i] == '_')
      string[i] = ' ';

  switch (media) {
  case SCREEN:
    /* get text extent first */
    
    XTextExtents (font_small, string, strlen(string), &dummy, &dummy, &dummy, &info);
    width = info.width;
    height = info.ascent;
    
    XSetFont(display, staticgc, font_small->fid);
    XDrawString (display, staticwindow, staticgc, x-width/2, y-height/2,
		 string, strlen(string));
    break;
  case POSTSCRIPT:
    fprintf (ps, "/Helvetica-Narrow findfont 11 scalefont setfont\n");
    fprintf (ps, "%d %d\n", y-2, x);
    fprintf (ps, "(%s) stringwidth\npop\n2 div sub exch moveto\n", string);
    fprintf (ps, "gsave 1 -1 scale\n");
    fprintf (ps, "(%s) show\n", string);
    fprintf (ps, "grestore\n");
    break;
  }
}


void gp_bigtext (int x, int y, char *string)   /* center of string */
{
  int dummy, width, height;
  XCharStruct info;

  switch (media) {
  case SCREEN:
    /* get text extent first */
    
    XTextExtents (font_big, string, strlen(string), &dummy, &dummy, &dummy, &info);
    width = info.width;
    height = info.ascent;
    
    XSetFont(display, staticgc, font_big->fid);
    XDrawString (display, staticwindow, staticgc, x-width/2, y-height/2,
		 string, strlen(string));
    break;
  case POSTSCRIPT:
    fprintf (ps, "/Helvetica findfont 11 scalefont setfont\n");
    fprintf (ps, "%d %d\n", y-9, x);
    fprintf (ps, "(%s) stringwidth\npop\n2 div sub exch moveto\n", string);
    fprintf (ps, "(%s) show\n", string);
    break;
  }
}






void gp_setplane (unsigned long plane)
{
  switch (media) {
  case SCREEN:
    XSetPlaneMask (display, gcplane, plane_mask (plane));
    XSetFunction (display, gcplane, GXset);
    break;
  case POSTSCRIPT:
    break;
  }
}


void gp_drawplanearea (int *x, int *y, int numpoints)
{
  XPoint points[200];
  int i;

  for (i=0; i<numpoints; i++)
    {
      points[i].x = x[i];
      points[i].y = y[i];
    }

  switch (media) {
  case SCREEN:
    XFillPolygon (display, staticwindow, gcplane, points, numpoints, Complex,
		  CoordModeOrigin);
    
    break;
  case POSTSCRIPT:
    break;
  }
}




