/* gkrellsun.c
 * Copyright (C) 2001, Norman Walsh. Derived from gkrellmoon by
 * Dale P. Smith and wmSun by Mike Henderson
 *
 * $Id: gkrellsun.c,v 1.2 2001/11/10 15:08:47 ndw Exp $
 *
 */

#include <gkrellm/gkrellm.h>

#include "uvsun.xpm"
#include "digits.xpm"

#define SUN_XPM uvsun_xpm

#define HEIGHT 55
#define SUN_WIDTH 54
#define SUN_HEIGHT 54
#define SUN_COUNT 1

#define DIGIT_WIDTH 7
#define DIGIT_HEIGHT 11
#define DIGIT_COUNT 15
#define DIGIT_COLON 10
#define DIGIT_DASH 11
#define DIGIT_AM 12
#define DIGIT_PM 13
#define DIGIT_SPACE 14

#define STYLE_NAME "sun"
#define PLUGIN_CONFIG_KEYWORD    "sun"
#define SUNCLOCK_MAJOR_VERSION	0
#define SUNCLOCK_MINOR_VERSION 2

typedef struct {
    int longitude;
    int latitude;
} Options;

static Panel   *panel;
static Options options;
static gint    style_id;

static GtkWidget *longitude_spin_button;
static GtkWidget *latitude_spin_button;
static GdkPixmap *sun_image = NULL;
static GdkBitmap *sun_mask = NULL;
static Decal     *sun = NULL;

static GdkPixmap *digit_image = NULL;
static GdkBitmap *digit_mask = NULL;

#define RISEHOUR_X 16
#define RISEHOUR_Y 10

static Decal     *riseHour10 = NULL;
static Decal     *riseHour01 = NULL;
static Decal     *riseHourC = NULL;
static Decal     *riseMin10 = NULL;
static Decal     *riseMin01 = NULL;
static Decal     *riseTimeAP = NULL;

#define SETHOUR_X 16
#define SETHOUR_Y 36

static Decal     *setHour10 = NULL;
static Decal     *setHour01 = NULL;
static Decal     *setHourC = NULL;
static Decal     *setMin10 = NULL;
static Decal     *setMin01 = NULL;
static Decal     *setTimeAP = NULL;

static GtkTooltips *tooltip;

#include "CalcEphem.h"

extern void SunRise(int, int, int, double, double *, double *);

typedef struct CTrans SunData;

typedef struct _Sun Sun;
struct _Sun {
    SunData data;
};

static Sun sununit;

double	Glon, SinGlat, CosGlat, TimeZone;

static void update_tooltip(Sun *sun);

static void update_sun_data(Sun * sun)
{
    struct tm *time_struc;	/* The tm struct is defined in <time.h> */
    time_t current_gmt;
    gdouble local_std_time, univ_time, eot;
    glong date;
    gint day_of_month, month, year;

    current_gmt = time(CurrentTime);	/* CurrentTime defined in <X11/X.h> */

    time_struc = gmtime(&current_gmt);
    univ_time =
	time_struc->tm_hour + time_struc->tm_min / 60.0 +
	time_struc->tm_sec / 3600.0;

    /* The date needs to be the date in UTC, i.e. in greenwich, so
     * be sure not to call the localtime function until after date
     * has been set (there's only one tm structure).  */

    year = time_struc->tm_year + 1900;
    month = time_struc->tm_mon + 1;
    day_of_month = time_struc->tm_mday;

    date = year * 10000 + month * 100 + day_of_month;

    time_struc = localtime(&current_gmt);
    local_std_time =
	time_struc->tm_hour + time_struc->tm_min / 60.0 +
	time_struc->tm_sec / 3600.0;

    sun->data.Glat = options.latitude;
    sun->data.Glon = options.longitude;

    CalcEphem(date, univ_time, &sun->data);

    sun->data.LST = local_std_time;
    sun->data.LMT = univ_time - sun->data.Glon / 15.0;
    if (sun->data.LMT < 0.0)
	sun->data.LMT += 24.0;
    if (sun->data.LMT > 24.0)
	sun->data.LMT -= 24.0;

    /* eot is the equation of time. gmst is Greenwich Sidereal
     * Time.  This equation below is correct, but confusing at
     * first.  It's easy to see when you draw the following
     * picture: A sphere with 0 and 180 degree longitude, North on
     * top, a meridian for the real sun, a meridian for a fictive
     * average sun, a meridian denoting the vernal equinox.  Note
     * that universal time is the hour angle between 180 degrees
     * and the fictive sun's meridian measured clockwise.  gmst is
     * the hour angle between 0 degrees and the meridian of the
     * vernal equinox measured clockwise.  RA_sun/15.0 is the hour
     * angle of the real sun measured counterclockwise from the
     * vernal equinox. eot is the difference between the real and
     * the fictive sun.  Looking at the picture, it's easy to see
     * that 12=RA_sun/15-gmst+eot+utc (12 hours = 180 deg.) */

    eot =
	12.0 - univ_time + sun->data.gmst - sun->data.RA_sun / 15.0;

    if (eot < 0.0)
	eot += 24.0;
    if (eot > 24.0)
	eot -= 24.0;

    sun->data.LAT = sun->data.LMT + eot;
    if (sun->data.LAT < 0.0)
	sun->data.LAT += 24.0;
    if (sun->data.LAT > 24.0)
	sun->data.LAT -= 24.0;

    update_tooltip(sun);
}

static int
sun_image_number(Sun * sun)
{
  return 0;
}


static void
sun_update_plugin() {
  static int image_number;
  double val;
  int H, M;
  int am = 1;

  /* Draw plugin specific data on the chart */
  /* Use xlib or gdk functions, or gkrellm_draw_chart() if applicable */

  if (GK.minute_tick) {
    update_sun_data(&sununit);
  }

  image_number = sun_image_number(&sununit);

  gkrellm_draw_decal_pixmap(panel, sun, image_number);

  if (sununit.data.Rise) {
    val = sununit.data.LTRise;
    H = (int)val; val = (val-H)*60.0;
    M = (int)val;

    if (H >= 12) {
      am = 0;
      if (H > 12) {
	H -= 12;
      }
    }

    gkrellm_draw_decal_pixmap(panel, riseHour10, (int)(H / 10));
    gkrellm_draw_decal_pixmap(panel, riseHour01, H % 10);
    gkrellm_draw_decal_pixmap(panel, riseHourC, DIGIT_COLON);
    gkrellm_draw_decal_pixmap(panel, riseMin10, (int)(M / 10));
    gkrellm_draw_decal_pixmap(panel, riseMin01, M % 10);

    if (am) {
      gkrellm_draw_decal_pixmap(panel, riseTimeAP, DIGIT_AM);
    } else {
      gkrellm_draw_decal_pixmap(panel, riseTimeAP, DIGIT_PM);
    }
  } else {
    gkrellm_draw_decal_pixmap(panel, riseHour10, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, riseHour01, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, riseHourC, DIGIT_COLON);
    gkrellm_draw_decal_pixmap(panel, riseMin10, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, riseMin01, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, riseTimeAP, DIGIT_SPACE);
  }

  am = 1;
  if (sununit.data.Set) {
    val = sununit.data.LTSet;
    H = (int)val; val = (val-H)*60.0;
    M = (int)val;

    if (H >= 12) {
      am = 0;
      if (H > 12) {
	H -= 12;
      }
    }

    gkrellm_draw_decal_pixmap(panel, setHour10, (int)(H / 10));
    gkrellm_draw_decal_pixmap(panel, setHour01, H % 10);
    gkrellm_draw_decal_pixmap(panel, setHourC, DIGIT_COLON);
    gkrellm_draw_decal_pixmap(panel, setMin10, (int)(M / 10));
    gkrellm_draw_decal_pixmap(panel, setMin01, M % 10);

    if (am) {
      gkrellm_draw_decal_pixmap(panel, setTimeAP, DIGIT_AM);
    } else {
      gkrellm_draw_decal_pixmap(panel, setTimeAP, DIGIT_PM);
    }
  } else {
    gkrellm_draw_decal_pixmap(panel, setHour10, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, setHour01, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, setHourC, DIGIT_COLON);
    gkrellm_draw_decal_pixmap(panel, setMin10, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, setMin01, DIGIT_DASH);
    gkrellm_draw_decal_pixmap(panel, setTimeAP, DIGIT_SPACE);
  }

  gkrellm_draw_layers(panel);
}

static void
update_tooltip(Sun *sun)
{
    GString	*mboxes = NULL;
    gchar	buf[128];
    double      val;
    int         H,M;

    if (tooltip == NULL)
	return;

    mboxes = g_string_sized_new(512);

    snprintf(buf, sizeof(buf), "Location: %d lat %d lon\n",
	     options.latitude, options.longitude);
    g_string_append(mboxes, buf);

    if (sun->data.Rise) {
      val = sun->data.LTRise;
      H = (int)val; val = (val-H)*60.0;
      M = (int)val;
      if (H >= 12) {
	if (H > 12) {
	  H -= 12;
	}
	snprintf(buf, sizeof(buf), "Sunrise: %d:%02dp\n", H, M);
      } else {
	snprintf(buf, sizeof(buf), "Sunrise: %d:%02da\n", H, M);
      }
    } else {
      snprintf(buf, sizeof(buf), "Sunrise: never\n");
    }
    g_string_append(mboxes, buf);

    if (sun->data.Set) {
      val = sun->data.LTSet;
      H = (int)val; val = (val-H)*60.0;
      M = (int)val;
      if (H >= 12) {
	if (H > 12) {
	  H -= 12;
	}
	snprintf(buf, sizeof(buf), "Sunset: %d:%02dp\n", H, M);
      } else {
	snprintf(buf, sizeof(buf), "Sunset: %d:%02da\n", H, M);
      }
    } else {
      snprintf(buf, sizeof(buf), "Sunset: never\n");
    }
    g_string_append(mboxes, buf);

    gtk_tooltips_set_tip(tooltip, panel->drawing_area, mboxes->str, NULL);
    gtk_tooltips_set_delay(tooltip, 750);
    gtk_tooltips_enable(tooltip);
    if (mboxes)
	g_string_free(mboxes, TRUE);
}


static gint
panel_expose_event(GtkWidget *widget, GdkEventExpose *ev)
{
    gdk_draw_pixmap(widget->window,
		    widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
		    panel->pixmap, ev->area.x, ev->area.y, ev->area.x, ev->area.y,
		    ev->area.width, ev->area.height);
    return FALSE;
}

static void
load_images()
{
    GdkImlibImage  *image = NULL;

    gkrellm_load_image(NULL, SUN_XPM, &image, NULL);
    gkrellm_render_to_pixmap(image, &sun_image, &sun_mask, 0, 0);

    gkrellm_load_image(NULL, digits_xpm, &image, NULL);
    gkrellm_render_to_pixmap(image, &digit_image, &digit_mask, 0, 0);
}

static void
sun_create_plugin(GtkWidget *vbox, gint first_create)
{
    Style          *style = NULL;
    int            image_x_offset;
    int            image_y_offset;

    load_images();

    if (first_create)
        panel = gkrellm_panel_new0();
    else {
	gkrellm_destroy_decal_list(panel);
    }

    style = gkrellm_meter_style(style_id);

    image_x_offset = (gkrellm_chart_width() - SUN_WIDTH) / 2;
    image_y_offset = (HEIGHT - SUN_HEIGHT) / 2;

    sun = gkrellm_create_decal_pixmap(panel, sun_image, sun_mask,
				      SUN_COUNT,
				      style, image_x_offset, image_y_offset);

    image_x_offset = RISEHOUR_X;
    image_y_offset = RISEHOUR_Y;

    riseHour10 = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH;
    riseHour01 = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH - 2;
    riseHourC  = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH - 3;
    riseMin10  = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH;
    riseMin01  = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH;
    riseTimeAP = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);


    image_x_offset = SETHOUR_X;
    image_y_offset = SETHOUR_Y;

    setHour10 = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH;
    setHour01 = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH - 2;
    setHourC  = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH - 3;
    setMin10  = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH;
    setMin01  = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    image_x_offset += DIGIT_WIDTH;
    setTimeAP = gkrellm_create_decal_pixmap(panel, digit_image, digit_mask,
					     DIGIT_COUNT,
					     style, image_x_offset, image_y_offset);

    panel->textstyle = gkrellm_meter_textstyle(style_id);
    panel->label->h_panel = HEIGHT;      /* Whatever height you need */
    gkrellm_create_panel(vbox, panel, gkrellm_bg_meter_image(style_id));
    gkrellm_monitor_height_adjust(panel->h);

    if (first_create) {
        gtk_signal_connect(GTK_OBJECT(panel->drawing_area),
			   "expose_event", (GtkSignalFunc) panel_expose_event,
			   NULL);
	tooltip=gtk_tooltips_new();
    }

    update_sun_data(&sununit);

    gkrellm_draw_decal_pixmap(panel, sun, sun_image_number(&sununit));
    gkrellm_draw_layers(panel);
}


static void
sun_create_tab(GtkWidget *tab_vbox)
{
    GtkWidget		*tabs;
    GtkWidget		*vbox;

    tabs = gtk_notebook_new();
    gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
    gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);

/* --Setup Tab */
    vbox = gkrellm_create_tab(tabs, _("Setup"));

    gkrellm_spin_button(vbox, &longitude_spin_button,
			(gfloat) options.longitude,
			-180.0, 180.0, 1.0, 1.0, 0, 60, NULL, NULL,
			FALSE, _("Longitude (decimal degrees + = W, - = E)"));

    gkrellm_spin_button(vbox, &latitude_spin_button,
			(gfloat) options.latitude,
			-90.0, 90.0, 1.0, 1.0, 0, 60, NULL, NULL,
			FALSE, _("Latitude (decimal degrees + = N, - = S)"));

/* ----------------- about text --------------------*/

	{
	    gchar *plugin_about_text;
	    GtkWidget *label, *text;

	    plugin_about_text = g_strdup_printf(
		"SunClock %d.%d\n"
		"GKrellM SunClock Plugin\n\n"
		"Copyright (C) 2001 Norman Walsh\n"
		"ndw@nwalsh.com\n\n"
		"Derived from MoonClock 0.3 Copyright (C) 2001 Dale P. Smith\n"
		"and wmSun 1.03 Copyright (C) 1999 Mike Hnderson\n\n"
		"Released under the GNU Public Licence",
		SUNCLOCK_MAJOR_VERSION, SUNCLOCK_MINOR_VERSION);

	    text = gtk_label_new(plugin_about_text);
	    label = gtk_label_new("About");
	    gtk_notebook_append_page(GTK_NOTEBOOK(tabs),text,label);
	    g_free(plugin_about_text);
	}
}

static void
sun_apply_config()
{
    options.longitude = gtk_spin_button_get_value_as_int(
	GTK_SPIN_BUTTON(longitude_spin_button));

    options.latitude = gtk_spin_button_get_value_as_int(
	GTK_SPIN_BUTTON(latitude_spin_button));
}

static void
sun_save_config (FILE *f)
{
    fprintf(f, "%s longitude %d\n", PLUGIN_CONFIG_KEYWORD, options.longitude);
    fprintf(f, "%s latitude %d\n", PLUGIN_CONFIG_KEYWORD, options.latitude);
}

static void
sun_load_config (gchar *arg)
{
    gchar config[64], item[256];
    gint n;

    n = sscanf(arg, "%s %[^\n]", config, item);
    if (n != 2)
	return;

    if (strcmp(config, "longitude") == 0)
	sscanf(item, "%d\n", &(options.longitude));
    if (strcmp(config, "latitude") == 0)
	sscanf(item, "%d\n", &(options.latitude));
}

static Monitor  plugin_mon  = {
    "Sun Clock",		/* Name, for config tab.        */
    0,				/* Id,  0 if a plugin           */
    sun_create_plugin,		/* The create_plugin() function */
    sun_update_plugin,		/* The update_plugin() function */
    sun_create_tab,		/* The create_plugin_tab() config function */
    sun_apply_config,		/* The apply_plugin_config() function      */

    sun_save_config,		/* The save_plugin_config() function  */
    sun_load_config,		/* The load_plugin_config() function  */
    PLUGIN_CONFIG_KEYWORD,	/* config keyword                     */

    NULL,			/* Undefined 2  */
    NULL,			/* Undefined 1  */
    NULL,			/* private		*/

    MON_INSERT_AFTER|MON_CLOCK,	/* Insert plugin before this monitor.       */
    NULL,			/* Handle if a plugin, filled in by GKrellM */
    NULL			/* path if a plugin, filled in by GKrellM   */
};

Monitor *
init_plugin(void)
{
    options.longitude = 72;	/* Where I live! */
    options.latitude = 42;

    style_id = gkrellm_add_meter_style(&plugin_mon, STYLE_NAME);

    return &plugin_mon;
}


syntax highlighted by Code2HTML, v. 0.9.1