/*
 * color-drawing.c - demonstrate drawing of pixels, lines, arcs, etc, using
 *		      different foreground colors, in a window.
 * Acknowledgement: Little Unix Programmers Group
 */

#include <X11/Xlib.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

#include "specs.h"

XColor colours[MAX_COLOURS+1];
char *colournames[] = { "red", 
			"brown", 
			"blue", 
			"yellow", 
			"green",
                        "white" };

const unsigned int line_width = 2;  /* line width when drawing on
				       screen */ 
unsigned int width, height;	    /* height and width for the new
				       window.*/ 
Display* display;		    /* pointer to X Display
				       structure. */
GC gc;			            /* GC (graphics context) used for
				       drawing in our window. */
Window win;			    /* pointer to the newly created
				       window. */ 

/*
 * function: create_simple_window. Creates a window with a white background
 *           in the given size.
 * input:    display, size of the window (in pixels), and location of
 *           the window (in pixels).
 * output:   the window's ID.
 * notes:    window is created with a black border, 2 pixels wide.
 *           the window is automatically mapped after its creation.
 */
Window create_simple_window( Display* display, 
			     int width, int height, int x, int y ) {
  int screen_num = DefaultScreen(display);
  int win_border_width = 2;
  Window win;

  /* create a simple window, as a direct child of the screen's */
  /* root window. Use the screen's black and white colors as   */
  /* the foreground and background colors of the window,       */
  /* respectively. Place the new window's top-left corner at   */
  /* the given 'x,y' coordinates.                              */
  win = XCreateSimpleWindow(display, RootWindow(display, screen_num),
                            x, y, width, height, win_border_width,
                            BlackPixel(display, screen_num),
                            WhitePixel(display, screen_num));

  /* make the window actually appear on the screen. */
  XMapWindow(display, win);

  /* flush all pending requests to the X server. */
  XFlush(display);

  return win;
}


GC create_gc( Display* display, Window win, int reverse_video ) {
  GC gc;				/* handle of newly created GC.  */
  unsigned long valuemask = 0;		/* which values in 'values' to  */
					/* check when creating the GC.  */
  XGCValues values;			/* initial values for the GC.   */
  int line_style = LineSolid;		/* style for lines drawing and  */
  int cap_style = CapButt;		/* style of the line's edje and */
  int join_style = JoinBevel;		/*  joined lines.		*/
  int screen_num = DefaultScreen(display);

  gc = XCreateGC(display, win, valuemask, &values);
  if (gc < 0) {
	fprintf(stderr, "XCreateGC: \n");
  }

  /* allocate foreground and background colors for this GC. */
  if (reverse_video) {
    XSetForeground(display, gc, WhitePixel(display, screen_num));
    XSetBackground(display, gc, BlackPixel(display, screen_num));
  }
  else {
    XSetForeground(display, gc, BlackPixel(display, screen_num));
    XSetBackground(display, gc, WhitePixel(display, screen_num));
  }

  /* define the style of lines that will be drawn using this GC. */
  XSetLineAttributes(display, gc,
                     line_width, line_style, cap_style, join_style);

  /* define the fill style for the GC. to be 'solid filling'. */
  XSetFillStyle(display, gc, FillSolid);

  return gc;
}


void initialise_display( ) {
  int screen_num;		/* number of screen to place the window on.  */
  unsigned int display_width,
               display_height;	/* height and width of the X display.        */
  char *display_name = getenv("DISPLAY");  /* address of the X display.      */
  Colormap screen_colormap;     /* color map to use for allocating colors.   */
  Status rc;			/* return status of various Xlib
				   functions.  */
  int i;

  /* open connection with the X server. */
  display = XOpenDisplay(display_name);
  if (display == NULL) {
    fprintf(stderr, "Cannot connect to X server '%s'\n", display_name);
    exit(1);
  }

  /* get the geometry of the default screen for our display. */
  screen_num = DefaultScreen(display);
  display_width = DisplayWidth(display, screen_num);
  display_height = DisplayHeight(display, screen_num);

  width  = (display_width  / 2);
  height = (display_height / 6);

  /* create a simple window, as a direct child of the screen's   */
  /* root window. Use the screen's white color as the background */
  /* color of the window. Place the new window's top-left corner */
  /* at the given 'x,y' coordinates.                             */
  win = create_simple_window(display, width, height, 0, 0);

  /* allocate a new GC (graphics context) for drawing in the window. */
  gc = create_gc(display, win, 0);
  XSync(display, False);

  /* get access to the screen's color map. */
  screen_colormap = DefaultColormap(display, DefaultScreen(display));

  /* allocate the set of colors we will want to use for the drawing. */
  for( i = 0; i <= MAX_COLOURS; ++i ) {
    rc = XAllocNamedColor( display, screen_colormap, 
			   colournames[i], &colours[i], &colours[i] );
    if (rc == 0) {
      fprintf( stderr, 
	       "XAllocNamedColor - failed to allocated '%s' color.\n", 
	       colournames[i]);
      exit(1);
    }
  }

  /* Draw the "grid" of slots on the bridge */ 
  XSetForeground(display, gc, colours[brown].pixel);
  XDrawLine(display, win, gc, 0, height/2, width, height/2);
  for( i = 0; i < POSN_EACH_DIRECTION; ++i ) {
    const int step = width / POSN_EACH_DIRECTION;
    XDrawLine(display, win, gc, step * i, 0, step * i, height);
  }
}

void close_display() {
  /* close the connection to the X server. */
  XCloseDisplay(display);
}


void update_display( int right[POSN_EACH_DIRECTION], 
		     int left[POSN_EACH_DIRECTION] ) {
  int i;
  for( i = 0; i < POSN_EACH_DIRECTION; ++i ) {
    const int step      = width / POSN_EACH_DIRECTION;
    const int offset    = 5;
    const int carheight = ((height-line_width) / 2) - (2 * offset);
    const int carwidth  = (((width - (POSN_EACH_DIRECTION * line_width)) / 
			    POSN_EACH_DIRECTION) - (2 * offset));

    XSetForeground( display, gc, colours[right[i]].pixel );
    XFillRectangle( display, win, gc, step * i + offset, offset, 
		    carwidth, carheight );

    XSetForeground( display, gc, colours[left[i]].pixel );
    XFillRectangle( display, win, gc, step * i + offset, 
		    offset + height / 2, 
		    carwidth, carheight );
  }

  /* flush all pending requests to the X server. */
  XFlush(display);
}



