
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include <X11/Xutil.h>
#include <X11/StringDefs.h>
#include <sys/param.h>			/* get MAXPATHLEN if possible */
#ifndef MAXPATHLEN
#define MAXPATHLEN 256
#endif
#include <X11/Xmu/CvtCache.h>
#include <X11/Xmu/Drawing.h>

#include "gif.h"

/* This function almost completely lifted from XmuLocateBitmapFile();
   If XReadBitmapFile says the file isn't a valid bitmap file, we try
   to read a GIF instead (this is probably a silly way to go about it.)
   The colors (and how many) will be returned if and only if it's a gif.
 */
XImage *LocateBitmapFile (dpy, screen_no, name, srcname, srcnamelen,
			  widthp, heightp, xhotp, yhotp, colorsP, ncolorsP)
    Display *dpy;
    int screen_no;
    char *name;
    char *srcname;			/* RETURN */
    int srcnamelen;
    int *widthp, *heightp, *xhotp, *yhotp;  /* RETURN */
    XColor **colorsP;
    int *ncolorsP;
{
    Screen *screen = ScreenOfDisplay(dpy, screen_no);
    Window root = RootWindowOfScreen (screen);
    Bool try_plain_name = True;
    XmuCvtCache *cache = _XmuCCLookupDisplay (dpy);
    char **file_paths;
    char filename[MAXPATHLEN];
    unsigned int width, height;
    int xhot, yhot;
    int i;
    static char **split_path_string();

    /*
     * look in cache for bitmap path
     */
    if (cache) {
	if (!cache->string_to_bitmap.bitmapFilePath) {
	    XrmName xrm_name[2];
	    XrmClass xrm_class[2];
	    XrmRepresentation rep_type;
	    XrmValue value;

	    xrm_name[0] = XrmStringToName ("bitmapFilePath");
	    xrm_name[1] = NULL;
	    xrm_class[0] = XrmStringToClass ("BitmapFilePath");
	    xrm_class[1] = NULL;
	    /*
	     * XXX - warning, derefing Display * until XDisplayDatabase
	     */
	    if (!dpy->db) {
		/* what a hack; need to initialize dpy->db */
		(void) XGetDefault (dpy, "", "");
	    }
	    if (XrmQGetResource (dpy->db, xrm_name, xrm_class, 
				 &rep_type, &value) &&
		rep_type == XrmStringToQuark(XtRString)) {
		cache->string_to_bitmap.bitmapFilePath = 
		  split_path_string (value.addr);
	    }
	}
	file_paths = cache->string_to_bitmap.bitmapFilePath;
    }


    /*
     * Search order:
     *    1.  name if it begins with / or ./
     *    2.  "each prefix in file_paths"/name
     *    3.  BITMAPDIR/name
     *    4.  name if didn't begin with / or .
     */

#ifndef BITMAPDIR
#define BITMAPDIR "/usr/include/X11/bitmaps"
#endif

    for (i = 1; i <= 4; i++) {
        int status;
	char *fn = filename;
/*	Pixmap pixmap; */
	char *data;

	switch (i) {
	  case 1:
	    if (!(name[0] == '/' || (name[0] == '.') && name[1] == '/')) 
	      continue;
	    fn = name;
	    try_plain_name = False;
	    break;
	  case 2:
	    if (file_paths && *file_paths) {
		sprintf (filename, "%s/%s", *file_paths, name);
		file_paths++;
		i--;
		break;
	    }
	    continue;
	  case 3:
	    sprintf (filename, "%s/%s", BITMAPDIR, name);
	    break;
	  case 4:
	    if (!try_plain_name) continue;
	    fn = name;
	    break;
	}

/*	status = XReadBitmapFile (dpy, root, fn, &width, &height, 
				  &pixmap, &xhot, &yhot);
 */
	status = XmuReadBitmapDataFromFile (fn, &width, &height, 
					    &data, &xhot, &yhot);

	if (status == BitmapSuccess) {
	  if (widthp) *widthp = (int)width;
	  if (heightp) *heightp = (int)height;
	  if (xhotp) *xhotp = xhot;
	  if (yhotp) *yhotp = yhot;
	  if (srcname && srcnamelen > 0) {
	    strncpy (srcname, fn, srcnamelen - 1);
	    srcname[srcnamelen - 1] = '\0';
	  }
	  {
	    XImage *image = XCreateImage (dpy, DefaultVisual(dpy, screen_no),
					  1, XYBitmap, 0, data,
					  width, height,
					  8, 0);
	    /* Is this portable?  It seems necessary on my color sparc. */
	    image->bitmap_bit_order= LSBFirst;
	    image->byte_order= LSBFirst;
	    
	    return image;
	  }
	}
	else if (status == BitmapFileInvalid) {
	  XImage *image;
	  int status;
	  
	  status = ReadGifFile(dpy, screen_no, fn, &image, colorsP, ncolorsP);
	   switch (status) {
	    case RG_SUCCESS:
	      FrobnicateImage(dpy, screen_no, &image);
	      *widthp  = image->width;
	      *heightp = image->height;
	      *xhotp = 0;
	      *yhotp = 0;
/*
	      image = XCreatePixmapFromBitmapData
	      		(dpy, root, image->data, *widthp, *heightp,
			 1, 0, image->depth);
 */
	      /* ## need to deal with srcname */
	      printf("GIF! w=%d, h=%d, depth=%d\n", *widthp, *heightp,
		     image->depth);
	      return image;

	    case RG_ZCAT_ERROR:
	      fprintf(stderr, "GIF: %s not in compressed format\n", fn);
	      return None /* BitmapFileInvalid */ ;
	    case RG_MALLOC_FAILED:
	      fprintf(stderr, "GIF: couldn't malloc for %s\n", fn);
	      return None /* BitmapFileInvalid */ ;
	    case RG_FILE_NOT_FOUND:
	      fprintf(stderr, "GIF: couldn't find file \"%s\"??\n", fn);
	      return None /* BitmapFileInvalid */ ;
	    case RG_BAD_HEADER:
	    case RG_NOT_GIF_FILE:
	    case RG_CORRUPT:
	    case RG_BAD_COLORTABLE:
	    case RG_BAD_RAW_SPECS:
	    case RG_NO_SEPARATOR:
	      fprintf(stderr, "invalid GIF file %s\n", fn);
	      return None /* BitmapFileInvalid */ ;
	    default:
	      fprintf(stderr, "unknown GIF error %d for %s\n", status, fn);
	      return None /* BitmapFileInvalid */ ;
	   }
        }
    }
    return None;
}

unsigned long DataSize(bpl, height, depth, format)
     int bpl, height, depth, format;
{
    if (format != ZPixmap)
	return (bpl * height * depth);
    else
	return(bpl * height);
}

FrobnicateImage (dpy, scr, image, color_mappings, fg, bg)
     Display *dpy;
     int scr;
     XImage **image;
     unsigned int *color_mappings, fg, bg;
{
  /*
   * Create image that matches default visual.
   */
  XImage *new_image;
  int x, y;
  int width  = (*image)->width;
  int height = (*image)->height;
  int depth  = DefaultDepth(dpy, scr);
  int bytes_per_line = (width+31) / 8;
  int pad    = 32;
  int xoff   = 0;
  
  new_image = XCreateImage(dpy, DefaultVisual(dpy, scr), depth, ZPixmap, xoff,
			   XtMalloc(DataSize(bytes_per_line, height, depth,
					     ZPixmap) * 100),
			   width, height, pad,
			   0 /* bytes_per_line */
			   );
  
  for (y = 0; y < height; ++y) {
    for (x = 0; x < width; ++x) {
      if (color_mappings == 0)
	XPutPixel (new_image, x, y, (XGetPixel(*image, x, y) ? fg : bg));
      else
	XPutPixel (new_image, x, y, color_mappings[XGetPixel(*image, x, y)]);
    }
  }
/*
  for (y = 0; y < height; ++y) {
    for (x = 0; x < width; ++x) {
      printf("%c", XGetPixel(new_image, x, y) ? '*' : ' ');
    }
    printf("\n");
  }
 */
  XDestroyImage (*image);
  *image = new_image;
}


/* lifted without modification from lib/Xmu/LocBitmap.c 
 */

/*
 * split_path_string - split a colon-separated list into its constituent
 * parts; to release, free list[0] and list.
 */
static char **split_path_string (src)
    register char *src;
{
    int nelems = 1;
    register char *dst;
    char **elemlist, **elem;

    /* count the number of elements */
    for (dst = src; *dst; dst++) if (*dst == ':') nelems++;

    /* get memory for everything */
    dst = (char *) malloc (dst - src + 1);
    if (!dst) return NULL;
    elemlist = (char **) calloc ((nelems + 1), sizeof (char *));
    if (!elemlist) {
	free (dst);
	return NULL;
    }

    /* copy to new list and walk up nulling colons and setting list pointers */
    strcpy (dst, src);
    for (elem = elemlist, src = dst; *src; src++) {
	if (*src == ':') {
	    *elem++ = dst;
	    *src = '\0';
	    dst = src + 1;
	}
    }
    *elem = dst;

    return elemlist;
}
