# include "Ximage.h"

/* DirectColor doesn't seem to work, even though it is available:
   I cannot use XAllocColorCells to get pixels under DirectColor
*/

/* static int try_visual[] = {5, 3, 1, 4, 2, 0}; */

void CheckVisual (Graphic *graphic, int *argc, char **argv) {

  int i, Nfound, N;
  int isColor, isDefault, isDynamic;
  XVisualInfo *visual_list, visual_temp;
  unsigned long planes[3];
  XPixmapFormatValues *pixmaps;
  int Npixmaps, Npixels;

  if (DEBUG) {
    fprintf (stderr, "DirectColor: %d\n", DirectColor);
    fprintf (stderr, "PseudoColor: %d\n", PseudoColor);
    fprintf (stderr, "TrueColor:   %d\n", TrueColor);
    fprintf (stderr, "GrayScale:   %d\n", GrayScale);
    fprintf (stderr, "StaticColor: %d\n", StaticColor);
    fprintf (stderr, "StaticGray:  %d\n", StaticGray);
  }

  visual_temp.screen = graphic[0].screen;
  
  /* find available visuals */
  visual_list = XGetVisualInfo (graphic[0].display, VisualScreenMask, &visual_temp, &Nfound);
  if (Nfound == 0) {
    fprintf (stderr, "error finding useful visual\n");
    exit (0);
  }
  
  /* check default visual first */ 
  for (i = 0; (i < Nfound) && (graphic[0].visual != visual_list[i].visual); i++);
  if (i == Nfound) {
    fprintf (stderr, "default visual not found??\n");
    exit (0);
  }

  // set these based on selected visual
  isColor = isDefault = isDynamic = FALSE;

  // attempt to select the most desirable type of visual: Default as PseudoColor (XXX is it still true?)
  if (DEBUG) fprintf (stderr, "default visual class is %d\n", visual_list[i].class);
  if (visual_list[i].class == PseudoColor) {
    isColor = isDefault = isDynamic = TRUE;
    graphic[0].visual = visual_list[i].visual;
    graphic[0].visualclass = TRUE;
    goto test_pixels;
  }

  // attempt to select the most desirable type of visual: PseudoColor (XXX is it still true?)
  for (i = 0; (i < Nfound) && (visual_list[i].class != PseudoColor); i++);
  if (i != Nfound) {
    isColor = isDynamic = TRUE;
    if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
    isDefault = (graphic[0].visual == visual_list[i].visual);
    graphic[0].visual = visual_list[i].visual;
    graphic[0].visualclass = TRUE;
    goto test_pixels;
  }

  // attempt to select the most desirable type of visual: GrayScale (XXX is it still true?)
  for (i = 0; (i < Nfound) && (visual_list[i].class != GrayScale); i++);
  if (i != Nfound) {
    isDynamic = TRUE;
    if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
    isDefault = (graphic[0].visual == visual_list[i].visual);
    graphic[0].visual = visual_list[i].visual;
    graphic[0].visualclass = TRUE;
    goto test_pixels;
  }

  // attempt to select the most desirable type of visual: TrueColor (XXX is it still true?)
  for (i = 0; (i < Nfound) && (visual_list[i].class != TrueColor); i++);
  if (i != Nfound) {
    isColor = TRUE;
    if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
    isDefault = (graphic[0].visual == visual_list[i].visual);
    graphic[0].visual = visual_list[i].visual;
    graphic[0].visualclass = FALSE;
    goto test_pixels;
  }

  // attempt to select the most desirable type of visual: TrueColor (XXX is it still true?)
  for (i = 0; (i < Nfound) && (visual_list[i].class != StaticColor); i++);
  if (i != Nfound) {
    if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
    isDefault = (graphic[0].visual == visual_list[i].visual);
    graphic[0].visual = visual_list[i].visual;
    graphic[0].visualclass = FALSE;
    goto test_pixels;
  }

  // attempt to select the most desirable type of visual: TrueColor (XXX is it still true?)
  for (i = 0; (i < Nfound) && (visual_list[i].class != StaticGray); i++);
  if (i != Nfound) {
    if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
    isDefault = (graphic[0].visual == visual_list[i].visual);
    graphic[0].visual = visual_list[i].visual;
    graphic[0].visualclass = FALSE;
    goto test_pixels;
  }

  test_pixels:

  /* need to make a colormap if 
     1) the selected visual is not the default 
     2) there are not enough colors available */

  /* NEED TO ADD A COUPLE LINES DEFINING THE VARIOUS HARD COLORS (BLACK, WHITE, AND THE OVERLAYS) */

  // allow user to force a private colormap
  if ((N = get_argument (*argc, argv, "-private"))) {
    remove_argument(N, argc, argv);
    isDefault = FALSE;
  } 

  // allocate a private colormap, if needed
  if (!isDefault) {
    if (DEBUG) fprintf (stderr, "allocated private colormap\n");
    graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, AllocNone);
  }

  if (isDynamic) {
    Npixels = NPIXELS_DYNAMIC;
    if ((N = get_argument (*argc, argv, "-ncolors"))) {
      remove_argument(N, argc, argv);
      Npixels = atoi (argv[N]);
      remove_argument(N, argc, argv);
    } 

    /* allocate color cells */
    ALLOCATE (graphic[0].pixels, unsigned long, Npixels);
    ALLOCATE (graphic[0].cmap,   XColor,        Npixels);
    for (graphic[0].Npixels = Npixels; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
      if (DEBUG) fprintf (stderr, "trying %d colors\n", (int) graphic[0].Npixels);
      if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels)) {
	break;
      }
    }

    /* insufficient cells, can we make a private colormap? */
    if (graphic[0].Npixels < 16) {
      if (!isDefault) {
	fprintf (stderr, "can't allocate enough cells in private colormap\n");
	exit (0);
      }
      if (DEBUG) fprintf (stderr, "can't allocate enough cells, using private colormap\n");
      graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, AllocNone);

      for (graphic[0].Npixels = NPIXELS_DYNAMIC; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
	if (DEBUG) fprintf (stderr, "trying %d colors\n", (int) graphic[0].Npixels);
	if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels)) {
	  break;
	}
      }

      if ((N = get_argument (*argc, argv, "-colorcount"))) {
	fprintf (stderr, "kapa can grab %d colors\n", graphic[0].Npixels);
	exit (0);
      } 
      if (graphic[0].Npixels < 16) {
	fprintf (stderr, "can't even allocate enough cells in private colormap\n");
	exit (0);
      }
    }
  } else {
    Npixels = NPIXELS_STATIC;
    if ((N = get_argument (*argc, argv, "-ncolors"))) {
      remove_argument(N, argc, argv);
      Npixels = atoi (argv[N]);
      remove_argument(N, argc, argv);
    } 

    // XXX allocate the unsigned long *pixels here and above
    ALLOCATE (graphic[0].pixels, unsigned long, Npixels);
    ALLOCATE (graphic[0].cmap,   XColor,        Npixels);
    graphic[0].Npixels = Npixels;
  }

  if ((N = get_argument (*argc, argv, "-colorcount"))) {
    fprintf (stderr, "kii can grab %d colors\n", graphic[0].Npixels);
    exit (0);
  } 
  
  pixmaps = XListPixmapFormats (graphic[0].display, &Npixmaps);
  for (i = 0; i < Npixmaps; i++) {
    if (pixmaps[i].depth == graphic[0].depth) {
      graphic[0].Nbits = pixmaps[i].bits_per_pixel;
    }
  }
}
