/* routines to read image files and display on the screen */
/*   calls fileio.c  */

#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"


#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 Argc;
char **Argv;

unsigned char **vis_data;

unsigned char lift_lut[256];

unsigned int   
  data_sets=0,
  channels=0,
  screen_depth;

unsigned long  *plane_masks,pixels[256];
unsigned int   free_pixels=0;

unsigned int   
  bottom=40;



float height_scale=1.0,width_scale=1.0;

/* some flags */

unsigned char 
  color_flag = (char)0xff,
  raw=0,
  fast=0,
  invert=0,
  setroot=0,
  verbose=0,
  fullroot=0;

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



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);
  XSetErrorHandler ((void *)error_hook);
  assign_xcolors();
 }


assign_xcolors()
  {
  XColor         xcolors[256];
  float          color_step,this_color;
  short          shift,i;
  unsigned int   count = 0;
  
  free_pixels = 0;
  bottom      = 40;
  
  for (shift=7;shift>=0;shift--)
    if (XAllocColorCells (dpy,XDefaultColormap (dpy,screen),0,plane_masks,0,&pixels[free_pixels],(unsigned int)1<<shift))
      free_pixels += (unsigned int)1<<shift;

  if (free_pixels < bottom) bottom = 0;
  if (verbose != 0) fprintf (stderr,"Available Pixels :: %d Using %d\n",free_pixels,free_pixels - bottom);
  if (colormap == 0)
    if ((free_pixels - bottom < MIN_PIXELS))
	{
	if (verbose != 0) fprintf (stderr,"Not Enough Free Cells to share resources using own colormap\n");
	colormap = XCreateColormap (dpy, root , pseudocolor_visual, AllocAll);  
	free_pixels = 255;
	bottom      = 0;
	for (i=0;i<free_pixels;i++) pixels[i] = (long)i;
	}
    else colormap = XDefaultColormap(dpy,screen);

  color_step = 255.0  / (float)(free_pixels - bottom);
  for (i=bottom,this_color=0;i<free_pixels;i++,this_color+=color_step)
      { 
      xcolors[count].pixel = pixels[i];
      xcolors[count].red   = (short)(this_color)<<8;   
      xcolors[count].green =  xcolors[count].red; 
      xcolors[count].blue  = xcolors[count].green;
      xcolors[count].flags = color_flag;
      count++;
      }
  XStoreColors (dpy,colormap,xcolors, count);
  if (colormap == XDefaultColormap(dpy,screen)) XFreeColors (dpy,colormap,&pixels[0],free_pixels,0L); 

  color_step = 1.0 / color_step;
  if (!fast)
    if (invert)
      for (i=0;i<=255;i++)
	lift_lut[255-i] = pixels[(unsigned char)(bottom + i*color_step)];
    else
      for (i=0;i<=255;i++)
	lift_lut[i]= (unsigned char)pixels[(unsigned char)(bottom + i*color_step)];
  if (verbose != 0) fprintf (stderr,"the colormap id is %d\n", colormap);
  }





void parse_descriptor (dirname,w,h)
char *dirname;
unsigned int *w, *h;
  {
  FILE *desc_file;
  unsigned char *buffer, *bufstart;
  char filename[128];
  int buflen,width,height;
  
  sprintf (filename,"%s/descriptor",dirname);
  /* read garbage till you get dimensions, maybe theyre capitilized */
  if (verbose != 0) fprintf (stderr,"reading descriptor %s\n",filename);
  if ((desc_file = (FILE *)open_file_noquit (filename,"r")) != NULL) 
    {
    bufstart = buffer = read_entire_file_into_buffer (filename);
    buflen = get_file_size (desc_file);
    while (buffer < bufstart + buflen)
	{
	if ((strncmp (buffer,"_dimension",10) == 0)  ||
	    (strncmp (buffer,"_DIMENSION",10)) ==0)
	    { 
	    while (!isdigit(*buffer)) buffer++;         /* move to numbers */
	    sscanf (buffer,"%d %d",&height,&width);
	    *h = height;
	    *w = width;
	    if (verbose != 0) fprintf (stderr,"DIMENSIONS : %d %d\n",height,width);
	    }
	if ((strncmp (buffer,"_channels",9) == 0)  ||
	    (strncmp (buffer,"_CHANNELS",9)) ==0)
	    { 
	    while (!isdigit(*buffer)) buffer++;    
	    sscanf (buffer,"%d",&channels);
	    if (verbose != 0) fprintf (stderr,"CHANNELS : %d \n",channels);
	    }
	if ((strncmp (buffer,"_data_sets",10) == 0)  ||
	    (strncmp (buffer,"_DATA_SETS",10)) ==0)
	    { 
	    while (!isdigit(*buffer)) buffer++;       
	    sscanf (buffer,"%d",&data_sets);
	    if (verbose != 0) fprintf (stderr,"DATA_SETS : %d \n",channels);
	    }
	buffer++;
	}
    }
  else if (verbose != 0) fprintf (stderr,"could not find descriptor %s...\n",filename);
  if (verbose != 0) fprintf (stderr,"------------------------\n");
  fclose (desc_file);
  free(bufstart);
  }

write_the_image(data,filename,w,h)
     char *filename;
     unsigned char *data;
     unsigned int w,h;
{
  FILE *outfile;

  outfile = open_file(filename, "w");
  if (outfile == 0)
    {
      fprintf(stderr, "cannot open file to write\n");
      exit(1);
    }
  write_image(data, ((int) w*h), outfile);
  fclose(outfile);
}


unsigned char *read_the_image (filename,w,h)
char *filename;
unsigned int *w, *h;
/* usage:  data = read_the_image(filename, &width, &height);
**     where filename is the directory name for an image
*/
  {
  
  FILE *infile;
  char  datfile[128];
  unsigned char *data;
  int n;
  unsigned int width, height;


  if (!raw) parse_descriptor (filename, &width, &height);

  if (!width || !height)        /* descriptor must have failed.. */
      {       
      if (verbose != 0) fprintf (stderr,"no descriptor assuming square ...");
      fflush (stderr);
      infile = open_file (filename,(char *)"r");
      n= get_file_size (infile);
      width = (unsigned int)(sqrt((double)n));
      height = width;

      }
  else 
      {
      if (!raw)
	sprintf (datfile,"%s/data",filename);
      else strcpy (datfile,filename);
      infile = open_file (datfile,"r");
      }
  

  data = read_image (width*height,infile);  /* malloc's data */
  fclose (infile); 
  
  if (verbose != 0) fprintf (stderr,"read the data\n");
  
  *w = width;
  *h = height;
  return data;
  }


Pixmap make_pixmap(data, width, height, pixmap)
     unsigned char *data;  /* must be contiguous in memory in scanline order */
     unsigned int width, height;
     Pixmap pixmap;
{
  int n;
  XImage *image;
  unsigned char *lifted_data;

  lifted_data = (unsigned char *) malloc (width*height);

  if (!fast)
    for (n=0;n<width*height;n++)
      lifted_data[n]= lift_lut[(unsigned char)data[n]];

  image = XCreateImage(dpy,pseudocolor_visual,screen_depth,2,0,lifted_data,width,height,screen_depth,0);  
                             /* Zpixmap = 2 */
  if (verbose != 0) fprintf (stderr,"the image id is %d\n",image);
  
  if (!pixmap) pixmap = XCreatePixmap(dpy,root,width,height,screen_depth);

  XPutImage (dpy,pixmap,gc,image, 0, 0, 0, 0 ,width, height);
  XFree(image);
  if (setroot) free (data);
  free (lifted_data);
  return pixmap;
}


Window make_window(width, height)
unsigned int width, height;
  {
  Window win;
  XSetWindowAttributes attributes;
  XSizeHints sizehints;
  

  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,colormap);
  sizehints.flags = 0;
  XSetStandardProperties(dpy, win, "Xshow",
			 "Xshow", None, Argv, Argc, &sizehints);   
  return win;
}


void show_pixmap(pixmap, win, width, height)
     unsigned int width, height;
     Pixmap pixmap;
     Window win;
/* N.B. :  frees pixmap if window destroyed */
{
  XEvent event;
  
#define blt   XCopyArea (dpy, pixmap,win,gc, 0,0, width,height,0,0);  XFlush (dpy)

  while (1)
      {
      XWindowEvent (dpy, win, KeyPressMask|ExposureMask,&event);
      switch (event.type)
	  {
	    case KeyPress:
	      if (event.xkey.keycode == 61) 
		{
		  XUnmapWindow(dpy,win);
		  XDestroyWindow(dpy, win);
		  /* XFreePixmap(dpy,pixmap);  */
		  exit (1);
		}
	      break;
	   case Expose :
	      blt;
	      break;
	      }
      
      }
  
  }

void redraw_pixmap(pixmap, win, width, height)
     unsigned int width, height;
     Pixmap pixmap;
     Window win;
{
  XCopyArea (dpy, pixmap,win,gc, 0,0, width,height,0,0);  XFlush (dpy);
}


/* call show_image first to initialize a window and create a fork for it. */

void show_image(data, pixmap, win, width, height)  /* pix, win are pointers */
     unsigned char *data;
     unsigned int width, height;
     Window *win;
     Pixmap *pixmap;
/* set pixmap !=0 to redisplay an old one */
{
  setup_x_stuff(); 
  *pixmap = make_pixmap(data,width,height,*pixmap);
  if (!*win) *win = make_window(width, height);
  if (!fork())  /* make child process to monitor window */
    {
      /* fclose(stderr); */
      show_pixmap(*pixmap, *win, width, height);
    }
}

/* call redraw_image to redisplay in an existing window/pixmap */

void redraw_image(data, pixmap, win, width, height)
     unsigned int width, height;
     Pixmap pixmap;
     Window win;
     unsigned char *data;
/* creates a window if none exists, but will not return win, pixmap */
{
  if (!win) show_image(data, &pixmap, &win, width, height);
  else
    {
      make_pixmap(data, width, height, pixmap);
      redraw_pixmap(pixmap, win, width, height);
    }
}

/*********************************************************/
/*  routines to make a big window with multiple pictures */

unsigned int im_width, im_height, win_width, win_height, x_images, y_images;
Window big_window;
Pixmap big_pixmap;

make_big_window(width, height, num_x, num_y)
     unsigned int width, height, num_x, num_y;
{
  XImage *image;
  int w,h;

  win_width = (width+4) * num_x - 4;
  win_height = (height+4) * num_y - 4;
  x_images = num_x;
  y_images = num_y;
  im_height = height;
  im_width = width;

  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);
  vis_data = ucialloc(win_width, win_height);
  XFlush(dpy);
  for(h=0 ; h<win_height ; h++)
    for(w=0 ; w<win_width ; w++)
      {
	(image->data)[(w + h*win_width)] = lift_lut[128];
	vis_data[w][h] = (unsigned char) 128;
      }
  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_big_window()
{
  XEvent event;
  XImage *image;
  FILE *fd;
  float **vis_image;
  char string[10], winfile[100];
  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[(win_width-w-1)][(win_height-h-1)] 
		    = (float) (image->data)[(w + h*win_width)];
	      fifwrite(fd, vis_image, win_width, win_height);
	      */
	      ucifwrite(fd, vis_data, win_width, win_height);
	      /* fifree(vis_image); */
	      fclose(fd);
	      /* XDestroyImage(image); */
	    }
	  break;
	}
    }
}
  

put_big_window(data, x_index, y_index)
     unsigned char *data;
     unsigned int x_index, y_index;
{
  XImage *image;
  unsigned char *lifted_data;
  int n, dest_x, dest_y, x, y;

  dest_x = x_index * (im_width + 4);
  dest_y = y_index * (im_height +4);

  lifted_data = (unsigned char *) malloc (im_width*im_height);

  for (n=0;n<im_width*im_height;n++)
    lifted_data[n]= lift_lut[(unsigned char)data[n]];

  for (y=0 ; y<im_height ; y++)
    for (x=0 ; x<im_width ; x++)
      vis_data[(x+dest_x)][(y+dest_y)] = data[(x + y*im_width)];

  image = XCreateImage(dpy,pseudocolor_visual,screen_depth,2,0,lifted_data,im_width,im_height,screen_depth,0);  
                             /* Zpixmap = 2 */
  if (verbose != 0) fprintf (stderr,"the image id is %d\n",image);
  
  XPutImage (dpy,big_pixmap,gc,image,0,0,dest_x,dest_y,im_width,im_height);
  if (verbose) fprintf(stderr, "put image OK\n");
  XFree(image);
  free (lifted_data);

  XCopyArea(dpy,big_pixmap,big_window,gc,0,0,win_width,win_height,0,0);
  XFlush(dpy);

  
}     
