/* countdown.c	- requires GKrellM 2.0.0 or better

  Copyright 2003, James C. Jones <jcjones@ufl.edu>

  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


  This plugin simply reads in a UNIX time from the configuration file, and
  provides a countdown from now until then with one second accuracy. The
  target time can be configured using the GTK2 calendar widget in the
  normal method of configuring plugins -- right click the plugin, or
  right click GKrellM and choose "Configuration."

  The plugin makes no effort to take into account silly things like time 
  zones, lunar phases, or invasions from Omicron Persei VIII.

  Left clicking the plugin resets the scroll such that you can read the 
  days column.
  Middle clicking the plugin pauses the countdown and the scroll.
  Right clicking the plugin opens the configuration.

  WIN32 defines in this demo are for portability to Windows.

*/

#if !defined(WIN32)
#include <gkrellm2/gkrellm.h>
#else
#include <src/gkrellm.h>
#include <src/win32-plugin.h>
#endif

#define	CONFIG_NAME	"Countdown"
#define MONITOR_CONFIG_KEYWORD	"countdown_timer"

#define	STYLE_NAME	"Countdown"

static GkrellmMonitor *countdown_monitor;
static GkrellmPanel   *countdown_panel;
static GkrellmDecal *countdown_decal_text1;

gchar *countdown_scroll_text = "Scrolling text";
GtkWidget *cal, *cal_hours, *cal_minutes, *s_locked;
static gint     countdown_style_id;

static int reset_scroll = 0, scroll_pause = 0, scroll_locked = 0;

int countdown_diff = 0, countdown_days = 0, countdown_hours = 0, countdown_minutes = 0, countdown_seconds = 0;
time_t countdown_currenttime = 0, countdown_targettime = 0;

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

static gint cb_panel_press(GtkWidget *widget, GdkEventButton *ev, gpointer data)
{
  if (ev->button == 3) {
    gkrellm_open_config_window(countdown_monitor);
    return TRUE;
  } else if (scroll_locked) {
    return TRUE; // Disable the other two buttons while scroll locked.
  } else if (ev->button == 2) {
    scroll_pause = !scroll_pause;
  } else {
    reset_scroll = TRUE;
  }

  return TRUE;
}

static void update_plugin()
{
  static gint	x_scroll, w;
  
  gchar countdown_tmp_text[4096];
  sprintf(countdown_tmp_text,"%id %ih %im %is", countdown_days, countdown_hours, countdown_minutes, countdown_seconds);

  if (GK.second_tick)
    {
      // Here update the countdown
      countdown_currenttime = time(&countdown_currenttime);
      countdown_diff = difftime(countdown_targettime, countdown_currenttime);
      countdown_days = countdown_diff/86400;
      countdown_hours = (countdown_diff-(countdown_days*86400))/3600;
      countdown_minutes = (countdown_diff-((countdown_days*86400)+(countdown_hours*3600)))/60;
      countdown_seconds = (countdown_diff-((countdown_days*86400)+(countdown_hours*3600)+(countdown_minutes*60)));
    }

  /* If prohibit scrolling is enabled, then just update and return 
     after trimming off any 0 values, so we show as much precision 
     as possible.
  */
  if (scroll_locked) {
    // Chop off any left-aligned 0 values (like, 0 hours left)
    if (countdown_hours<1)
      sprintf(countdown_tmp_text,"%im %is", countdown_minutes, 
	      countdown_seconds);
    else if (countdown_days<1)
      sprintf(countdown_tmp_text,"%ih %im %is", countdown_hours,
	      countdown_minutes, countdown_seconds);
    
    // Ensure the well hasn't been poisoned by drawing at a nonzero x location
    countdown_decal_text1->x_off = 0;
    gkrellm_draw_decal_text(countdown_panel, countdown_decal_text1, countdown_tmp_text, -1);
    gkrellm_draw_panel_layers(countdown_panel);
    return;
  }
	  
  if (w == 0)
    w = gkrellm_chart_width();

  if (!scroll_pause)
    x_scroll = (x_scroll + 2) % (int)( 2.7 * w );

  if (reset_scroll > 0) {
    x_scroll = w-5;
    reset_scroll = FALSE;
  }

  countdown_decal_text1->x_off = w - x_scroll;
  gkrellm_draw_decal_text(countdown_panel, countdown_decal_text1, countdown_tmp_text, w - x_scroll);
  gkrellm_draw_panel_layers(countdown_panel);
}


static void create_plugin(GtkWidget *vbox, gint first_create)
{
  GkrellmStyle	*countdown_style;
  GkrellmTextstyle *ts, *ts_alt;
  gint			y;

  if (first_create) {
    countdown_panel = gkrellm_panel_new0();
    reset_scroll = FALSE;
    if (countdown_targettime == 0) {
	/* Set the target time to now. This will be overwritten by the
	   loaded config if there's one to load. If not, at least the
	   calendar will be on the right day, month and year!
	*/
	countdown_targettime = time(NULL);
    }
  }
  
  countdown_style = gkrellm_meter_style(countdown_style_id);
  
  /* Each Style has two text styles.  The theme designer has picked the
  |  colors and font sizes, presumably based on knowledge of what you draw
  |  on your panel.  You just do the drawing.  You can assume that the
  |  ts font is larger than the ts_alt font.
  */
  ts = gkrellm_meter_textstyle(countdown_style_id);
  ts_alt = gkrellm_meter_alt_textstyle(countdown_style_id);
  

  /* ==== Create a text decal that will be used to scroll text. ====
  |  Make it the full panel width (minus the margins).  Position it at top
  |  border and left margin of the style.  The "Ay" string is a vertical
  |  sizing string for the decal and not an initialization string.
  */
  countdown_decal_text1 = gkrellm_create_decal_text(countdown_panel, "Ay", ts, countdown_style,
	    -1,     /* x = -1 places at left margin */
	    -1,     /* y = -1 places at top margin	*/
	    -1);    /* w = -1 makes decal the panel width minus margins */
  y = countdown_decal_text1->y + countdown_decal_text1->h + 2;


  /* Configure the panel to hold the above created decals, and create it. */
  gkrellm_panel_configure(countdown_panel, NULL, countdown_style);
  gkrellm_panel_create(vbox, countdown_monitor, countdown_panel);

  /* Note: the above gkrellm_draw_decal_text() call will not
  |  appear on the panel until a gkrellm_draw_panel_layers() call is
  |  made.  This will be done in update_plugin(), otherwise we would
  |  make the call here after the panel is created and anytime the
  |  decals are changed.
  */

  if (first_create)
    {
      g_signal_connect(G_OBJECT (countdown_panel->drawing_area), "expose_event",
		       G_CALLBACK(panel_expose_event), NULL);
      g_signal_connect(G_OBJECT(countdown_panel->drawing_area), "button_press_event",
		       G_CALLBACK(cb_panel_press), NULL );
    }
  
}


static void save_plugin_config(FILE *f)
{
  gint tmp_tar_time = (int) countdown_targettime;
  fprintf(f, "%s time %d\n", MONITOR_CONFIG_KEYWORD, tmp_tar_time);
  fprintf(f, "%s locked %d\n", MONITOR_CONFIG_KEYWORD, scroll_locked);

}


  /* When GKrellM is started up, load_plugin_config() is called if any
  |  config lines for this plugin are found.  The lines must have been
  |  saved by save_plugin_config().  gkrellm_load_chartconfig() must
  |  have the address of a ChartConfig struct pointer.  At this point, the
  |  pointer is almost always NULL and the function will allocate a
  |  ChartConfig struct and update the pointer.  The struct will be
  |  initialized with values from the config line.
  */
static void load_plugin_config(gchar *config_line)
{
	gchar	config_keyword[32], config_data[CFG_BUFSIZE];
	gint	n, tmp_tar_time, tmp_scroll_locked;

	if ((n = sscanf(config_line, "%31s %[^\n]", \
			config_keyword, config_data)) != 2)
		return;

	if (!strcmp(config_keyword, "time")) {
	  sscanf(config_data, "%d", &tmp_tar_time);
	  countdown_targettime = (int)tmp_tar_time;
	}

	if (!strcmp(config_keyword, "locked")) {
	  sscanf(config_data, "%d", &tmp_scroll_locked);
	  scroll_locked = (int)tmp_scroll_locked;
	}

}


  /* The apply is called whenever the user hits the OK or the Apply
  |  button in the config window.
  */
static void apply_plugin_config(void)
{
  guint year,month,day;
  struct tm countdown_new_selected_time;

  scroll_locked = (int)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s_locked));


  gtk_calendar_get_date(GTK_CALENDAR(cal),&year,&month,&day);
  //printf("year:%d month:%d day:%d\n",year,month,day);
  countdown_new_selected_time.tm_mday = day;
  countdown_new_selected_time.tm_year = year - 1900;
  countdown_new_selected_time.tm_mon  = month;
  countdown_new_selected_time.tm_hour = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cal_hours));;
  countdown_new_selected_time.tm_min  = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cal_minutes));;
  countdown_new_selected_time.tm_sec  = 1;
  countdown_new_selected_time.tm_isdst= -1;

  countdown_targettime = mktime(&countdown_new_selected_time);
}


static gchar	*plugin_info_text[] =
{
  "<b>GKrellM Countdown\n",
  "\n",
  "This plugin simply reads in a UNIX time from the configuration file, and\n",
  "provides a countdown from now until then with one second accuracy. The\n",
  "target time can be configured using the GTK2 calendar widget in the\n",
  "normal method of configuring plugins -- right click the plugin, or\n",
  "right click GKrellM and choose \"Configuration.\"\n",
  "\n",
  "The plugin makes no effort to take into account silly things like time\n",
  "zones, lunar phases, or invasions from Omicron Persei VIII.\n",
  "\n",
  "Left clicking the plugin resets the scroll such that you can read the\n",
  "days column.\n",
  "Middle clicking the plugin pauses the countdown and the scroll.\n",
  "Right clicking the plugin opens the configuration.\n",
  "\n",
  "Prohibit scrolling makes the text static, and attempts to keep\n",
  "logical amounts of precision. Left and middle mouse clicks do\n",
  "not work while scrolling is prohibited.\n",
  "\n",
  "<b>Copyright 2003, James C. Jones <jcjones [at] ufl [dot] edu>\n",
  "\n",
  "This program is free software; you can redistribute it and/or modify\n",
  "it under the terms of the GNU General Public License as published by\n",
  "the Free Software Foundation; either version 2 of the License, or\n",
  "(at your option) any later version.\n",
  "\n",
  "This program is distributed in the hope that it will be useful,\n",
  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
  "GNU General Public License for more details.\n",
  "\n",
  "You should have received a copy of the GNU General Public License\n",
  "along with this program; if not, write to the Free Software\n",
  "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
};


static void create_plugin_tab(GtkWidget *tab_vbox) 
{
  /* Create your Gtk user config widgets here. */

  GtkWidget	*tabs, *text;
  GtkWidget	*vbox, *hbox, *timelabel;
  gint		i;
  GtkAdjustment * cal_hours_value;
  GtkAdjustment * cal_minutes_value;
  struct tm *target; 

  cal_hours_value   = GTK_ADJUSTMENT( gtk_adjustment_new(6.0,0.0,23.0,1.0,6.0,0.0));
  cal_minutes_value = GTK_ADJUSTMENT( gtk_adjustment_new(0.0,0.0,59.0,15.0,1.0,0.0));

  /* Build the notebook */
  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_gtk_framed_notebook_page(tabs, "Setup");

  /* Scroll Lock */
  s_locked = gtk_check_button_new_with_label("Prohibit Scrolling");
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(s_locked), scroll_locked);
  gtk_container_add( GTK_CONTAINER(vbox), s_locked);
  
  /* Calendar */
  hbox = gtk_hbox_new(FALSE, 5);
  cal = gtk_calendar_new();
  gtk_container_add( GTK_CONTAINER(vbox), cal);
  gtk_container_add( GTK_CONTAINER(vbox), hbox);
  cal_hours = gtk_spin_button_new(cal_hours_value,1,0);
  cal_minutes = gtk_spin_button_new(cal_minutes_value,15,0);
  timelabel = gtk_label_new("Hours, Minutes:");
  gtk_container_add( GTK_CONTAINER(hbox), timelabel);
  gtk_container_add( GTK_CONTAINER(hbox), cal_hours);
  gtk_container_add( GTK_CONTAINER(hbox), cal_minutes);

  /* setup the calendar with prestored values
     countdown_targettime holds the UNIX time, so convert it 
     to day, month, year, hour, minute, and pass the values 
     as needed 
  */
  target=localtime(&countdown_targettime);

  //	printf("Date is %d/%02d/%02d\n", target->tm_year+1900, target->tm_mon, target->tm_mday);
  //	printf("Time is %02d:%02d\n", target->tm_hour, target->tm_min);
  gtk_calendar_select_month(GTK_CALENDAR(cal), target->tm_mon, target->tm_year+1900);
  gtk_calendar_select_day(GTK_CALENDAR(cal), target->tm_mday);

  /* setup the spinboxes with prestored values */
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_hours), target->tm_hour);
  gtk_spin_button_set_value(GTK_SPIN_BUTTON(cal_minutes), target->tm_min);


  /* --Info tab */
  vbox = gkrellm_gtk_framed_notebook_page(tabs, "Info");
  text = gkrellm_gtk_scrolled_text_view(vbox, NULL,
		     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  for (i = 0; i < sizeof(plugin_info_text)/sizeof(gchar *); ++i)
    gkrellm_gtk_text_view_append(text, plugin_info_text[i]);
}


/* The monitor structure tells GKrellM how to call the plugin routines.
*/
static GkrellmMonitor	plugin_mon = 
{
  CONFIG_NAME,        /* Name, for config tab.    */
  0,                  /* Id,  0 if a plugin       */
  create_plugin,      /* The create function      */
  update_plugin,      /* The update function      */
  create_plugin_tab,               /* The config tab create function   */
  apply_plugin_config,             /* Apply the config function        */

  save_plugin_config,              /* Save user config   */
  load_plugin_config,              /* Load user config   */
  MONITOR_CONFIG_KEYWORD,          /* config keyword     */

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

  MON_MAIL,           /* Insert plugin before this monitor */

  NULL,               /* Handle if a plugin, filled in by GKrellM     */
  NULL                /* path if a plugin, filled in by GKrellM       */
};


  /* All GKrellM plugins must have one global routine named init_plugin()
  |  which returns a pointer to a filled in monitor structure.
  */
#if defined(WIN32)
__declspec(dllexport) GkrellmMonitor *
gkrellm_init_plugin(win32_plugin_callbacks* calls)
#else
GkrellmMonitor *
gkrellm_init_plugin(void)
#endif
{

  countdown_style_id = gkrellm_add_meter_style(&plugin_mon, STYLE_NAME);
  countdown_monitor = &plugin_mon;

  return &plugin_mon;
}
