/*
 * io.c
 */

#include <wms.h>

#ifdef  STDC_HEADERS
#include <stdlib.h>
#include <unistd.h>
#endif  /* STDC_HEADERS */
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>

#include "io.h"
#include "colors.h"


/**********************************************************************
 * Forward Declarations
 **********************************************************************/

static void  genericRaster(Io *io, UInt8 *data);
static void  fastRaster32(Io *io, UInt8 *data);
static void  fastRaster8(Io *io, UInt8 *data);


/**********************************************************************
 * functions
 **********************************************************************/
void  io_init(Io *io, const char *dpyName, int maxColors, Rnd *rnd) {
  int  scrn;
  XVisualInfo xvi, *vlr;
  int  i;
    
  if ((io->dpy = XOpenDisplay(dpyName)) == NULL) {
    if (dpyName == NULL) {
      fprintf(stderr, "Could not open default X display.\n");
    } else {
      fprintf(stderr, "Could not open X display \"%s\".\n", dpyName);
    }
    exit(1);
  }
  scrn = DefaultScreen(io->dpy);
  io->w = DisplayWidth(io->dpy, scrn);
  io->h = DisplayHeight(io->dpy, scrn);
  io->rootWin = RootWindow(io->dpy, scrn);
  io->pixmap = XCreatePixmap(io->dpy, io->rootWin, io->w, io->h,
			     DefaultDepth(io->dpy, scrn));
  io->image = XCreateImage(io->dpy, DefaultVisual(io->dpy, scrn),
			   DefaultDepth(io->dpy, scrn),
			   ZPixmap, 0, NULL, io->w, 1, 32, 0);
  io->image->data = wms_malloc(io->image->bytes_per_line);
  xvi.visual = DefaultVisual(io->dpy, scrn);
  xvi.visualid = XVisualIDFromVisual(xvi.visual);
  vlr = XGetVisualInfo(io->dpy, VisualIDMask, &xvi, &i);
  if ((vlr[0].class != TrueColor) && (vlr[0].class < 2)) {
    io->maxColors = 1;
  } else {
    io->maxColors = maxColors;
  }
  io->numColors = colors_new(io->dpy, io->colors, io->maxColors, rnd);
}


void  io_recolor(Io *io, Rnd *rnd) {
  colors_free(io->dpy, io->colors, io->numColors);
  io->numColors = colors_new(io->dpy, io->colors, io->maxColors, rnd);
}


void  io_update(Io *io, int lineNum, UInt8 *data) {
#if WORDS_BIGENDIAN
  genericRaster(io, data);
#else  /* Little endian. */
  if ((io->image->bits_per_pixel == 32) &&
      (io->image->format == ZPixmap) &&
      (io->image->byte_order == LSBFirst) &&
      (io->image->bitmap_bit_order == LSBFirst)) {
    fastRaster32(io, data);
  } else if ((io->image->bits_per_pixel == 8) &&
	     (io->image->format == ZPixmap) &&
	     (io->image->byte_order == LSBFirst) &&
	     (io->image->bitmap_bit_order == LSBFirst)) {
    fastRaster8(io, data);
  } else {
    genericRaster(io, data);
  }
#endif
  XPutImage(io->dpy, io->pixmap, DefaultGC(io->dpy,
					   DefaultScreen(io->dpy)),
	    io->image, 0, 0, 0, lineNum, io->w, 1);
  XSetWindowBackgroundPixmap(io->dpy, io->rootWin, io->pixmap);
  XClearArea(io->dpy, io->rootWin, 0, lineNum, io->w, 1, FALSE);
  XFlush(io->dpy);
}


static void  genericRaster(Io *io, UInt8 *data) {
  int  i, w = io->w;
  XImage *image = io->image;
  ulong *colors = io->colors;
  
  for (i = 0;  i < w;  ++i) {
    XPutPixel(image, i, 0, colors[*(data++)]);
  }
}


static void  fastRaster32(Io *io, UInt8 *data) {
  int  i, w = io->w;
  XImage *image = io->image;
  ulong *colors = io->colors;
  uint32  *imageData;
  
  imageData = (uint32 *)image->data;
  for (i = 0;  i < w;  ++i) {
    *(imageData++) = (uint32)colors[*(data++)];
  }
}


static void  fastRaster8(Io *io, UInt8 *data) {
  int  i, w = io->w;
  XImage *image = io->image;
  ulong *colors = io->colors;
  uchar  *imageData;
  
  imageData = (uchar *)image->data;
  for (i = 0;  i < w;  ++i) {
    *(imageData++) = (uchar)colors[*(data++)];
  }
}
