/* GNOME clock & mailcheck applet
 * (C) 1999 John Ellis
 *
 * Author: John Ellis
 *
 */

#include "clockmail.h"

#include "backgrnd.xpm"
#include "digmed.xpm"
#include "mailpics.xpm"

static GdkPixmap *get_pixmap_from_data(gchar **data);
static GdkPixmap *get_pixmap_from_file(gchar *path);
static DigitData *new_digit(GdkPixmap *pixmap);
static DigitData *new_digit_from_data(gchar **data);
static DigitData *new_digit_from_file(gchar *file);
static void free_digit(DigitData *digit);
static NumberData *new_number(DigitData *digits, gint length, gint zeros, gint x, gint y);
static void free_number(NumberData *number);
static ItemData *new_item(GdkPixmap *pixmap, gint sections, gint x, gint y);
static ItemData *new_item_from_data(gchar **data, gint sections, gint x, gint y);
static ItemData *new_item_from_file(gchar *file, gint sections, gint x, gint y);
static void free_item(ItemData *item);
static SkinData *new_skin();
static void draw_digit(DigitData *digit, gint n, gint x, gint y, AppData *ad);
static SkinData *load_default_skin();
static ItemData *get_item(gchar *path, gchar *datafile, gchar *name, gint sections, gint vertical);
static DigitData *get_digit(gchar *path, gchar *datafile, gchar *name, gint vertical);
static NumberData *get_number(gchar *path, gchar *datafile, gchar *name, gint count, gint zeros, gint vertical, SkinData *skin);
static GtkWidget *get_background(gchar *path, gchar *datafile, gint vertical);
static SkinData *load_skin(gchar *skin_path, gint vertical);

static GdkPixmap *get_pixmap_from_data(gchar **data)
{
	GdkPixmap *pixmap = NULL;
	GdkBitmap *mask = NULL;

	gdk_imlib_data_to_pixmap(data, &pixmap, &mask);
	if (mask) gdk_imlib_free_bitmap(mask);
	return pixmap;
}

static GdkPixmap *get_pixmap_from_file(gchar *path)
{
	GdkPixmap *pixmap = NULL;
	GdkBitmap *mask = NULL;

	if (!g_file_exists(path)) return NULL;

	gdk_imlib_load_file_to_pixmap(path, &pixmap, &mask);
	if (mask) gdk_imlib_free_bitmap(mask);
	return pixmap;
}

void redraw_skin(AppData *ad)
{
	gdk_window_set_back_pixmap(ad->display_area->window,ad->skin->background,FALSE);
	gdk_window_clear(ad->display_area->window);
}

static DigitData *new_digit(GdkPixmap *pixmap)
{
	DigitData *digit;
	gint width;
	gint height;

	digit = g_new0(DigitData, 1);

	gdk_window_get_size (pixmap, &width, &height);

	digit->pixmap = pixmap;
	digit->width = width / 11;
	digit->height = height;

	return digit;
}

static DigitData *new_digit_from_data(gchar **data)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_data(data);

	return new_digit(pixmap);
}

static DigitData *new_digit_from_file(gchar *file)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_file(file);
	if (!pixmap) return NULL;

	return new_digit(pixmap);
}

static void free_digit(DigitData *digit)
{
	if (!digit) return;
	if (digit->pixmap) gdk_imlib_free_pixmap(digit->pixmap);
	g_free(digit);
}

static NumberData *new_number(DigitData *digits, gint length, gint zeros, gint x, gint y)
{
	NumberData *number;
	number = g_new0(NumberData, 1);

	number->digits = digits;
	number->length = length;
	number->zeros = zeros;
	number->x = x;
	number->y = y;

	return number;
}

static void free_number(NumberData *number)
{
	if (!number) return;
	g_free(number);
}

static ItemData *new_item(GdkPixmap *pixmap, gint sections, gint x, gint y)
{
	ItemData *item;
	gint width;
	gint height;

	item = g_new0(ItemData, 1);

	gdk_window_get_size (pixmap, &width, &height);

	item->pixmap = pixmap;
	item->width = width;
	item->height = height / sections;
	item->sections = sections;
	item->x = x;
	item->y = y;

	return item;
}

static ItemData *new_item_from_data(gchar **data, gint sections, gint x, gint y)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_data(data);

	return new_item(pixmap, sections, x, y);
}

static ItemData *new_item_from_file(gchar *file, gint sections, gint x, gint y)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_file(file);
	if (!pixmap) return NULL;

	return new_item(pixmap, sections, x, y);
}

static void free_item(ItemData *item)
{
	if (!item) return;
	if (item->pixmap) gdk_imlib_free_pixmap(item->pixmap);
	g_free(item);
}

static SkinData *new_skin()
{
	SkinData *s;
	s = g_new0(SkinData, 1);
	return s;
}

void sync_window_to_skin(AppData *ad)
{
	if (!ad->skin) return;

	/* Fix ME! Fix ME! Fix ME! Fix ME! Fix ME! Fix ME! Fix ME! */
	/* all this, and I can't make the applet smaller */
	gtk_drawing_area_size(GTK_DRAWING_AREA(ad->display_area), ad->skin->width, ad->skin->height);
	gtk_widget_set_usize(ad->display_area, ad->skin->width, ad->skin->height);
	gtk_widget_set_usize(ad->applet, ad->skin->width, ad->skin->height);
	redraw_skin(ad);
	/* attempt to set the applets shape, to no avail */
/*	gdk_window_shape_combine_mask (ad->applet->window, ad->skin->mask, 0, 0);*/
	gdk_window_shape_combine_mask (ad->display_area->window, ad->skin->mask, 0, 0);

	if (ad->skin->mail)
		ad->mail_sections = ad->skin->mail->sections;
	else
		ad->mail_sections = 1;

	/* we are forcing some redraws here */
	ad->old_week = -1;
	ad->old_n = -1;
	ad->old_amount = -1;
}

void free_skin(SkinData *s)
{
	if (!s) return;
	if(s->pixmap) gtk_widget_destroy(s->pixmap);
	free_number(s->hour);
	free_number(s->min);
	free_number(s->sec);
	free_number(s->month);
	free_number(s->day);
	free_number(s->year);
	free_number(s->mail_count);
	free_digit(s->dig_small);
	free_digit(s->dig_large);
	free_item(s->mail);
	free_item(s->month_txt);
	free_item(s->week_txt);
	free_item(s->mail_amount);
	g_free(s);
}

static void draw_digit(DigitData *digit, gint n, gint x, gint y, AppData *ad)
{
	if (!digit) return;

	if (n == -1)
		gdk_draw_pixmap(ad->skin->background,
			ad->display_area->style->fg_gc[GTK_WIDGET_STATE(ad->display_area)],
			digit->pixmap, digit->width * 10, 0, x, y, digit->width, digit->height);
	if (n >= 0 && n <= 9)
		gdk_draw_pixmap(ad->skin->background,
			ad->display_area->style->fg_gc[GTK_WIDGET_STATE(ad->display_area)],
			digit->pixmap, n * digit->width, 0, x, y, digit->width, digit->height);
}

void draw_number(NumberData *number, gint n, AppData *ad)
{
	gint i, d;
	gint t = 1;
	gint x;
	gint z;
	DigitData *digit;

	if (!number) return;

	x = number->x;
	z = number->zeros;
	digit = number->digits;

	for (i=0; i< number->length - 1; i++) t = t * 10;
	x += number->length * digit->width;
	for (i=number->length; i > 0; i--)
		{
		d = n / t;
		n -= d * t;
		t = t / 10;
		if (d == 0 && i>1 && (!z))
			d = -1;
		else
			z = TRUE;
		draw_digit(digit, d, x - (i * digit->width), number->y, ad);
		}
}

void draw_item(ItemData *item, gint section, AppData *ad)
{
	if (!item) return;

	gdk_draw_pixmap (ad->skin->background,
		ad->display_area->style->fg_gc[GTK_WIDGET_STATE(ad->display_area)],
		item->pixmap, 0, item->height * section, item->x, item->y, item->width, item->height);
	
}

static SkinData *load_default_skin()
{
	SkinData *s;
	gint width, height;

	s = new_skin();

	s->pixmap = gnome_pixmap_new_from_xpm_d(backgrnd_xpm);
	s->background = GNOME_PIXMAP(s->pixmap)->pixmap;
	s->mask = GNOME_PIXMAP(s->pixmap)->mask;

	gdk_window_get_size (s->background, &width, &height);

	s->width = width;
	s->height = height;

	s->dig_large = new_digit_from_data((gchar **)digmed_xpm);

	s->hour = new_number(s->dig_large, 2, FALSE, 3, 4);
	s->min = new_number(s->dig_large, 2, TRUE, 26, 4);

	s->mail = new_item_from_data((gchar **)mailpics_xpm, 10, 3, 23);
	return s;
}

/* the following are functions for loading external skins */

static ItemData *get_item(gchar *path, gchar *datafile, gchar *name, gint sections, gint vertical)
{
	ItemData *item;
	gchar **vector = NULL;
	gint length;
	gchar *filename;
	gchar *lang_filename = NULL;
	gint x;
	gint y;
	gchar *prefix;

	if (vertical)
		prefix = g_strconcat ("=", datafile, "=/Vertical/", NULL);
	else
		prefix = g_strconcat ("=", datafile, "=/Horizontal/", NULL);

	gnome_config_push_prefix (prefix);
	g_free (prefix);

	gnome_config_get_vector(name, &length, &vector);
	lang_filename = gnome_config_get_translated_string (name);
	gnome_config_pop_prefix();

	if (sections > 0)
		{
		if (!vector || length < 3)
			{
			g_free(lang_filename);
			g_strfreev (vector);
			return NULL;
			}
		}
	else
		{
		if (!vector || length < 4)
			{
			g_free(lang_filename);
			g_strfreev (vector);
			return NULL;
			}
		}

	/* if the language specific file exists, load it instead of the default */
	if (lang_filename)
		{
		filename = g_strconcat(path, "/", lang_filename, NULL);
		g_free (lang_filename);
		if (!g_file_exists(filename))
			{
			g_free(filename);
			filename = g_strconcat(path, "/", vector[0], NULL);
			}
		}
	else
		filename = g_strconcat(path, "/", vector[0], NULL);

	if (sections > 0)
		{
		x = strtol(vector[1], NULL, 0);
		y = strtol(vector[2], NULL, 0);
		}
	else
		{
		sections = strtol(vector[1], NULL, 0);
		x = strtol(vector[2], NULL, 0);
		y = strtol(vector[3], NULL, 0);
		}

	g_strfreev (vector);

	if (!g_file_exists(filename))
		{
		g_free(filename);
		return NULL;
		}

	item = new_item_from_file(filename, sections, x, y);
	g_free(filename);
	return item;
}

static DigitData *get_digit(gchar *path, gchar *datafile, gchar *name, gint vertical)
{
	DigitData *digit;
	gchar *filename;
	gchar *buf = NULL;
	gchar *prefix;

	if (vertical)
		prefix = g_strconcat ("=", datafile, "=/Vertical/", NULL);
	else
		prefix = g_strconcat ("=", datafile, "=/Horizontal/", NULL);

	gnome_config_push_prefix (prefix);
	g_free (prefix);

	buf = gnome_config_get_string(name);
	gnome_config_pop_prefix();

	if (!buf)
		{
		g_free(buf);
		return NULL;
		}

	filename = g_strconcat(path, "/", buf, NULL);
	g_free(buf);

	if (!g_file_exists(filename))
		{
		g_free(filename);
		return NULL;
		}

	digit = new_digit_from_file(filename);
	g_free(filename);
	return digit;
}

static NumberData *get_number(gchar *path, gchar *datafile, gchar *name, gint count, gint zeros, gint vertical, SkinData *skin)
{
	NumberData *number;
	DigitData *digit;
	gchar **vector = NULL;
	gint length;
	gchar *filename;
	gint x;
	gint y;
	gchar *prefix;

	if (vertical)
		prefix = g_strconcat ("=", datafile, "=/Vertical/", NULL);
	else
		prefix = g_strconcat ("=", datafile, "=/Horizontal/", NULL);

	gnome_config_push_prefix (prefix);
	g_free (prefix);

	gnome_config_get_vector(name, &length, &vector);
	gnome_config_pop_prefix();

	if (!vector || length < 3)
		{
		g_strfreev (vector);
		return NULL;
		}

	filename = g_strdup(vector[0]);
	x = strtol(vector[1], NULL, 0);
	y = strtol(vector[2], NULL, 0);

	g_strfreev (vector);

	if (!strcasecmp(filename, "Large"))
		digit = skin->dig_large;
	else if (!strcasecmp(filename, "Small"))
		digit = skin->dig_small;
	else
		{
		g_free(filename);
		return NULL;
		}

	number = new_number(digit, count, zeros, x, y);
	g_free(filename);
	return number;
}

static GtkWidget *get_background(gchar *path, gchar *datafile, gint vertical)
{
	GtkWidget *pixmap = NULL;
	gchar *buf = NULL;
	gchar *filename;
	gchar *prefix;

	if (vertical)
		prefix = g_strconcat ("=", datafile, "=/Vertical/", NULL);
	else
		prefix = g_strconcat ("=", datafile, "=/Horizontal/", NULL);

	gnome_config_push_prefix (prefix);
	g_free (prefix);

	buf = gnome_config_get_string("Background=");
	gnome_config_pop_prefix();

	if (!buf)
		{
		g_free(buf);
		return NULL;
		}

	filename = g_strconcat(path, "/", buf, NULL);
	g_free(buf);

	if (!g_file_exists(filename))
		{
		g_free(filename);
		return NULL;
		}

	pixmap = gnome_pixmap_new_from_file(filename);

	g_free(filename);
	return pixmap;
}

static SkinData *load_skin(gchar *skin_path, gint vertical)
{
	SkinData *s;
	gchar *datafile = g_strconcat(skin_path, "/clockmaildata", NULL);

	if (!g_file_exists(datafile))
		{
		/* no file has been created yet */
		printf("Unable to open skin data file: %s\n",datafile);
		g_free(datafile);
		return NULL;
		}
	s = new_skin();

	/* background */

	s->pixmap = NULL;
	s->pixmap = get_background(skin_path, datafile, vertical);
	if (s->pixmap)
		{
		gint width, height;
		s->background = GNOME_PIXMAP(s->pixmap)->pixmap;
		s->mask = GNOME_PIXMAP(s->pixmap)->mask;
		gdk_window_get_size (s->background, &width, &height);
		s->width = width;
		s->height = height;
		}
	else
		{
		free_skin(s);
		g_free(datafile);
		return NULL;
		}

	s->dig_small = get_digit(skin_path, datafile, "Digit_Small=", vertical);
	s->dig_large = get_digit(skin_path, datafile, "Digit_Large=", vertical);
	s->hour = get_number(skin_path, datafile, "Number_Hour=", 2, FALSE, vertical, s);
	s->min = get_number(skin_path, datafile, "Number_Minutes=", 2, TRUE, vertical, s);
	s->sec = get_number(skin_path, datafile, "Number_Seconds=", 2, TRUE, vertical, s);
	s->month = get_number(skin_path, datafile, "Number_Month=", 2, FALSE, vertical, s);
	s->day = get_number(skin_path, datafile, "Number_Day=", 2, FALSE, vertical, s);
	s->year = get_number(skin_path, datafile, "Number_Year=", 2, TRUE, vertical, s);
	s->mail = get_item(skin_path, datafile, "Mail_Image=", 0, vertical);
	s->mail_amount = get_item(skin_path, datafile, "Item_Mail_Percent=", 0, vertical);
	s->month_txt = get_item(skin_path, datafile, "Item_Month_Text=", 12, vertical);
	s->week_txt = get_item(skin_path, datafile, "Item_Week_text=", 7, vertical);
	s->mail_count = get_number(skin_path, datafile, "Number_Mail=", 4, FALSE, vertical, s);

	g_free(datafile);
	return s;
}

gint change_to_skin(gchar *path, AppData *ad)
{
	SkinData *nsh = NULL;
	SkinData *nsv = NULL;
	SkinData *osh = ad->skin_h;
	SkinData *osv = ad->skin_v;

	printf("changed\n");

	if (!path)
		{
		nsh = load_default_skin();
		}
	else
		{
		nsh = load_skin(path, FALSE);
		nsv = load_skin(path, TRUE);
		}

	if (!nsh) return FALSE;

	ad->skin_h = nsh;
	ad->skin_v = nsv;

	ad->skin = nsh;
	if (nsv && (ad->orient == ORIENT_LEFT || ad->orient == ORIENT_RIGHT))
		{
		ad->skin = nsv;
		}

	sync_window_to_skin(ad);

	free_skin(osh);
	free_skin(osv);

	return TRUE;
}
