/*
 * colors.c
 */

#include <wms.h>
#include "base.h"
#include "colors.h"


/**********************************************************************
 * Constants
 **********************************************************************/

#define  maxAnchors  20

/**********************************************************************
 * Forward Declarations
 **********************************************************************/
static void  randcolor(XColor *c, Rnd *r);
static bool  colors_get(Display *dpy, unsigned long *colors, int numColors,
			Rnd *r);


/**********************************************************************
 * Functions
 **********************************************************************/

int colors_new(Display *dpy, unsigned long *colors, int maxColors, Rnd *r) {
  int  numColors = maxColors;

  while (!colors_get(dpy, colors, numColors, r))
    numColors >>= 1;
  if (numColors == 1)
    numColors = 2;
  return(numColors);
}


static bool colors_get(Display *dpy, unsigned long *colors, int numColors,
		       Rnd *r) {
  int  anchors[maxAnchors], numAnchors;
  int  i, j, k, temp, startIndex, endIndex;
  XColor  thisColor, startColor, endColor, color0;
  Colormap cmap = DefaultColormap(dpy, DefaultScreen(dpy));
  Status status;

  if (numColors == 1) {
    thisColor.red = 0;
    thisColor.green = 0;
    thisColor.blue = 0;
    XAllocColor(dpy, cmap, &thisColor);
    for (i = 0;  i < base_limit;  i += 2) {
      colors[i] = thisColor.pixel;  
    }
    thisColor.red = 0xffff;
    thisColor.green = 0xffff;
    thisColor.blue = 0xffff;
    XAllocColor(dpy, cmap, &thisColor);
    for (i = 1;  i < base_limit;  i += 2) {
      colors[i] = thisColor.pixel;  
    }
    colors[base_limit] = BlackPixel(dpy, DefaultScreen(dpy));
    return(TRUE);
  }
  numAnchors = 2 + (rnd_int(r) % ((numColors + 52) / 20));
  if (numAnchors > maxAnchors)
    numAnchors = maxAnchors;
  anchors[0] = 0;
  for (i = 1;  i < numAnchors;  ++i) {
    do {
      anchors[i] = rnd_int(r) % numColors;
      for (j = 0;  j < i;  ++j) {
	if (anchors[j] == anchors[i])
	  break;
      }
    } while (j != i);
    for (j = 0;  j < i;  ++j) {
      if (anchors[j] > anchors[i]) {
	temp = anchors[j];
	anchors[j] = anchors[i];
	anchors[i] = temp;
      }
    }
  }
  randcolor(&color0, r);
  endColor = color0;
  for (i = 0;  i < numAnchors;  ++i) {
    startColor = endColor;
    startIndex = anchors[i];
    if (i + 1 < numAnchors) {
      randcolor(&endColor, r);
      endIndex = anchors[i + 1];
    } else {
      endColor = color0;
      endIndex = numColors;
    }
    for (j = startIndex;  j < endIndex;  ++j) {
      thisColor.red = ((ulong)startColor.red * (endIndex - j) +
		       (ulong)endColor.red * (j - startIndex) +
		       ((endIndex - startIndex) >> 1)) /
	(endIndex - startIndex);
      thisColor.green = ((ulong)startColor.green * (endIndex - j) +
			 (ulong)endColor.green * (j - startIndex) +
			 ((endIndex - startIndex) >> 1)) /
	(endIndex - startIndex);
      thisColor.blue = ((ulong)startColor.blue * (endIndex - j) +
			(ulong)endColor.blue * (j - startIndex) +
			((endIndex - startIndex) >> 1)) /
	(endIndex - startIndex);
      status = XAllocColor(dpy, cmap, &thisColor);
      if (status == 0) {
	XFreeColors(dpy, DefaultColormap(dpy,
					 DefaultScreen(dpy)),
		    colors, j, 0);
	return(FALSE);
      }
      for (k = j;  k < base_limit;  k += numColors) {
	colors[k] = thisColor.pixel;
      }
    }
  }
  colors[base_limit] = BlackPixel(dpy, DefaultScreen(dpy));

  return(TRUE);
}


void colors_free(Display *dpy, unsigned long *colors, int numColors) {
  if (numColors > 2) {
    XFreeColors(dpy, DefaultColormap(dpy,
				     DefaultScreen(dpy)),
		colors, numColors, 0);
  }
}


static void  randcolor(XColor *c, Rnd *r) {
  c->red = rnd_int(r) & 0xffff;
  c->green = rnd_int(r) & 0xffff;
  c->blue = rnd_int(r) & 0xffff;
}

