/*
 * Copyright (C) 2005-2009 Alex Murray <murray.alex@gmail.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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#ifdef HAVE_STRING_H
#include <string.h>
#endif /* HAVE_STRING_H */

#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gio/gio.h>

#include "active-sensor.h"
#include "sensors-applet-plugins.h"
#include "sensors-applet-settings.h"

typedef enum {
        VERY_LOW_SENSOR_VALUE = 0,
        LOW_SENSOR_VALUE,
        NORMAL_SENSOR_VALUE,
        HIGH_SENSOR_VALUE,
        VERY_HIGH_SENSOR_VALUE
} SensorValueRange;

/* Cast a given value to a valid SensorValueRange */
#define SENSOR_VALUE_RANGE(x) ((SensorValueRange)(CLAMP(x, VERY_LOW_SENSOR_VALUE, VERY_HIGH_SENSOR_VALUE)))

#define CAIRO_GRAPH_COLOR_GRADIENT 0.4

static const gchar * const temp_overlay_icons[] = {
        PIXMAPS_DIR "very-low-temp-icon.png",
        PIXMAPS_DIR "low-temp-icon.png",
        PIXMAPS_DIR "normal-temp-icon.png",
        PIXMAPS_DIR "high-temp-icon.png",
        PIXMAPS_DIR "very-high-temp-icon.png"
};

static gdouble sensor_value_range_normalised(gdouble value,
                                          gdouble low_value,
                                          gdouble high_value) {
        return ((value - low_value)/(high_value - low_value));
}

static SensorValueRange sensor_value_range(gdouble sensor_value,
                                                            gdouble low_value,
                                                            gdouble high_value) {
        gdouble range;
        range = sensor_value_range_normalised(sensor_value, low_value, high_value)*(gdouble)(VERY_HIGH_SENSOR_VALUE);

        /* check if need to round up, otherwise let int conversion
         * round down for us and make sure it is a valid range
         * value */
        return SENSOR_VALUE_RANGE(((gint)range + ((range - ((gint)range)) >= 0.5)));
}


static gboolean active_sensor_execute_alarm(ActiveSensor *active_sensor,
                                            NotifType notif_type) {
        gboolean ret;
	GError *error = NULL;

        sensors_applet_notify_active_sensor(active_sensor, notif_type);
        g_debug("EXECUTING %s ALARM: %s", 
                (notif_type == LOW_ALARM ? 
                 "LOW" : "HIGH"),
                active_sensor->alarm_command[notif_type]);
	ret = g_spawn_command_line_async (active_sensor->alarm_command[notif_type], &error);
        g_debug("Command executed in shell");

	if (error)
		g_error_free (error);

        return ret;
}

static gboolean active_sensor_execute_low_alarm(ActiveSensor *active_sensor) {
        return active_sensor_execute_alarm(active_sensor, LOW_ALARM);
}

static gboolean active_sensor_execute_high_alarm(ActiveSensor *active_sensor) {
        return active_sensor_execute_alarm(active_sensor, HIGH_ALARM);
}

/* needs to be able to be called by the config dialog when the alarm
 * command changes */
void active_sensor_alarm_off(ActiveSensor *active_sensor,
                             NotifType notif_type) {
	g_assert(active_sensor);

	if (active_sensor->alarm_timeout_id[notif_type] != -1) {
		g_debug("Disabling %s alarm.", 
                        (notif_type == LOW_ALARM ? "LOW" : "HIGH"));
		if (!g_source_remove(active_sensor->alarm_timeout_id[notif_type])) {
			g_debug("Error removing alarm source");
		}
		g_free(active_sensor->alarm_command[notif_type]);
		active_sensor->alarm_timeout_id[notif_type] = -1;

	}
        sensors_applet_notify_end(active_sensor, notif_type);
}

static void active_sensor_all_alarms_off(ActiveSensor *active_sensor) {
        /* turn off any alarms */
        int i;
        for (i = 0; i < NUM_ALARMS; i++) {
                if (active_sensor->alarm_timeout_id[i] >= 0) {
                        g_debug("-- turning off notif with type %d ---", i);
                        active_sensor_alarm_off(active_sensor, i);
                }
        }
}

static void active_sensor_alarm_on(ActiveSensor *active_sensor,
                                   NotifType notif_type) {
	GtkTreeModel *model;
	GtkTreePath *tree_path;
	GtkTreeIter iter;
        
	g_assert(active_sensor);

	model = gtk_tree_row_reference_get_model(active_sensor->sensor_row);
	tree_path = gtk_tree_row_reference_get_path(active_sensor->sensor_row);

	if (gtk_tree_model_get_iter(model, &iter, tree_path)) {

		if (active_sensor->alarm_timeout_id[notif_type] == -1) {
			/* alarm is not currently on */			
			gtk_tree_model_get(model,
					   &iter,
					   (notif_type == LOW_ALARM ? 
                                            LOW_ALARM_COMMAND_COLUMN :
                                            HIGH_ALARM_COMMAND_COLUMN), 
                                           &(active_sensor->alarm_command[notif_type]),
					   ALARM_TIMEOUT_COLUMN, &(active_sensor->alarm_timeout),
					   -1);
                        g_debug("Activating alarm to repeat every %d seconds", active_sensor->alarm_timeout);
                        
			/* execute alarm once, then add to time to
			   keep repeating it */
			active_sensor_execute_alarm(active_sensor, notif_type);
                        int timeout = (active_sensor->alarm_timeout <= 0 ? 
                                       G_MAXINT : 
                                       active_sensor->alarm_timeout);
                        switch (notif_type) {
                        case LOW_ALARM:
                                active_sensor->alarm_timeout_id[notif_type] = g_timeout_add_seconds(timeout,
                                                                                                    (GSourceFunc)active_sensor_execute_low_alarm,
                                                                                                    active_sensor);
                                break;
                        case HIGH_ALARM:
                                active_sensor->alarm_timeout_id[notif_type] = g_timeout_add_seconds(timeout,
                                                                                                    (GSourceFunc)active_sensor_execute_high_alarm,
                                                                                                    active_sensor);
                                break;
                        default:
                                g_debug("Unknown notif type: %d", notif_type);
                        }
                        
                        
                }
	}
	gtk_tree_path_free(tree_path);
        
}

/**
 * Compares two ActiveSensors and returns -1 if a comes before b in the tree,
 * 0 if refer to same row, 1 if b comes before a
 */
gint active_sensor_compare(ActiveSensor *a, ActiveSensor *b) {
	GtkTreePath *a_tree_path, *b_tree_path;
	gint ret_val;

	g_assert(a);
	g_assert(b);

	a_tree_path = gtk_tree_row_reference_get_path(a->sensor_row);
	b_tree_path = gtk_tree_row_reference_get_path(b->sensor_row);

	ret_val = gtk_tree_path_compare(a_tree_path, b_tree_path);

	gtk_tree_path_free(a_tree_path);
	gtk_tree_path_free(b_tree_path);

	return ret_val;
}

static void active_sensor_update_icon(ActiveSensor *active_sensor, 
                                      GdkPixbuf *base_icon, 
                                      SensorType sensor_type) {

	GdkPixbuf *overlay_icon, *new_icon;
	const gchar *overlay_icon_filename = NULL;
        SensorValueRange value_range;

	g_assert(active_sensor);

	/* select overlay icon
	 * depending on sensor
	 * value */
        value_range = sensor_value_range(active_sensor->sensor_values[0],
                                         active_sensor->sensor_low_value,
                                         active_sensor->sensor_high_value);

        if (sensor_type == TEMP_SENSOR) {
                overlay_icon_filename = temp_overlay_icons[value_range];
        } 

	/* load base icon */
	new_icon = gdk_pixbuf_copy(base_icon);

	/* only load overlay if required */
	if (overlay_icon_filename) {
		overlay_icon = gdk_pixbuf_new_from_file_at_size(overlay_icon_filename,
								DEFAULT_ICON_SIZE, 
								DEFAULT_ICON_SIZE,
								NULL);
		if (overlay_icon) {
			gdk_pixbuf_composite(overlay_icon, new_icon,
					     0, 0,
					     DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE,
					     0, 0,
					     1.0, 1.0,
					     GDK_INTERP_BILINEAR,
					     255);
			
			g_object_unref(overlay_icon);
		}
	}
        gtk_image_set_from_pixbuf(GTK_IMAGE(active_sensor->icon),
                                  new_icon);
	g_object_unref(new_icon);
	
}

static void active_sensor_update_graph(ActiveSensor *as, cairo_t *cr) {
        GtkAllocation allocation;
        gdouble line_height;
        gdouble width, height;
        gdouble x, y;
        cairo_pattern_t *pattern;
        gint i;

        gtk_widget_get_allocation (as->graph, &allocation);
        width = allocation.width;
        height = allocation.height;

        /* so we can set a clipping area, as well as fill the
         * back of the graph black */
        cairo_rectangle(cr,
                        0, 0,
                        width,
                        height);
        /* clip to rectangle and keep it as a path so can be
         * filled below */
        cairo_clip_preserve(cr);

        /* use black for bg color of graphs */
        cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
        cairo_fill(cr);
        

        /* determine height to scale line at for each value -
         * only do as many as will fit or the number of
         * samples that we have */
        for (i = 0; i < MIN(as->num_samples, width); i++) {
                /* need to remove one more to make it line up
                 * properly  when drawing */
                x = width - i - 1;
                y = height;

                line_height = sensor_value_range_normalised(as->sensor_values[i],
                                                            as->sensor_low_value,
                                                            as->sensor_high_value) * height;
                
                
                
                if (line_height > 0) { 
                        cairo_move_to(cr,
                                      x, 
                                      y);
                        cairo_line_to(cr, x, 
                                      y - line_height);
                }

        }
        /* make lines a gradient from slightly darker than
         * chosen color at bottom of graph, to slightly
         * lighter than chosen color at top of graph */
        pattern = cairo_pattern_create_linear(x, y,
                                              x, 0);
        cairo_pattern_add_color_stop_rgb(pattern,
                                         0,
                                         as->graph_color.red / 65535.0 - CAIRO_GRAPH_COLOR_GRADIENT, 
                                         as->graph_color.green / 65535.0 - CAIRO_GRAPH_COLOR_GRADIENT, 
                                         as->graph_color.blue / 65535.0 - CAIRO_GRAPH_COLOR_GRADIENT);

        cairo_pattern_add_color_stop_rgb(pattern,
                                         height,
                                         as->graph_color.red / 65535.0 + CAIRO_GRAPH_COLOR_GRADIENT, 
                                         as->graph_color.green / 65535.0 + CAIRO_GRAPH_COLOR_GRADIENT, 
                                         as->graph_color.blue / 65535.0 + CAIRO_GRAPH_COLOR_GRADIENT);

        cairo_set_source(cr, pattern);
        cairo_stroke(cr);
        cairo_pattern_destroy(pattern);
}

void active_sensor_destroy(ActiveSensor *active_sensor) {
        g_debug("-- destroying active sensor label...");
        gtk_widget_destroy(active_sensor->label);

        g_debug("-- destroying active sensor icon..");
        gtk_widget_destroy(active_sensor->icon);

        g_debug("-- destroying active sensor value...");
        gtk_widget_destroy(active_sensor->value);

        g_debug("-- destroying active sensor graph and frame...");
        gtk_widget_destroy(active_sensor->graph);
        gtk_widget_destroy(active_sensor->graph_frame);

        g_debug("-- destroying active sensor values...");
        g_free(active_sensor->sensor_values);

        active_sensor_all_alarms_off(active_sensor);

        g_free(active_sensor);
}

#if GTK_CHECK_VERSION (3, 0, 0)
gboolean graph_draw_cb(GtkWidget *graph,
                       cairo_t *cr,
                       gpointer data) {
#else
gboolean graph_expose_event_cb(GtkWidget *graph,
                               GdkEventExpose *event,
                               gpointer data) {
#endif
        ActiveSensor *as;

        as = (ActiveSensor *)data;

#if !GTK_CHECK_VERSION (3, 0, 0)
        cairo_t *cr;
        cr = gdk_cairo_create (event->window);
        gdk_cairo_region (cr, event->region);
        cairo_clip (cr);
#endif

        active_sensor_update_graph(as, cr);
        /* propagate event onwards */

#if !GTK_CHECK_VERSION (3, 0, 0)
        cairo_destroy (cr);
#endif

        return FALSE;
}

static void active_sensor_set_graph_dimensions(ActiveSensor *as,
                                               gint width,
                                               gint height) {
        gdouble *old_values;
        gint num_samples, old_num_samples;
        gint graph_width, graph_height;

        /* dimensions are really for graph frame, so need to remove
         * extra width added by graph frame - make sure not less than
         * 1 - always need atleast 1 sample */
        graph_width = CLAMP(width - GRAPH_FRAME_EXTRA_WIDTH, 1, width - GRAPH_FRAME_EXTRA_WIDTH);
        graph_height = CLAMP(height - GRAPH_FRAME_EXTRA_WIDTH, 1 , height - GRAPH_FRAME_EXTRA_WIDTH);

        g_debug("setting graph dimensions to %d x %d", graph_width, graph_height);
        num_samples = graph_width;

        if (as->sensor_values) {
                old_values = as->sensor_values;
                old_num_samples = as->num_samples;
                
                as->num_samples = num_samples;
                as->sensor_values = g_malloc0(sizeof(gdouble)*as->num_samples);
                memcpy(as->sensor_values,
                       old_values,
                       MIN(old_num_samples, as->num_samples)*sizeof(gdouble));

                g_free(old_values);
        } else {
                as->sensor_values = g_malloc0(sizeof(gdouble)*num_samples);
                as->num_samples = num_samples;
        }                

        /* update graph frame size request */
        gtk_widget_set_size_request(as->graph,
                                    graph_width, 
                                    graph_height);
}

void active_sensor_update_graph_dimensions(ActiveSensor *as,
                                     gint sizes[2]) {
        active_sensor_set_graph_dimensions(as, sizes[0], sizes[1]);
        gtk_widget_queue_draw (as->graph);
}

ActiveSensor *active_sensor_new(SensorsApplet *sensors_applet,
                                GtkTreeRowReference *sensor_row) {
        ActiveSensor *active_sensor;
        MatePanelAppletOrient orient;
        gint graph_size;
        gboolean horizontal;

        g_assert(sensors_applet);
        g_assert(sensor_row);

        g_debug("creating new active sensor");

	active_sensor = g_new0(ActiveSensor, 1);
        active_sensor->sensors_applet = sensors_applet;

	active_sensor->sensor_row = sensor_row;

        int i;
        for (i = 0; i < NUM_NOTIFS; i++) {
                active_sensor->alarm_timeout_id[i] = -1;
        }

        active_sensor->label = gtk_label_new("");
        active_sensor->value = gtk_label_new("");
        active_sensor->icon = gtk_image_new();

        active_sensor->graph = gtk_drawing_area_new();
        active_sensor->graph_frame = gtk_frame_new(NULL);
        gtk_frame_set_shadow_type(GTK_FRAME(active_sensor->graph_frame),
                                  GTK_SHADOW_IN);
        gtk_container_add(GTK_CONTAINER(active_sensor->graph_frame),
                          active_sensor->graph);
        gtk_widget_add_events(active_sensor->graph_frame,
                              GDK_ALL_EVENTS_MASK);

        /* need to set size according to orientation */
        orient = mate_panel_applet_get_orient(active_sensor->sensors_applet->applet);
        graph_size = g_settings_get_int(active_sensor->sensors_applet->settings, GRAPH_SIZE);

        horizontal = ((orient == MATE_PANEL_APPLET_ORIENT_UP) ||
                      (orient == MATE_PANEL_APPLET_ORIENT_DOWN));

        active_sensor_set_graph_dimensions(active_sensor,
                                           (horizontal ? graph_size : sensors_applet->size),
                                           (horizontal ? sensors_applet->size : graph_size));

        g_signal_connect(G_OBJECT(active_sensor->graph),
#if GTK_CHECK_VERSION (3, 0, 0)
                         "draw",
                         G_CALLBACK(graph_draw_cb),
#else
                         "expose_event",
                         G_CALLBACK(graph_expose_event_cb),
#endif
                         active_sensor);

        active_sensor->updated = FALSE;
        return active_sensor;
}

static void active_sensor_update_sensor_value(ActiveSensor *as,
                                              gdouble sensor_value) {

        /* only if have more than 1 sample stored */
        if (as->num_samples > 1) {
                memmove(&(as->sensor_values[1]),
                        as->sensor_values,
                        (as->num_samples - 1)*sizeof(gdouble));
        }
        
        as->sensor_values[0] = sensor_value;
}

void active_sensor_update(ActiveSensor *active_sensor, 
                          SensorsApplet *sensors_applet) {

        GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreePath *path;

	/* instance data from the tree for this sensor */
	gchar *sensor_path = NULL;
	gchar *sensor_id = NULL;
	gchar *sensor_label = NULL;
	SensorType sensor_type;
	gchar *sensor_interface;
	gboolean sensor_enabled;
	gdouble sensor_low_value;
	gdouble sensor_high_value;
	gboolean sensor_alarm_enabled;
	gdouble sensor_multiplier;
	gdouble sensor_offset;
	gdouble sensor_value;
        GdkPixbuf *icon_pixbuf;
        gchar *graph_color;

	/* to build the list of labels as we go */
	gchar *value_text = NULL;
	gchar *old_value_text;

        TemperatureScale scale;
        DisplayMode display_mode;

	GError *error = NULL;

        gchar *tooltip = NULL;
        gchar *value_tooltip = NULL;

        /* hidden gsettings options */
        gint font_size = 0;
        gboolean hide_units = FALSE;

	g_assert(active_sensor);
	g_assert(active_sensor->sensor_row);
        g_assert(sensors_applet);

	model = gtk_tree_row_reference_get_model(active_sensor->sensor_row);
	path = gtk_tree_row_reference_get_path(active_sensor->sensor_row);

	/* if can successfully get iter can proceed */
	if (gtk_tree_model_get_iter(model, &iter, path)) {
		gtk_tree_path_free(path);
		gtk_tree_model_get(GTK_TREE_MODEL(sensors_applet->sensors), 
				   &iter,
				   PATH_COLUMN, &sensor_path,
				   ID_COLUMN, &sensor_id,
				   LABEL_COLUMN, &sensor_label,
				   INTERFACE_COLUMN, &sensor_interface,
				   SENSOR_TYPE_COLUMN, &sensor_type,
				   ENABLE_COLUMN, &sensor_enabled,
				   LOW_VALUE_COLUMN, &sensor_low_value,
				   HIGH_VALUE_COLUMN, &sensor_high_value,
				   ALARM_ENABLE_COLUMN, &sensor_alarm_enabled,
				   MULTIPLIER_COLUMN, &sensor_multiplier,
				   OFFSET_COLUMN, &sensor_offset,
                                   ICON_PIXBUF_COLUMN, &icon_pixbuf,
                                   GRAPH_COLOR_COLUMN, &graph_color,
				   -1);
			

                SensorsAppletPluginGetSensorValue get_sensor_value;
		/* only call function if is in hash table for plugin */
                if ((get_sensor_value = sensors_applet_plugins_get_sensor_value_func(sensors_applet, sensor_interface)) != NULL) {
                        sensor_value = get_sensor_value(sensor_path,
                                                        sensor_id,
                                                        sensor_type,
                                                        &error);
				

                        if (error) {
                                g_debug("Error updating active sensor: %s", error->message);
                                sensors_applet_notify_active_sensor(active_sensor, 
                                                                    SENSOR_INTERFACE_ERROR);
                                
                                /* hard code text as ERROR */
				value_text = g_strdup(_("ERROR"));
                                value_tooltip = g_strdup_printf("- %s", error->message);
				g_error_free(error);
				error = NULL;

                                /* set sensor value to an error code -
                                 * note this is not unique */
                                sensor_value = -1;
			} else { 
                                /* use hidden gsettings key for hide_units */

				hide_units = g_settings_get_boolean(sensors_applet->settings, HIDE_UNITS);

                                /* scale value and set text using this
                                 * value */
				switch (sensor_type) {
				case TEMP_SENSOR:

                                        scale = (TemperatureScale) g_settings_get_int(sensors_applet->settings, TEMPERATURE_SCALE);
                                        /* scale value */
					sensor_value = sensors_applet_convert_temperature(sensor_value, 
                                                                                          CELSIUS,
                                                                                          scale); 
                                        
                                        sensor_value = (sensor_value * sensor_multiplier) + sensor_offset;
                                        switch (scale) {
                                        case FAHRENHEIT:
                                                value_text = g_strdup_printf("%2.0f %s", sensor_value, (hide_units ? "" : UNITS_FAHRENHEIT));
                                                /* tooltip should
                                                 * always display
                                                 * units */
                                                value_tooltip = g_strdup_printf("%2.0f %s", sensor_value, UNITS_FAHRENHEIT);
                                                
                                                break;
                                        case CELSIUS:
                                                value_text = g_strdup_printf("%2.0f %s", sensor_value, (hide_units ? "" : UNITS_CELSIUS));
                                                value_tooltip = g_strdup_printf("%2.0f %s", sensor_value, UNITS_CELSIUS);
                                                break;
                                        case KELVIN:
                                                value_text = g_strdup_printf("%2.0f", sensor_value);
                                                value_tooltip = g_strdup(value_text);
                                                break;
                                        }
                                        break;
				
                                case FAN_SENSOR:
                                        sensor_value = (sensor_value * sensor_multiplier) + sensor_offset;
                                        value_text = g_strdup_printf("%4.0f %s", sensor_value, (hide_units ? "" : UNITS_RPM));
                                        value_tooltip = g_strdup_printf("%4.0f %s", sensor_value, UNITS_RPM);

					break;
                                        
				case VOLTAGE_SENSOR:
					sensor_value = (sensor_value * sensor_multiplier) + sensor_offset;
					value_text = g_strdup_printf("%4.2f %s", sensor_value, (hide_units ? "" : UNITS_VOLTAGE));
					value_tooltip = g_strdup_printf("%4.2f %s", sensor_value, UNITS_VOLTAGE);

					break;
				
				case CURRENT_SENSOR:
					sensor_value = (sensor_value * sensor_multiplier) + sensor_offset;
					value_text = g_strdup_printf("%4.2f %s", sensor_value, (hide_units ? "" : UNITS_CURRENT));
					value_tooltip = g_strdup_printf("%4.2f %s", sensor_value, UNITS_CURRENT);
					break;
				
                                } /* end switch(sensor_type) */
                        } /* end else on error */

                        /* setup for tooltips */
                        tooltip = g_strdup_printf("%s %s", sensor_label, value_tooltip);
                        g_free(value_tooltip);

                        /* only do icons and labels / graphs if needed */
                        display_mode = g_settings_get_int (sensors_applet->settings, DISPLAY_MODE);
                        
                        /* most users wont have a font size set */
                        font_size = g_settings_get_int (sensors_applet->settings, FONT_SIZE);

                                                
                        /* do icon if needed */
                        if (display_mode == DISPLAY_ICON ||
                            display_mode == DISPLAY_ICON_WITH_VALUE) {
                                /* update icon if icon range has changed if no
                                 * update has been done before */
                                if ((sensor_value_range(sensor_value, sensor_low_value, sensor_high_value) != sensor_value_range(active_sensor->sensor_values[0], active_sensor->sensor_low_value, active_sensor->sensor_high_value)) || !(active_sensor->updated)) {
                                        active_sensor_update_sensor_value(active_sensor,
                                                                          sensor_value);
                                        active_sensor->sensor_low_value = sensor_low_value;
                                        active_sensor->sensor_high_value = sensor_high_value;                                
                                        active_sensor_update_icon(active_sensor, icon_pixbuf, sensor_type);
                                } 
                                /* always update tooltip */
                                gtk_widget_set_tooltip_text(active_sensor->icon,
                                                            tooltip);
                        }
                        active_sensor_update_sensor_value(active_sensor,
                                                          sensor_value);
                        active_sensor->sensor_low_value = sensor_low_value;
                        active_sensor->sensor_high_value = sensor_high_value;
                
                        /* do graph if needed */
                        if (display_mode == DISPLAY_GRAPH) {
                                /* update graph color in case has changed */
                                gdk_color_parse(graph_color,
                                                &(active_sensor->graph_color));
                                
                                gtk_widget_queue_draw (active_sensor->graph);
                                gtk_widget_set_tooltip_text(active_sensor->graph,
                                                            tooltip);
                                
                        }

                        old_value_text = value_text;

                        if (sensor_alarm_enabled) {
                                if (sensor_value >= sensor_high_value || 
                                    sensor_value <= sensor_low_value) {
                                        /* make value text red and
                                         * activate alarm */
                                        if (display_mode == DISPLAY_LABEL_WITH_VALUE ||
                                            display_mode == DISPLAY_ICON_WITH_VALUE ||
                                            display_mode == DISPLAY_VALUE) {
                                                value_text = g_markup_printf_escaped("<span foreground=\"#FF0000\">%s</span>", old_value_text);
                                                
                                                g_free(old_value_text);
                                        }
                                        /* could have both coditions at once */
                                        if (sensor_value >= sensor_high_value) {
                                                active_sensor_alarm_on(active_sensor, HIGH_ALARM);
                                        }

                                        if (sensor_value <= sensor_low_value) {
                                                active_sensor_alarm_on(active_sensor, LOW_ALARM);
                                        }
                                        
                                } else {
                                        /* make sure alarms are off */
                                        active_sensor_all_alarms_off(active_sensor);
                                }				
                        } else { /* else for if alarm enabled */
                                /* make sure all alarms are off */
                                active_sensor_all_alarms_off(active_sensor);
                        }
			
                        /* do value label */
                        if (display_mode == DISPLAY_LABEL_WITH_VALUE ||
                            display_mode == DISPLAY_ICON_WITH_VALUE ||
                            display_mode == DISPLAY_VALUE) {
                                if (font_size) {
                                        old_value_text = value_text;

                                        value_text = g_strdup_printf("<span font_desc=\"%d\">%s</span>", font_size, old_value_text);
                                        g_free(old_value_text);
                                }
                                gtk_label_set_markup(GTK_LABEL(active_sensor->value),
                                                     value_text);
                        
			
                                gtk_widget_set_tooltip_text(active_sensor->value,
                                                            tooltip);
                        }
                        /* finished with value text */
                        g_free(value_text);

                        /* do label label */
                        if (display_mode == DISPLAY_LABEL_WITH_VALUE) {
                                if (font_size) {
                                        old_value_text = sensor_label;
                                        sensor_label = g_strdup_printf("<span font_desc=\"%d\">%s</span>", font_size, old_value_text);
                                        g_free(old_value_text);
                                }
                                gtk_label_set_markup(GTK_LABEL(active_sensor->label),
                                                     sensor_label);
                                gtk_widget_set_tooltip_text(active_sensor->label,
                                                            tooltip);

                        }

                        g_free(tooltip);
		} else {
                        g_debug("no get_sensor_value function yet installed for interface %s.", sensor_interface);
		}
		g_free(sensor_path);
		g_free(sensor_id);
		g_free(sensor_label);
        	g_free(sensor_interface);
	        g_free(graph_color);
		g_object_unref(icon_pixbuf);
		
	} else {
		g_debug("Error getting iter when updating sensor...");
		
	}
        active_sensor->updated = TRUE;

}

/* to be called when the icon within the GtkRowReference that this
 * sensor references is changed - updates icon based upon value in the
 * ActiveSensor */
void active_sensor_icon_changed(ActiveSensor *active_sensor,
				SensorsApplet *sensors_applet) {
	
	GtkTreeModel *model;
	GtkTreePath *path;
	GtkTreeIter iter;
	
	SensorType sensor_type;
        GdkPixbuf *icon_pixbuf;

	g_assert(active_sensor);
	g_assert(sensors_applet);

	model = gtk_tree_row_reference_get_model(active_sensor->sensor_row);
	path = gtk_tree_row_reference_get_path(active_sensor->sensor_row);

	/* if can successfully get iter can proceed */
	if (gtk_tree_model_get_iter(model, &iter, path)) {
		gtk_tree_model_get(GTK_TREE_MODEL(sensors_applet->sensors),
				   &iter,
				   SENSOR_TYPE_COLUMN, &sensor_type,
				   ICON_PIXBUF_COLUMN, &icon_pixbuf,
				   -1);

		active_sensor_update_icon(active_sensor,
                                          icon_pixbuf,
                                          sensor_type);
		g_object_unref(icon_pixbuf);
	}
	gtk_tree_path_free(path);
}