/*
 * Copyright (c) 1999 Ethan Fischer <allanon@crystaltokyo.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "../configure.h"

#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

#include "../include/aftersteplib.h"
#include "../include/mystyle.h"
#include "../include/mystyle_property.h"
#include "../include/asproperty.h"

#ifdef I18N
#define MAX_FONTSET_NAME_LENGTH  256
#endif

void mystyle_set_property(Display* dpy, Window w, Atom name, Atom type)
{
	MyStyle* style;
	unsigned long* prop;
	int i, nelements;

	nelements = 0;
	for (style = mystyle_first ; style != NULL ; style = style->next)
	{
		nelements += 9;
#ifndef NO_TEXTURE
		nelements += 7 + style->gradient.npoints * 4;
#endif /* NO_TEXTURE */
	}

	prop = safemalloc(sizeof(unsigned long) * nelements);

	i = 0;
	for (style = mystyle_first ; style != NULL ; style = style->next)
	{
		int k;

		prop[i++] = style->set_flags;
		prop[i++] = XInternAtom(dpy, style->name, False);
		prop[i++] = style->text_style;
#ifndef I18N
		prop[i++] = style->font.font->fid;
#else
		prop[i++] = XInternAtom(dpy, style->font.name, False);
#endif
		prop[i++] = style->colors.fore;
		prop[i++] = style->colors.back;
		prop[i++] = style->relief.fore;
		prop[i++] = style->relief.back;
		prop[i++] = style->texture_type;
#ifndef NO_TEXTURE
		prop[i++] = style->max_colors;
		prop[i++] = style->back_icon.pix;
		prop[i++] = style->back_icon.mask;
		prop[i++] = style->tint.red;
		prop[i++] = style->tint.green;
		prop[i++] = style->tint.blue;
		prop[i++] = style->gradient.npoints;
		for (k = 0 ; k < style->gradient.npoints ; k++)
		{
			prop[i++] = style->gradient.color[k].red;
			prop[i++] = style->gradient.color[k].green;
			prop[i++] = style->gradient.color[k].blue;
			prop[i++] = style->gradient.offset[k] * 0x1000000;
		}
#endif /* NO_TEXTURE */
	}
	/* set the property version to 1.1 */
	set_as_property(dpy, w, name, (unsigned long*)prop, nelements * sizeof(unsigned long), (1<<8)+1 );
	free(prop);
}

void mystyle_get_property(Display* dpy, Window w, Atom name, Atom type)
{
	unsigned long* prop;
	size_t i, k, n ;
	unsigned long version;

	if( (prop = get_as_property( dpy, w, name, &n, &version )) == NULL ) 
	    return;
	/* do we know how to handle this version? */
	if (version != (1 << 8) + 1)
	{
		fprintf(stderr, "%s: style property has unknown version %d.%d\n", MyName, (int)version >> 8, (int)version & 0xff);
		return;
	}

	n /= sizeof(unsigned long);
	for (i = 0 ; i < n ; )
	{
		MyStyle* style;
		char* name;
		unsigned long flags = prop[i + 0];

		name = XGetAtomName(dpy, prop[i + 1]);
		if ((style = mystyle_find(name)) == NULL)
			style = mystyle_new_with_name(name);
		XFree(name);

		/* free up any resources that are already in use */
		if (style->user_flags & F_FONT)
			unload_font(&style->font);
#ifndef NO_TEXTURE
		if (style->user_flags & F_BACKGRADIENT)
		{
			free(style->gradient.color);
			free(style->gradient.offset);
		}
		if (style->user_flags & F_BACKPIXMAP)
		{
			if (style->back_icon.pix != None)
				XFreePixmap (dpy, style->back_icon.pix);
			if (style->back_icon.mask != None)
				XFreePixmap (dpy, style->back_icon.mask);
		}
		if (style->user_flags & F_BACKTRANSPIXMAP)
			XDestroyImage(style->back_icon.image);
#endif /* NO_TEXTURE */

		style->user_flags = 0;
		style->inherit_flags = flags;
		style->text_style = prop[i + 2];
		
		if (style->inherit_flags & F_FONT)
		{
#ifndef I18N
			XFontStruct* font = XQueryFont(dpy, prop[i + 3]);
			style->font.name = NULL;
			style->font.font = font;
			if (font != NULL)
			{
				style->font.width = font->max_bounds.rbearing + font->min_bounds.lbearing;
				style->font.height = font->ascent + font->descent;
				style->font.y = font->ascent;
			}
#else
			name = XGetAtomName(dpy, prop[i + 3]);
			load_font (name, &style->font);
			XFree(name);
#endif
		}
		style->colors.fore = prop[i + 4];
		style->colors.back = prop[i + 5];
		style->relief.fore = prop[i + 6];
		style->relief.back = prop[i + 7];
		style->texture_type = prop[i + 8];
#ifndef NO_TEXTURE
		style->max_colors = prop[i + 9];
		style->back_icon.pix = prop[i + 10];
		style->back_icon.mask = prop[i + 11];
		style->tint.red = prop[i + 12];
		style->tint.green = prop[i + 13];
		style->tint.blue = prop[i + 14];
		style->gradient.npoints = prop[i + 15];
		if (style->inherit_flags & F_BACKGRADIENT)
		{
			style->gradient.color = NEW_ARRAY(XColor, style->gradient.npoints);
			style->gradient.offset = NEW_ARRAY(double, style->gradient.npoints);
			for (k = 0 ; k < style->gradient.npoints ; k++)
			{
				style->gradient.color[k].red = prop[i + 16 + k * 4 + 0];
				style->gradient.color[k].green = prop[i + 16 + k * 4 + 1];
				style->gradient.color[k].blue = prop[i + 16 + k * 4 + 2];
				style->gradient.offset[k] = (double)prop[i + 16 + k * 4 + 3] / 0x1000000;
			}
			style->user_flags |= F_BACKGRADIENT;
			style->inherit_flags &= ~F_BACKGRADIENT;
		}
		/* if there's a backpixmap, make sure it's valid and get its geometry */
		if (style->inherit_flags & F_BACKPIXMAP)
		{
			Window junk_w;
			int junk;
			if (!XGetGeometry (dpy, style->back_icon.pix, &junk_w, &junk, &junk, &style->back_icon.width, &style->back_icon.height, &junk, &junk))
			{
				style->texture_type = 0;
				style->back_icon.pix = None;
				style->back_icon.mask = None;
				style->inherit_flags &= ~(F_BACKPIXMAP | F_BACKTRANSPIXMAP);
			}
		}
		else if (style->inherit_flags & F_BACKTRANSPIXMAP)
		{
			fprintf(stderr, "Transpixmap requested, but no pixmap detected for style '%s'\n", style->name);
			fprintf(stderr, "This is a bug, please report it!\n");
			style->inherit_flags &= ~F_BACKTRANSPIXMAP;
		}

		/* set back_icon.image if necessary */
		if (style->inherit_flags & F_BACKTRANSPIXMAP)
		{
			MyStyle* tmp;
			/* try to find another style with the same pixmap to inherit from */
			for (tmp = mystyle_first ; tmp != NULL ; tmp = tmp->next)
			{
				if (tmp == style)
					continue;
				if ((tmp->set_flags & (F_BACKPIXMAP | F_BACKTRANSPIXMAP)) && style->back_icon.pix == tmp->back_icon.pix)
				{
					style->back_icon.image = tmp->back_icon.image;
					break;
				}
			}
			/* that failed, so create the XImage here */
			if (tmp == NULL)
			{
				style->back_icon.image = XGetImage(dpy, style->back_icon.pix, 0, 0, style->back_icon.width, style->back_icon.height, AllPlanes, ZPixmap);
				style->user_flags |= F_BACKTRANSPIXMAP;
				style->inherit_flags &= ~F_BACKTRANSPIXMAP;
			}
		}
		i += 7 + style->gradient.npoints * 4;
#endif /* NO_TEXTURE */
		i += 9;
		style->set_flags = style->user_flags | style->inherit_flags;
	}

	/* force update of global gcs */
	mystyle_fix_styles();
	mystyle_set_global_gcs (NULL);

	XFree(prop);
}

