/* GNOME clock & mailcheck applet
 * (C) 1999 John Ellis
 *
 * Author: John Ellis
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 
 * 02139, USA.
 *
 */

#include "clockmail.h"

static void about_cb (AppletWidget *widget, gpointer data);
static void set_tooltip(struct tm *time_data, AppData *ad);
static void redraw_display(AppData *ad);
static void update_mail_display(int n, AppData *ad);
static void update_time_count(gint h, gint m, gint s, AppData *ad);
static gint blink_callback(gpointer data);
static gint update_display(gpointer data);
static void applet_change_back(GtkWidget *applet, PanelBackType type, char *pixmap,
				GdkColor *color, gpointer data);
static void destroy_applet(GtkWidget *widget, gpointer data);
static AppData *create_new_app(GtkWidget *applet);
static void applet_change_orient(GtkWidget *w, PanelOrientType o, gpointer data);
static gint applet_save_session(GtkWidget *widget, char *privcfgpath,
					char *globcfgpath, gpointer data);
static GtkWidget * applet_start_new_applet(const gchar *goad_id, const char **params, int nparams);

static void about_cb (AppletWidget *widget, gpointer data)
{
	GtkWidget *about;
	const gchar *authors[2];
	gchar version[32];

	g_snprintf(version, sizeof(version), _("%d.%d.%d"),
		   CLOCKMAIL_APPLET_VERSION_MAJ,
		   CLOCKMAIL_APPLET_VERSION_MIN,
		   CLOCKMAIL_APPLET_VERSION_REV);

	authors[0] = _("John Ellis <johne@bellatlantic.net>");
	authors[1] = NULL;

        about = gnome_about_new ( _("Clock and Mail Notify Applet"), version,
			_("(C) 1999"),
			authors,
			_("Released under the GNU general public license.\n"
			"Basic digital clock with date in a tooltip. "
			"Optional 12/24 time display. Mail blinking can be "
			"for any unread mail, or only briefly when new mail arrives."),
			NULL);
	gtk_widget_show (about);
}

/*
 * Get file modification time, based upon the code
 * of Byron C. Darrah for coolmail and reused on fvwm95
 * I updated this by adding the old/new time check so the newmail notifier works
 * the way I wanted to work (eg. newmail is true only when mail has arrived since last check)
 * added a reset command in the event the mail_file has changed from the properties dialog
 */
void check_mail_file_status (int reset, AppData *ad)
{
	struct stat s;
	off_t newsize;
	time_t newtime;
	int status;
	int checktime;

	if (reset)
		{
		ad->mailsize = 0;
		ad->oldtime = 0;
		return;
		}

	/* no need to continue if no mail item is available */
	if (!ad->skin->mail && !ad->skin->mail_amount && !ad->skin->mail_count) return;

	/* check if mail file contains something */
	if (!ad->mail_file) return;

	status = stat (ad->mail_file, &s);
	if (status < 0){
		ad->mailsize = 0;
		ad->anymail = ad->newmail = ad->unreadmail = 0;
		return;
	}
	
	newsize = s.st_size;
	newtime = s.st_mtime;
	ad->anymail = newsize > 0;
	ad->unreadmail = (s.st_mtime >= s.st_atime && newsize > 0);

	checktime = (newtime > ad->oldtime);
	if (newsize >= ad->mailsize && ad->unreadmail && checktime){
		ad->newmail = 1;
		ad->mailcleared = 0;
	} else
		ad->newmail = 0;
	ad->oldtime = newtime;
	ad->mailsize = newsize;
}

static void set_tooltip(struct tm *time_data, AppData *ad)
{
	if (time_data->tm_yday != ad->old_yday)
		{
		gchar date[128];
		strftime(date, 128, "%a, %b %d", time_data);

		if (ad->use_gmt)
			{
			gchar *buf;
			if (ad->gmt_offset == 0)
				{
				buf = g_strconcat (date, _(" (GMT)"), NULL);
				}
			else
				{
				gchar gmt_text[32];
				g_snprintf(gmt_text, sizeof(gmt_text), 
					   _(" (GMT %+d)"), ad->gmt_offset);
				buf = g_strconcat (date, gmt_text, NULL);
				}
			gtk_tooltips_set_tip (ad->tooltips, ad->applet, buf, NULL);
			g_free(buf);
			}
		else
			gtk_tooltips_set_tip (ad->tooltips, ad->applet, date, NULL);
		ad->old_yday = time_data->tm_yday;
		}
}

static void redraw_display(AppData *ad)
{
	redraw_skin(ad);
}

static void update_mail_display(int n, AppData *ad)
{
	if (n != ad->old_n)
		{
		draw_item(ad->skin->mail, n, ad);
		ad->old_n = n;
		}
}

static void update_mail_amount_display(AppData *ad)
{
	if (ad->mailsize != ad->old_amount)
		{
		if (ad->skin->mail_amount)
			{
			gint p;
			if (ad->mailsize >= ad->mail_max * 1024)
				p = ad->skin->mail_amount->sections - 1;
			else
				p = (float)ad->mailsize / ( ad->mail_max * 1024 ) * ad->skin->mail_amount->sections;
			if (p == 0 && ad->anymail && ad->skin->mail_amount->sections > 1) p = 1;
			draw_item(ad->skin->mail_amount, p, ad);
			}
		draw_number(ad->skin->mail_count, ad->mailsize / 1024, ad);
		ad->old_amount = ad->mailsize;
		}
}

static void update_time_count(gint h, gint m, gint s, AppData *ad)
{
	if (ad->am_pm_enable)
		{
		if (h > 12) h -= 12;
		if (h == 0) h = 12;
		}
	draw_number(ad->skin->hour, h, ad);
	draw_number(ad->skin->min, m, ad);
	draw_number(ad->skin->sec, s, ad);
}

static void update_date_displays(gint year, gint month, gint day, gint weekday, AppData *ad)
{
	/* no point in drawing things again if they don't change */
	if (ad->old_week == weekday) return;

	draw_number(ad->skin->year, year, ad);
	draw_number(ad->skin->month, month, ad);
	draw_number(ad->skin->day, day, ad);
	draw_item(ad->skin->month_txt, month, ad);
	draw_item(ad->skin->week_txt, weekday, ad);

	ad->old_week = weekday;
}

static gint blink_callback(gpointer data)
{
	AppData *ad = data;
	ad->blink_lit++;

	if (ad->blink_lit >= ad->mail_sections - 1)
		{
		ad->blink_lit = 0;
		ad->blink_count++;
		}
	update_mail_display(ad->blink_lit, ad);
	redraw_display(ad);

	if (ad->blink_count >= ad->blink_times || !ad->anymail)
		{
		if (ad->always_blink && ad->anymail)
			{
			if (ad->blink_count >= ad->blink_times) ad->blink_count = 1;
			}
		else
			{
			/* reset counters for next time */
			ad->blink_count = 0;
			ad->blink_lit = 0;
			if (ad->anymail)
				update_mail_display(ad->mail_sections - 1, ad);
			else
				update_mail_display(0, ad);
			redraw_display(ad);
			ad->blinking = FALSE;
			return FALSE;
			}
		}

	return TRUE;
}

static gint update_display(gpointer data)
{
	AppData *ad = data;
	time_t current_time;
	struct tm *time_data;

	time(&current_time);

	/* if using a non-local time, calculate it from GMT */
	if (ad->use_gmt)
		{
		current_time += (time_t)ad->gmt_offset * 3600;
		time_data = gmtime(&current_time);
		}
	else
		time_data = localtime(&current_time);

	/* update time */
	update_time_count(time_data->tm_hour,time_data->tm_min, time_data->tm_sec, ad);

	/* update date */
	update_date_displays(time_data->tm_year, time_data->tm_mon, time_data->tm_mday,
				time_data->tm_wday, ad);

	/* set tooltip to the date */
	set_tooltip(time_data, ad);

	/* now check mail */
	check_mail_file_status (FALSE, ad);

	if (!ad->blinking)
		{
		if (ad->anymail)
			if (ad->newmail || ad->always_blink)
				{
				ad->blinking = TRUE;
				ad->blink_timeout_id = gtk_timeout_add(ad->blink_delay,
						(GtkFunction)blink_callback, ad);
				if (ad->newmail && ad->exec_cmd_on_newmail)
					{
					if (ad->newmail_exec_cmd && strlen(ad->newmail_exec_cmd) > 0)
						gnome_execute_shell(NULL, ad->newmail_exec_cmd);
					}
				}
			else
				{
				update_mail_display(ad->mail_sections - 1, ad);
				}
		else
			{
			update_mail_display(0, ad);
			}
		}

	update_mail_amount_display(ad);

	redraw_display(ad);

	return TRUE;
}

static void applet_change_back(GtkWidget *applet, PanelBackType type, char *pixmap,
				GdkColor *color, gpointer data)
{
	AppData *ad = data;
	GtkStyle *ns;

	printf("back changes\n");
	switch (type)
		{
		case PANEL_BACK_NONE :
			ns = gtk_style_new();
			gtk_style_ref(ns);
			gtk_widget_set_style(GTK_WIDGET(ad->applet), ns);
			gtk_style_unref(ns);
			break;
		case PANEL_BACK_COLOR :
			ns = gtk_style_copy(GTK_WIDGET(ad->applet)->style);
			gtk_style_ref(ns);
			ns->bg[GTK_STATE_NORMAL] = *color;
			gtk_widget_set_style(GTK_WIDGET(ad->applet), ns);
			gtk_style_unref(ns);
			break;
		case PANEL_BACK_PIXMAP :
			if (g_file_exists (pixmap))
				{
				GdkImlibImage *im = gdk_imlib_load_image (pixmap);
				if (im)
					{
					/* FIX me! pixmap leak */
					GdkPixmap *pmap;
					gdk_imlib_render (im, im->rgb_width, im->rgb_height);
					pmap = gdk_imlib_move_image (im);
					gdk_imlib_destroy_image (im);
					gdk_window_set_back_pixmap(ad->applet->window, pmap, FALSE);
					gdk_window_clear(ad->applet->window);
					}
				}
			break;
		}
}

/* clean up function to free all the applet's memory and stop timers */
static void destroy_applet(GtkWidget *widget, gpointer data)
{
	AppData *ad = data;

	gtk_timeout_remove(ad->update_timeout_id);
	if (ad->blinking)
		gtk_timeout_remove(ad->blink_timeout_id);

	free_skin(ad->skin_h);
	free_skin(ad->skin_v);

	g_free(ad->mail_file);
	g_free(ad->newmail_exec_cmd);
	g_free(ad->theme_file);
	g_free(ad);
}

static AppData *create_new_app(GtkWidget *applet)
{
        AppData *ad;

        ad = g_new0(AppData, 1);

	ad->applet = applet;
	ad->propwindow = NULL;
	ad->orient = ORIENT_UP;

	ad->mailsize = 0;
	ad->oldtime = 0;
	ad->old_week = -1;
	ad->old_n = 0;
	ad->blink_lit = 0;
	ad->blink_count = 0;

	ad->use_gmt = FALSE;
	ad->gmt_offset = 0;
	ad->mail_max = 150;

	/* (duration = BLINK_DELAY / 1000 * BLINK_TIMES) */
	ad->blink_delay = 166;
	ad->blink_times = 16;

	ad->am_pm_enable = FALSE;
	ad->always_blink = FALSE;

	/* mail file location */
	ad->mail_file = NULL;

	/* execute a command on new mail */
	ad->newmail_exec_cmd = NULL;
	ad->exec_cmd_on_newmail = FALSE;

	ad->skin = NULL;
	ad->skin_h = NULL;
	ad->skin_v = NULL;

	ad->theme_file = NULL;

	property_load(APPLET_WIDGET(applet)->privcfgpath, ad);

	/* get mail filename from environment if not specified in the session file */
	if (!strcmp(ad->mail_file,"default"))
		{
		if (ad->mail_file) g_free(ad->mail_file);
		ad->mail_file = NULL;
		if (getenv ("MAIL"))
			ad->mail_file = g_strdup(getenv ("MAIL"));
		}

	gtk_signal_connect(GTK_OBJECT(ad->applet),"change_orient",
		GTK_SIGNAL_FUNC(applet_change_orient), ad);

	/* create a tooltip widget to display song title */
	ad->tooltips = gtk_tooltips_new();

	ad->display_area = gtk_drawing_area_new();
	gtk_signal_connect(GTK_OBJECT(ad->display_area), "destroy",
		GTK_SIGNAL_FUNC(destroy_applet), ad);
	gtk_widget_show(ad->display_area);

	applet_widget_add(APPLET_WIDGET(ad->applet), ad->display_area);

	gtk_widget_realize(ad->display_area);

	if (ad->theme_file && strlen(ad->theme_file) == 0)
		{
		change_to_skin(NULL, ad);
		}
	else if (!change_to_skin(ad->theme_file, ad))
		{
		printf("Failed to load skin %s, loading default\n", ad->theme_file);
		change_to_skin(NULL, ad);
		}

	gtk_widget_show(ad->applet);

	gtk_signal_connect(GTK_OBJECT(ad->applet),"save_session",
		GTK_SIGNAL_FUNC(applet_save_session), ad);
	gtk_signal_connect(GTK_OBJECT(ad->applet),"back_change",
		GTK_SIGNAL_FUNC(applet_change_back), ad);

	applet_widget_register_stock_callback(APPLET_WIDGET(ad->applet),
						"properties",
						GNOME_STOCK_MENU_PROP,
						_("Properties..."),
						property_show,
						ad);

	applet_widget_register_stock_callback(APPLET_WIDGET(ad->applet),
						"about",
						GNOME_STOCK_MENU_ABOUT,
						_("About..."),
						about_cb,
						NULL);

	update_display(ad);

	ad->update_timeout_id = gtk_timeout_add(1000, (GtkFunction)update_display, ad);
	
	return ad;
}

static void applet_change_orient(GtkWidget *w, PanelOrientType o, gpointer data)
{
	AppData *ad = data;
	ad->orient = o;
	if (ad->orient == ORIENT_LEFT || ad->orient == ORIENT_RIGHT)
		{
		if (ad->skin_v && ad->skin != ad->skin_v)
			{
			ad->skin = ad->skin_v;
			sync_window_to_skin(ad);
			}
		}
	else
		{
		if (ad->skin != ad->skin_h)
			{
			ad->skin = ad->skin_h;
			sync_window_to_skin(ad);
			}
		}
}

static gint applet_save_session(GtkWidget *widget, gchar *privcfgpath,
					gchar *globcfgpath, gpointer data)
{
	AppData *ad = data;
        property_save(privcfgpath, ad);
        return FALSE;
}

static GtkWidget * applet_start_new_applet(const gchar *goad_id,
					   const char **params, int nparams)
{
	GtkWidget *applet;

	g_return_val_if_fail(!strcmp(goad_id, "clockmail_applet"), NULL);

	applet = applet_widget_new(goad_id);

	if (!applet)
	  g_error("Can't create applet!\n");

	create_new_app(applet);

	return applet;
}

int main (int argc, char *argv[])
{
	GtkWidget *applet;
	char *goad_id;

	/* Initialize the i18n stuff */
	bindtextdomain (PACKAGE, GNOMELOCALEDIR);
	textdomain (PACKAGE);

	applet_widget_init("clockmail_applet", VERSION, argc, argv, NULL, 0,
			   NULL);

	applet_factory_new("clockmail_applet_factory", NULL,
			   applet_start_new_applet);

	goad_id = (char *)goad_server_activation_id();
	if(goad_id && !strcmp(goad_id, "clockmail_applet")) {
		applet = applet_widget_new("clockmail_applet");
		if (!applet)
			g_error("Can't create applet!\n");

		create_new_app(applet);
	}

	applet_widget_gtk_main();
	return 0;
}
