/*
 * $RCSfile: timer_edit.c,v $  $Revision: 1.11 $  $Name:  $
 * $Id: timer_edit.c,v 1.11 2007/01/04 15:43:14 bpaauwe Exp $
 * $Author: bpaauwe $
 * $Date: 2007/01/04 15:43:14 $
 * ----------------------------------------------------------------------------
 *
 *  Copyright (c) Bob Paauwe (2006)
 *
 *  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
 *
 * ----------------------------------------------------------------------------
 *
 *  Description:
 *    Functions to handle the Timer editor configuration dialog box.
 * ----------------------------------------------------------------------------
 */

#include <string.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <glade/glade.h>
#include <glade/glade-build.h>

#ifdef WITH_GNOME
#  include <libgnomeui/libgnomeui.h>
#endif
#include "globals.h"
#include "timers.h"
#include "timer_edit.h"
#include "scenes.h"

char *tm_cmd_str(timer_timerec_t *timer, int id);
char *tm_dow_str(timer_timerec_t *timer);
char *tm_option_str(timer_timerec_t *timer);
char *tm_type_str(timer_timerec_t *timer);
void check_button(GtkWidget *button, unsigned char flag, unsigned char bit);
unsigned char query_button(GtkWidget *button, unsigned char *flag,
		unsigned char bit);
static void fill_timer(timer_timerec_t *new_tmr);

static gboolean timer_active;

gboolean tod_function(gpointer *label)
{
	unsigned char cmdid[10];
	char str[34];

	if (label != NULL) {
		/* Display time of day lable */
		ibios_read_memory(iplc, 0x0158, 9, cmdid);
		sprintf(str, "Time of Day: %02d/%02d/%02d %02d:%02d:%02d",
				cmdid[3], cmdid[4], cmdid[2], cmdid[6], cmdid[7], cmdid[8]);
		gtk_label_set_text((GtkLabel *)label, str);
	} else {
		timer_active = 0;
	}

	return timer_active;
}

/*
 * Initialize the timer edit widgets so they can be used.
 */
void initialize_timers_configuration(GladeXML *xml)
{
	tm_dialog = glade_xml_get_widget(xml, "tm_dialog");
	tm_list = glade_xml_get_widget(xml, "tm_list");
	tm_hours = glade_xml_get_widget(xml, "tm_hours");
	tm_minutes = glade_xml_get_widget(xml, "tm_minutes");
	tm_tt_time = glade_xml_get_widget(xml, "tm_tt_time");
	tm_tt_sunrise_p = glade_xml_get_widget(xml, "tm_tt_sunrise_p");
	tm_tt_sunrise_m = glade_xml_get_widget(xml, "tm_tt_sunrise_m");
	tm_tt_sunset_p = glade_xml_get_widget(xml, "tm_tt_sunset_p");
	tm_tt_sunset_m = glade_xml_get_widget(xml, "tm_tt_sunset_m");
	tm_monday = glade_xml_get_widget(xml, "tm_monday");
	tm_tuesday = glade_xml_get_widget(xml, "tm_tuesday");
	tm_wednesday = glade_xml_get_widget(xml, "tm_wednesday");
	tm_thursday = glade_xml_get_widget(xml, "tm_thursday");
	tm_friday = glade_xml_get_widget(xml, "tm_friday");
	tm_saturday = glade_xml_get_widget(xml, "tm_saturday");
	tm_sunday = glade_xml_get_widget(xml, "tm_sunday");
	tm_security = glade_xml_get_widget(xml, "tm_security");
	tm_rnd_security = glade_xml_get_widget(xml, "tm_rnd_security");
	tm_holiday = glade_xml_get_widget(xml, "tm_holiday");
	tm_active = glade_xml_get_widget(xml, "tm_active");
	tm_sel_device = glade_xml_get_widget(xml, "tm_sel_device");
	tm_sel_scene = glade_xml_get_widget(xml, "tm_sel_scene");
	tm_device_selector = glade_xml_get_widget(xml, "tm_device_selector");
	tm_scene_selector = glade_xml_get_widget(xml, "tm_scene_selector");
	tm_command = glade_xml_get_widget(xml, "tm_command");
	tm_on_level = glade_xml_get_widget(xml, "tm_on_level");
	tm_tod = glade_xml_get_widget(xml, "tm_tod");
}

void on_edit_timers_activate(GtkWidget *widget, gpointer user_data)
{
	timer_timerec_t *tl;
	GtkListStore *store;
	GtkTreeIter iter;
	char str[25], cmdid[10];
	scene_t *scene;
	int i;

	/* Get the timers from the PLC and store in a global list */
	timers = get_timer_info(iplc);

	/* Build tree list view of the timers. */
	store = gtk_list_store_new(6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
			G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);

	tl = timers;
	while (tl) {
		for (i = 0; i < tl->cmd_group.count; i++) {
			gtk_list_store_append(store, &iter);
			sprintf(str, "%d", tl->tid);
			gtk_list_store_set(store, &iter, 0, str, -1);
			gtk_list_store_set(store, &iter, 1, tm_type_str(tl), -1);
			gtk_list_store_set(store, &iter, 2, tm_option_str(tl), -1);
			gtk_list_store_set(store, &iter, 3, tm_dow_str(tl), -1);
			sprintf(cmdid, "%d", i);
			gtk_list_store_set(store, &iter, 4, cmdid, -1);
			gtk_list_store_set(store, &iter, 5, tm_cmd_str(tl, i), -1);
		}
		tl = tl->next;
	}
	gtk_tree_view_set_model((GtkTreeView *)tm_list, (GtkTreeModel *)store);
	g_object_unref (G_OBJECT (store));

	/* Clear existing scene list */
	/*
	 * Maybe this can be done by creating a new GtkTreeModel and
	 * using gtk_combo_box_set_model(model).
	 */

	store = gtk_list_store_new(1, G_TYPE_STRING);
	gtk_combo_box_set_model((GtkComboBox *)tm_scene_selector,
			(GtkTreeModel *)store);
	g_object_unref (G_OBJECT (store));


	/* Build scene list (scenes controlled by PLC) */
	scene = scene_list;
	while (scene) {
		if ((scene->controller->device_type == 0x0000) ||
				(scene->controller->device_type == 0x0001)) {
			/* Now check that the device id is the current PLC */
			if (is_plc(iplc, scene->controller->device_id)) {
				gtk_combo_box_append_text((GtkComboBox *)tm_scene_selector,
					scene->name);
			}
		}
		scene = scene->next;
	}

	gtk_widget_show(tm_dialog);

	timer_active = 1;
	g_timeout_add(100, tod_function, (gpointer)tm_tod);
}

void on_tm_close_clicked(GtkWidget *widget, gpointer user_data)
{
	gtk_widget_hide(tm_dialog);
	timer_active = 0;
}


/*
 * add new timer
 *
 * Pull user information from the form and create a new timer
 * record. Add this record to the list and then update the PLC
 * with the new list.
 */
void on_tm_add_clicked(GtkWidget *widget, gpointer user_data)
{
	timer_timerec_t *new_tmr;

	printf("Adding new timer....\n");
	new_tmr = (timer_timerec_t *)malloc(sizeof(timer_timerec_t));
	if (new_tmr == NULL) {
		printf("Memory allocation failure for new timer record.\n");
		return;
	}

	memset(new_tmr, 0, sizeof(timer_timerec_t));
	new_tmr->cmd_group.cmds[0].data = (unsigned char *)malloc(6);

	fill_timer(new_tmr);

	/* Add timer to end of list */
	if (timers == NULL) {
		new_tmr->tid = 1;
		timers = new_tmr;
	} else {
		add_timer(timers, new_tmr);
	}

	/* Write timer list to PLC */
	write_timers(iplc, timers);

	/* Update treeview */
	on_edit_timers_activate(NULL, NULL);

}


/* modify timer
 *
 * Modify a timer record with the user entered information and
 * write the whole list back to the PLC.
 */
void on_tm_modify_clicked(GtkWidget *widget, gpointer user_data)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
	GtkTreeSelection *select;
	gchar *ch_data;
	timer_timerec_t *timer;

	select = gtk_tree_view_get_selection((GtkTreeView *)tm_list);
	if (select == NULL) {
		printf("No timer selected to delete.\n");
		return;
	}

	if (gtk_tree_selection_get_selected(select, &model, &iter)) {
		/* Get the TID of the selected timer */
		gtk_tree_model_get (model, &iter, 0, &ch_data, -1);
		if (ch_data == NULL) {
			printf("Invalid TID\n");
			return;
		}

		/* Find timer record with tid */
		timer = timers;
		while (timer != NULL) {
			if (timer->tid == atoi(ch_data)) {
				fill_timer(timer);
				break;
			}
			timer = timer->next;
		}

		/* Write timer list to PLC */
		write_timers(iplc, timers);

		/* Update treeview */
		on_edit_timers_activate(NULL, NULL);
	}
}


/*
 * delete timer
 *
 * Delete a timer from the list and from the PLC.
 */
void on_tm_delete_clicked(GtkWidget *widget, gpointer user_data)
{
	GtkTreeIter iter;
	GtkTreeModel *model;
	GtkTreeSelection *select;
	gchar *ch_data;
	int tid, cid;

	select = gtk_tree_view_get_selection((GtkTreeView *)tm_list);
	if (select == NULL) {
		printf("No timer selected to delete.\n");
		return;
	}

	if (gtk_tree_selection_get_selected(select, &model, &iter)) {
		/* Get the TID of the selected timer */
		gtk_tree_model_get (model, &iter, 0, &ch_data, -1);
		if (ch_data == NULL) {
			printf("Invalid TID\n");
			return;
		}
		tid = atoi(ch_data);

		/* Get the CID of the selected timer */
		gtk_tree_model_get (model, &iter, 4, &ch_data, -1);
		if (ch_data == NULL) {
			printf("Invalid CID\n");
			cid = 0;
		} else {
			cid = atoi(ch_data);
		}

		/* Delete from list */
		delete_timer(&timers, tid, cid);

		/* Write timer list to PLC */
		write_timers(iplc, timers);

		/* Update treeview */
		on_edit_timers_activate(NULL, NULL);
	}
}

/*
 * fill timer
 *
 * Fill in a timer record from the data in the form.
 */
static void fill_timer(timer_timerec_t *new_tmr)
{
	int hours, minutes;
	int sel;
	int group;

	new_tmr->rpt = 0x00;
	new_tmr->rpts = 0x00;
	new_tmr->cmd_group_id = 0x0000;
	new_tmr->cmd_group.count = 1;
	new_tmr->cmd_group.pos = 0;

	/* Get timer flags */
	new_tmr->flag0 = 0;
	query_button(tm_security, &(new_tmr->flag0), T_SECURITY);
	query_button(tm_rnd_security, &(new_tmr->flag0), T_RNDSECURITY);
	query_button(tm_holiday, &(new_tmr->flag0), T_HOLIDAY);
	query_button(tm_active, &(new_tmr->flag0), T_ACTIVE);

	new_tmr->dow = 0;
	query_button(tm_saturday, &(new_tmr->dow), T_SATURDAY);
	query_button(tm_sunday, &(new_tmr->dow), T_SUNDAY);
	query_button(tm_monday, &(new_tmr->dow), T_MONDAY);
	query_button(tm_tuesday, &(new_tmr->dow), T_TUESDAY);
	query_button(tm_wednesday, &(new_tmr->dow), T_WEDNESDAY);
	query_button(tm_thursday, &(new_tmr->dow), T_THURSDAY);
	query_button(tm_friday, &(new_tmr->dow), T_FRIDAY);

	/* Get timer time */
	hours = gtk_spin_button_get_value_as_int((GtkSpinButton *)tm_hours);
	minutes = gtk_spin_button_get_value_as_int((GtkSpinButton *)tm_minutes);
	if (gtk_toggle_button_get_active((GtkToggleButton *)tm_tt_time)) {
		new_tmr->type = T_ABSOLUTE;
		new_tmr->time = (hours * 60) + minutes;
	}
	if (gtk_toggle_button_get_active((GtkToggleButton *)tm_tt_sunrise_p)) {
		new_tmr->type = T_SUNRISE;
		new_tmr->time = (hours * 60) + minutes;
	}
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tm_tt_sunrise_m))) {
		new_tmr->type = T_SUNRISE;
		new_tmr->time = -((hours * 60) + minutes);
	}
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tm_tt_sunset_p))) {
		new_tmr->type = T_SUNSET;
		new_tmr->time = (hours * 60) + minutes;
	}
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tm_tt_sunset_m))) {
		new_tmr->type = T_SUNSET;
		new_tmr->time = -((hours * 60) + minutes);
	}

	/* Get timer command */
	new_tmr->cmd_group.cmds[0].type = T_INSTEON;
	new_tmr->cmd_group.cmds[0].len = 6;

	if (gtk_toggle_button_get_active((GtkToggleButton *)tm_sel_device)) {
		/* Device command */
		sel = gtk_combo_box_get_active((GtkComboBox *)tm_device_selector);
		memcpy(new_tmr->cmd_group.cmds[0].data, device_array[sel].device_id, 3);
		new_tmr->cmd_group.cmds[0].data[3] =
			MSG_STANDARD | MSG_DIRECT | MSG_1_HOP;
	} else {
		/* Group/scene command */
		sel = gtk_combo_box_get_active((GtkComboBox *)tm_scene_selector);
		group = get_plc_scene_by_index(iplc, sel);
		new_tmr->cmd_group.cmds[0].data[0] = 0;
		new_tmr->cmd_group.cmds[0].data[1] = 0;
		new_tmr->cmd_group.cmds[0].data[2] = group;
		new_tmr->cmd_group.cmds[0].data[3] =
			MSG_STANDARD | MSG_GROUP | MSG_2_HOP;
	}

	sel = gtk_combo_box_get_active((GtkComboBox *)tm_command);
	switch (sel) {
		case 0:
			new_tmr->cmd_group.cmds[0].data[4] = command_to_num("on");
			break;
		case 1:
			new_tmr->cmd_group.cmds[0].data[4] = command_to_num("off");
			break;
		default:
			break;
	}
	new_tmr->cmd_group.cmds[0].data[5] =
		gtk_spin_button_get_value_as_int((GtkSpinButton *)tm_on_level);
}



/*
 * delete all timers
 *
 * Free this list and reset the PLC.
 */
void on_tm_delete_all_clicked(GtkWidget *widget, gpointer user_data)
{
	free_timers(timers);
	clear_timers(iplc);
	on_edit_timers_activate(NULL, NULL);
}

/*
 * On timer list selection
 *
 * When the user clicks on one of the items on the list, all the
 * widgets need to get set to the proper values.
 *
 * First, look up the timer based on it's id. Then start setting widgets...
 */
void on_tm_list_cursor_changed(GtkWidget *widget, gpointer user_data)
{
	timer_timerec_t *tl;
	device_t *dev;
	GtkTreeIter iter;
	GtkTreeModel *model;
	GtkTreeSelection *select;
	gchar *ch_data;
	gdouble data;
	int hour, min;

	/* Get the timer id from the list */
	select = gtk_tree_view_get_selection((GtkTreeView *)widget);
	if (gtk_tree_selection_get_selected (select, &model, &iter)) {
		/* tid is the in the first column */
		gtk_tree_model_get (model, &iter, 0, &ch_data, -1);

		tl = timers;
		while (tl) {
			if (tl->tid == atoi(ch_data)) {
				/* Ok, found the timer, now start setting widgets */
				hour = (abs(tl->time) / 60);
				data = (gdouble)hour;
				gtk_spin_button_set_value((GtkSpinButton *)tm_hours, data);

				min = (abs(tl->time) - ((abs(tl->time) / 60) * 60));
				data = (gdouble)min;
				gtk_spin_button_set_value((GtkSpinButton *)tm_minutes, data);

				switch (tl->type) {
					case T_ABSOLUTE:
						gtk_toggle_button_set_active(
								GTK_TOGGLE_BUTTON(tm_tt_time), TRUE);
						break;
					case T_SUNRISE:
						if (tl->time >= 0) {
							gtk_toggle_button_set_active(
								GTK_TOGGLE_BUTTON(tm_tt_sunrise_p), TRUE);
						} else {
							gtk_toggle_button_set_active(
								GTK_TOGGLE_BUTTON(tm_tt_sunrise_m), TRUE);
						}
						break;
					case T_SUNSET:
						if (tl->time >= 0) {
							gtk_toggle_button_set_active(
								GTK_TOGGLE_BUTTON(tm_tt_sunset_p), TRUE);
						} else {
							gtk_toggle_button_set_active(
								GTK_TOGGLE_BUTTON(tm_tt_sunset_m), TRUE);
						}
						break;
				}

				check_button(tm_security, tl->flag0, T_SECURITY);
				check_button(tm_rnd_security, tl->flag0, T_RNDSECURITY);
				check_button(tm_holiday, tl->flag0, T_HOLIDAY);
				check_button(tm_active, tl->flag0, T_ACTIVE);
				check_button(tm_saturday, tl->dow, T_SATURDAY);
				check_button(tm_sunday, tl->dow, T_SUNDAY);
				check_button(tm_monday, tl->dow, T_MONDAY);
				check_button(tm_tuesday, tl->dow, T_TUESDAY);
				check_button(tm_wednesday, tl->dow, T_WEDNESDAY);
				check_button(tm_thursday, tl->dow, T_THURSDAY);
				check_button(tm_friday, tl->dow, T_FRIDAY);

				/* device or scene command? */
				if (tl->cmd_group.cmds[0].data[3] & MSG_GROUP) {
					/* scene */
					gtk_toggle_button_set_active(
							(GtkToggleButton *)tm_sel_scene, TRUE);
					gtk_combo_box_set_active(
							(GtkComboBox *)tm_scene_selector,
							get_scene_by_group_plc(iplc,
								tl->cmd_group.cmds[0].data[2]));
				} else {
					/* device */
					gtk_toggle_button_set_active(
							(GtkToggleButton *)tm_sel_device, TRUE);
					dev = find_device(tl->cmd_group.cmds[0].data);
					if (dev) {
						gtk_combo_box_set_active(
								(GtkComboBox *)tm_device_selector,
								dev->device_index);
					}
				}
				if (tl->cmd_group.cmds[0].data[4] == ON) {
					gtk_combo_box_set_active(
							(GtkComboBox *)tm_command, 0);
				} else { /* assuming it is off if it is not on */
					gtk_combo_box_set_active(
							(GtkComboBox *)tm_command, 1);
				}
				gtk_spin_button_set_value((GtkSpinButton *)tm_on_level,
						(gdouble)tl->cmd_group.cmds[0].data[5]);

				break;
			}
			tl = tl->next;
		}
	}
}


char *tm_type_str(timer_timerec_t *timer)
{
	static char str[15];

	if (timer->type == T_ABSOLUTE) {
		sprintf(str, "%02d:%02d ", (timer->time / 60),
				((timer->time - (timer->time / 60) * 60)));
	} else if (timer->type == T_SUNRISE) {
		sprintf(str, "Sunrise + %d ", timer->time);
	} else if (timer->type == T_SUNSET) {
		sprintf(str, "Sunset + %d ", timer->time);
	} else {
		sprintf(str, "Unknown ");
	}

	return str;
}



char *tm_option_str(timer_timerec_t *timer)
{
	static char str[10];

	sprintf(str, "[");
	if (timer->flag0 & T_SECURITY) {
		strcat(str, "S");
	}
	if (timer->flag0 & T_RNDSECURITY) {
		strcat(str, "Rs");
	}
	if (timer->flag0 & T_HOLIDAY) {
		strcat(str, "H");
	}
	if (timer->flag0 & T_ACTIVE) {
		strcat(str, "A");
	}
	if (timer->flag0 & T_DELETED) {
		strcat(str, "D");
	}
	strcat(str, "] ");

	return str;
}


char *tm_dow_str(timer_timerec_t *timer)
{
	static char str[12];

	strcpy(str, "");

	if (timer->dow & T_SUNDAY) {
		strcat(str, "Su");
	}
	if (timer->dow & T_MONDAY) {
		strcat(str, "M");
	}
	if (timer->dow & T_TUESDAY) {
		strcat(str, "Tu");
	}
	if (timer->dow & T_WEDNESDAY) {
		strcat(str, "W");
	}
	if (timer->dow & T_THURSDAY) {
		strcat(str, "Th");
	}
	if (timer->dow & T_FRIDAY) {
		strcat(str, "F");
	}
	if (timer->dow & T_SATURDAY) {
		strcat(str, "Sa");
	}

	return str;
}

char *tm_cmd_str(timer_timerec_t *timer, int id)
{
	static char str[40];
	int j;
	char hex_str[6];

	if (timer->cmd_group.cmds[id].type == T_NONE) {
		sprintf(str, "None ");
	}
	if (timer->cmd_group.cmds[id].type == T_INSTEON) {
		sprintf(str, "INSTEON ");
	}
	if (timer->cmd_group.cmds[id].type == T_X10) {
		sprintf(str, "X10 ");
	}
	if (timer->cmd_group.cmds[id].type == T_RS232) {
		sprintf(str, "rs232 ");
	}
	if (timer->cmd_group.cmds[id].type == T_VAR) {
		sprintf(str, "VAR ");
	}
	if (timer->cmd_group.cmds[id].type == T_MACRO) {
		sprintf(str, "Macro ");
	}

	for (j = 0; j < timer->cmd_group.cmds[id].len; j++) {
		sprintf(hex_str, "0x%02x ", timer->cmd_group.cmds[id].data[j]);
		strcat(str, hex_str);
	}

	return str;
}


/*
 * helper function to set a check button based on the value of a flag
 */
void check_button(GtkWidget *button, unsigned char flag,
		unsigned char bit)
{
	if (flag & bit) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
	} else {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
	}
}

unsigned char query_button(GtkWidget *button, unsigned char *flag,
		unsigned char bit)
{
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
		*flag |= bit;
	} else {
		*flag &= ~bit;
	}

	return *flag;
}
