#include "all.h"

#define MAX_COLORS 3
#define USE_DEFAULT_COLORMAP 1
#define USE_STANDARD_COLORMAP 0

static void chinput_get_colors (char *forecolor,
		char *backcolor, char *bordercolor)
{
	int default_depth;
	Visual *default_visual;

	static char *name[3];

	XColor exact_def;
	Colormap default_cmap;
	int ncolors = 0;
	int colors[MAX_COLORS];
	int i = 5;
	XVisualInfo visual_info;
	
	name[0] = bordercolor;
	name[1] = backcolor;
	name[2] = forecolor;

	/* Try to allocate colors for PseudoColor, TrueColor, 
	 * DirectColor, and StaticColor.  Use black and white
	 * for StaticGray and GrayScale */

	default_depth = DefaultDepth(display, screen_num);
	default_visual = DefaultVisual(display, screen_num);
	default_cmap   = DefaultColormap(display, screen_num);
	if (default_depth == 1)
	{
		/* must be StaticGray, use black and white */
		border_pixel = BlackPixel(display, screen_num);
		background_pixel = WhitePixel(display, screen_num);
		foreground_pixel = BlackPixel(display, screen_num);
		return;
	}

	while (!XMatchVisualInfo(display, screen_num, default_depth, /* visual class */i--, &visual_info))
		;
	
	if (i < 2)
	{
		/* No color visual available at default_depth.
		 * Some applications might call XMatchVisualInfo
		 * here to try for a GrayScale visual 
		 * if they can use gray to advantage, before 
		 * giving up and using black and white.
		 */
		border_pixel = BlackPixel(display, screen_num);
		background_pixel = WhitePixel(display, screen_num);
		foreground_pixel = BlackPixel(display, screen_num);
		return;
	}

	/* otherwise, got a color visual at default_depth */

	/* The visual we found is not necessarily the 
	 * default visual, and therefore it is not necessarily
	 * the one we used to create our window.  However,
	 * we now know for sure that color is supported, so the
	 * following code will work (or fail in a controlled way).
	 * Let's check just out of curiosity: */
/*
	if (visual_info.visual != default_visual)
		printf("%s: PseudoColor visual at default depth is not default visual!\nContinuing anyway...\n", progname);
*/
	for (i = 0; i < MAX_COLORS; i++)
	{
		if (!XParseColor (display, default_cmap, name[i], &exact_def))
		{
			//fprintf(stderr, "%s: color name %s not in database", progname, name[i]);
		}
   		if (!XAllocColor(display, default_cmap, &exact_def)) {
			//fprintf(stderr, "%s: can't allocate color: all colorcells allocated and no matching cell found.\n", progname);
		}
		colors[i] = exact_def.pixel;
		ncolors++;
	}

	border_pixel = colors[0];
	background_pixel = colors[1];
	foreground_pixel = colors[2];
	return;
}

void chinput_alloc_color (char *forecolor, char *backcolor, char *bordercolor)
{
	int i, j, k, l;
	XStandardColormap **best_map_info = NULL;
	int count;
	int strategy = USE_STANDARD_COLORMAP;
	XColor *exact_defs;
	unsigned long attribmask;
	XVisualInfo *vlist, vinfo_template, *v;
	int num_vis;
	XSetWindowAttributes attrib;
	int ncells;
	Visual *visual = NULL;

	if (XGetRGBColormaps (display, RootWindow (display, screen_num),
				best_map_info, &count, XA_RGB_BEST_MAP) == 0)
	{
		chinput_get_colors (forecolor, backcolor, bordercolor);
		strategy = USE_DEFAULT_COLORMAP;
	}
	else if (best_map_info[0] -> colormap)
	{
		if (best_map_info[0] -> red_max == 0)
		{
				strategy = USE_DEFAULT_COLORMAP;
		}
		attrib.colormap = best_map_info[0]->colormap;
	}
	else if (best_map_info[0] -> visualid == 0)
	{
		strategy = USE_DEFAULT_COLORMAP;
	}
	else
	{
		vlist = XGetVisualInfo (display, VisualNoMask, 
				&vinfo_template, &num_vis);
		for (v = vlist; v < vlist + num_vis; v++)
		{
			if (v -> visualid == best_map_info[0] -> visualid)
			{
					visual = v -> visual;
					break;
			}
		}

		best_map_info[0] -> colormap = XCreateColormap
			(display, RootWindow (display, screen_num), visual, AllocAll);

		if (best_map_info[0] -> colormap
				== DefaultColormap (display, screen_num)) 
		{
//			printf("Hardware colormap Immutable: Can't create new colormap.\n");
		}

		attrib.colormap = best_map_info[0] -> colormap;

		ncells = best_map_info[0] -> base_pixel
			+ ((best_map_info[0] -> red_max + 1)
					* (best_map_info[0] -> green_max + 1) 
					* (best_map_info[0] -> blue_max + 1));

		exact_defs = (XColor *) calloc (sizeof (XColor), ncells);

		// permute the levels of red, green and blue
		l = best_map_info[0] -> base_pixel;
		for (i = 0; i < best_map_info[0] -> blue_max; i++)
		{
			for (j = 0; j < best_map_info[0] -> green_max; j++)
			{
				for (k = 0; k < best_map_info[0] -> red_max; k++)
				{
					exact_defs[l].blue =
						65535 * i / best_map_info[0] -> blue_max;
					exact_defs[l].green =
						65535 * j / best_map_info[0] -> green_max;
					exact_defs[l].red =
						65535 * k / best_map_info[0] -> red_max;

					l++;
				}
			}
		}

		XStoreColors (display,
				best_map_info[0] -> colormap, exact_defs, ncells);

		XSetStandardColormap (display, RootWindow (display, screen_num), 
				best_map_info[0], XA_RGB_BEST_MAP);
	}
	if (strategy == USE_STANDARD_COLORMAP)
	{
		background_pixel = best_map_info[0] -> base_pixel
			+ (best_map_info[0] -> red_max
					* best_map_info[0] -> red_mult)
			+ (best_map_info[0] -> green_max
					* best_map_info[0] -> green_mult)
			+ (best_map_info[0] -> blue_max
					* best_map_info[0] -> blue_mult);

		attribmask = CWBackPixel | CWColormap;

		foreground_pixel = (best_map_info[0] -> green_max
				* best_map_info[0] -> green_mult / 2)
				+ best_map_info[0] -> base_pixel;

		border_pixel = (best_map_info[0] -> blue_max *
				best_map_info[0] -> blue_mult / 2) +
				best_map_info[0] -> base_pixel;
	}

}

void chinput_get_font_gc (Window win, GC *gc, 
	XFontStruct *font_info, char *colorname)
{
	unsigned long valuemask = 0;
	// Ignore XGCvalues and use defaults
	XGCValues values;
	unsigned int line_width = 6;
	int line_style = LineOnOffDash;
	int cap_style = CapRound;
	int join_style = JoinRound;
	int dash_offset = 0;
	static char dash_list[] = { 12, 24 };
	int list_length = 2;

	chinput_alloc_color (colorname, "#000000", "#000000");

	// Create default Graphics Context
	*gc = XCreateGC(display, win, valuemask, &values);

	// specify font
	XSetFont(display, *gc, font_info->fid);

	// specify black foreground since default may be white on white
	XSetForeground(display, *gc, foreground_pixel); 

	// set line attributes
	XSetLineAttributes(display, *gc, line_width, line_style, 
			cap_style, join_style);

	// set dashes to be line_width in length
	XSetDashes(display, *gc, dash_offset, dash_list, list_length);
}

void chinput_get_color_gc (Window win, GC *gc, char *colorname)
{
	unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */
	XGCValues values;

	chinput_alloc_color (colorname, "#000000", "#000000");

	*gc = XCreateGC(display, win, valuemask, &values);

	/* specify black foreground since default may be white on white */
	XSetForeground(display, *gc, foreground_pixel);
}

int chinput_get_fontstruct (XFontStruct **font_info, char *fontname)
{
	char **font_list = NULL;
	int  num_ret     = 0;

	font_list = XListFonts (display, fontname, 1, &num_ret);
	if (! num_ret)
		return 0;

	/* Access font */
	if ((*font_info = XLoadQueryFont(display,font_list[0])) == NULL)
	{
		XFreeFontNames (font_list);
		return 0;
	}

//	HZprint_system_message ("Chinput: font \"%s\" loaded.\n", font_list[0]);
//	XFreeFont (display, *font_info);
	XFreeFontNames (font_list);
	return 1;
}
