/*  gnutrition - a nutrition and diet analysis program.
 *  Copyright( C) 2000, 2001 Edgar Denny( e.denny@ic.ac.uk)
 *
 *  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
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <gnome.h>
#include <glade/glade.h>
#include <ctype.h>

#include "support.h"
#include "base_win.h"
#include "food.h"
#include "recipe.h"
#include "plan.h"
#include "recipe_srch_dlg.h"
#include "recipe_srch_res.h"
#include "recipe_win.h"
#include "plan_win.h"
#include "plan_add_dlg.h"
#include "wrap_mysql.h"

static void load_xml( void);
static void connect_signals( void);
static void delete_recipe( char *);

/* callbacks. */
static void on_clist_select_row( GtkCList *, int, int);
static void on_ok_button_released( GtkButton *, gpointer);
static void on_cancel_button_released( GtkButton *, gpointer);
static void on_delete_button_released( GtkButton *, gpointer);

static GladeXML *xml;
static int selected_row = -1;
static int no_recipes_in_clist = 0;

static enum { PLAN_VIEW, RECIPE_VIEW, FOOD_VIEW} active_view;

/* load the glade xml if not already loaded. */
static void
load_xml( )
{
	static gboolean loaded_xml = FALSE;

	/* load the glade interface. */
	if(  !loaded_xml) {
		xml = glade_xml_new( 
			GNUTRITION_GLADEDIR "/recipe_srch_res_dlg.glade", NULL);
		loaded_xml = TRUE;

		if( xml) {
			connect_signals( );
		} else {
			g_log( "Gnutrition", G_LOG_LEVEL_ERROR,
				"cannot load: recipe_srch_res_dlg.glade\n");
			return;
		}
	}
}

/* connect the signals. */
static void
connect_signals()
{
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "cancel_button")),
		"released", GTK_SIGNAL_FUNC( on_cancel_button_released), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "ok_button")),
		"released", GTK_SIGNAL_FUNC( on_ok_button_released), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "delete_button")),
		"released", GTK_SIGNAL_FUNC( on_delete_button_released), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "clist")),
		"select_row", GTK_SIGNAL_FUNC( on_clist_select_row), NULL);
}

/* show the dialog. */
void
gnutr_show_recipe_res_dlg( GList *list,
                           int    view)
{
	GtkWidget *dlg, *entry;
	GtkCList *clist;
	GList *ptr;
	char **elm;
	int i, row = 0;
	char *text1, *text2;
	char *recipe_no;

	if( !xml) load_xml( );

	g_return_if_fail( list);

	active_view = view;

	no_recipes_in_clist = 0;

	clist = (GtkCList *)glade_xml_get_widget( xml, "clist");
	dlg = glade_xml_get_widget( xml, "recipe_srch_res_dlg");

	gtk_clist_clear( clist);

	for ( ptr = list; ptr; ptr = ptr->next) {
		elm = (char **)ptr->data;
		/* elm[0] = recipe_no, elm[1] = recipe_name. */
		recipe_no = g_strdup( elm[0]);
		gtk_clist_append( clist, &elm[1]);
		gtk_clist_set_row_data( clist, row, (gpointer)recipe_no);
		row++;
		no_recipes_in_clist++;
	}

	for ( i=0; i<row; i++) {
		gtk_clist_get_text( clist, i, 0, &text1);
		text2 = (char *)gtk_clist_get_row_data( clist, i);
	}

	entry = glade_xml_get_widget( xml, "entry");
	gtk_entry_set_text( GTK_ENTRY( entry), "");

	switch( active_view) {
		case RECIPE_VIEW:
		{
			GtkWidget *widget;
			widget = glade_xml_get_widget( xml, "no_serv_entry");
			gtk_widget_hide( widget);
			widget = glade_xml_get_widget( xml, "no_serv_label");
			gtk_widget_hide( widget);
		}
		break;
		case PLAN_VIEW:
		{
			GtkWidget *widget;
			widget = glade_xml_get_widget( xml, "no_serv_entry");
			gtk_entry_set_text( GTK_ENTRY( widget), "");
			gtk_widget_show( widget);
			widget = glade_xml_get_widget( xml, "no_serv_label");
			gtk_widget_show( widget);
		}
			
		break;
		case FOOD_VIEW:
		break;
	}

	/* free the list. */
	gnutr_free_row_list( list, 2);

	gtk_widget_show( dlg);
}

/* when a row is selected from the clist of recipes, set the
 * text entry below it to the recipe. */
static void
on_clist_select_row( GtkCList *clist, 
                     int row,
                     int column)
{
	GtkEntry *entry = GTK_ENTRY( glade_xml_get_widget( xml, "entry"));
	char *text;

	selected_row = row;
	gtk_clist_get_text( clist, row, column, &text);
	gtk_entry_set_text( entry, text);
}

/* when the "OK" button is released. */
static void
on_ok_button_released( GtkButton *button,
                       gpointer user_data)
{
	GtkEntry *entry;
	GtkWidget *dlg;
	GtkCList *clist;
	GtkEntry *no_serv_entry;
	char *query;
	char *recipe_no;
	int row;

	entry = GTK_ENTRY( glade_xml_get_widget( xml, "entry"));
	dlg = glade_xml_get_widget( xml, "recipe_srch_res_dlg");
	clist = (GtkCList *)glade_xml_get_widget( xml, "clist");
	no_serv_entry = GTK_ENTRY( 
		glade_xml_get_widget( xml, "no_serv_entry"));

	/* check a recipe has been selected. */
	if ( selected_row == -1) {
		GtkWidget *warn_dlg;
		
		warn_dlg = gnome_warning_dialog( 
			"A recipe must be selected from the list.");
		gtk_widget_show( warn_dlg);
		return;
	}

	switch ( active_view) {
		case RECIPE_VIEW:
		/* get the recipe from the database and put in
		 * the recipe_win clist. */
		{
			char *recipe_name, *no_serv, *cat_no; 
			char *cat_desc;
			GList *list1, *list2 = NULL, *ptr;
			char **elm1, **elm2;
			GHashTable *htbl1, *htbl2, *htbl3;
			int i;

			htbl1 = get_htbl_msre_no_msre_desc();
			htbl2 = get_htbl_fd_no_fd_desc();
			htbl3 = get_htbl_cat_no_cat_desc();

			gtk_clist_get_text( clist, selected_row, 0, 
				&recipe_name);
			recipe_no = (char *)gtk_clist_get_row_data( 
				clist, selected_row);

			/* get the recipe category and number of servings. */
			query = g_strconcat( "SELECT no_serv, category_no ",
				" FROM recipe WHERE recipe_no = '", recipe_no,
				"'", NULL);
			elm1 = row_ret_val_query_db( query);
			no_serv = g_strdup( elm1[0]);
			cat_no = g_strdup( elm1[1]);
			cat_desc = (char *)g_hash_table_lookup( htbl3, 
				(gpointer)cat_no);
			g_free( query);

			for( i=0; i<2; i++) g_free( elm1[i]);
			g_free( elm1);

			/* get the ingredients. */
			query = g_strconcat( "SELECT amount, msre_no, fd_no ",
				"FROM ingredient WHERE recipe_no = '", 
				recipe_no, "'", NULL);
			list1 = rows_glist_ret_val_query_db( query);

			/* create a new list where msre_no and fd_no have
			 * been converted into msre_desc and food_desc. */
			for ( ptr = list1; ptr; ptr = ptr->next) {
				elm1 = (char **)ptr->data;

				elm2 = (char **)g_malloc( 4 * sizeof(char *));

				/* amount. */
				elm2[0] = g_strdup( elm1[0]);
				/* msre_desc. */
				if ( strcmp( elm1[1], "99999") == 0) {
					elm2[1] = g_strdup( "gm");
				} else {
					elm2[1] = g_strdup( (char *)
						g_hash_table_lookup( htbl1, 
						(gpointer)elm1[1]));
				}
				/* food_desc. */
				elm2[2] = g_strdup( 
					(char *)g_hash_table_lookup( htbl2, 
						(gpointer)elm1[2]));
				/* food_no. */
				elm2[3] = g_strdup( elm1[2]);

				list2 = g_list_append( list2, (gpointer)elm2);
			}

			/* update the clist in the recipe_win to show the
			 * newly loaded recipe. */
			gnutr_set_recipe_win( recipe_name, recipe_no, no_serv, 
				cat_desc, list2);

			gnutr_free_row_list( list1, 3);

			g_free( no_serv);
			g_free( cat_no);

			gnutr_hide_recipe_srch_dlg();
		}
		break;
		case PLAN_VIEW:
		/* get the recipe from the database and put in
		 * the plan_win clist. */
		{
			char *no_portions;
			char *recipe_name;

			/* get the recipe name, recipe number, and number
			 * of portions. */
			gtk_clist_get_text( clist, selected_row, 0, 
				&recipe_name);
			recipe_no = (char *)gtk_clist_get_row_data( clist, 
				selected_row);
			no_portions = gtk_entry_get_text( no_serv_entry);

			/* check the number of portions has been specified. */
			if( strlen( no_portions) ==0) {
				GtkWidget *warn_dlg;
				char *text;
				
				text = g_strconcat( "The number of portions ",
					"must be specified.", NULL);
				warn_dlg = gnome_warning_dialog( text); 
				gtk_widget_show( warn_dlg);
				g_free( text);
				return;
			}

			/* update the clist in the plan_win to show the newly
			 * added recipe. */
			gnutr_add_recipe_to_plan( recipe_name, recipe_no, 
				no_portions);

			gnutr_hide_plan_add_dlg();

		}
		break;
		case FOOD_VIEW:
		break;
	}

	for ( row=0; row<no_recipes_in_clist; row++) {
		recipe_no = (char *)gtk_clist_get_row_data( clist, row);
		if (recipe_no) g_free( recipe_no);
	}
	gtk_clist_clear( clist);

	selected_row = -1;
	no_recipes_in_clist = 0;

	gtk_widget_hide( dlg);
}

/* when the "Cancel" button is released. */
static void
on_cancel_button_released( GtkButton *button,
                           gpointer user_data)
{
	GtkWidget *dlg = glade_xml_get_widget( xml, "recipe_srch_res_dlg");
	GtkCList *clist =(GtkCList *)glade_xml_get_widget( xml, "clist");

	gtk_clist_clear( clist);
	gnutr_hide_recipe_srch_dlg();
	gtk_widget_hide( dlg);
}

/* when the "Delete" button is released. */
static void 
on_delete_button_released( GtkButton *button, 
                           gpointer user_data)
{
	GtkWidget *dlg;
	GtkWidget *label;
	GtkWidget *base_win = gnutr_get_base_win();
	char *message;
	int reply;
	GtkWidget *entry;
	char *recipe_name;

	entry = glade_xml_get_widget( xml, "entry");
	recipe_name = gtk_entry_get_text( GTK_ENTRY( entry));

	if ( strcmp( recipe_name, "") == 0) return;

	dlg = gnome_dialog_new( "Gnutrition: Delete Recipe", 
		GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL);
	
	gnome_dialog_set_parent( GNOME_DIALOG( dlg), GTK_WINDOW( base_win));

	message = g_strconcat( "You are about to delete a recipe from "
		"the database.\n", "Are you sure you want to do this?", NULL);
	label = gtk_label_new(message);

	gtk_box_pack_start( GTK_BOX( GNOME_DIALOG( dlg)->vbox), label,
		TRUE, TRUE, 5);
	g_free( message);

	gtk_widget_show_all( dlg);

	reply = gnome_dialog_run( GNOME_DIALOG( dlg));

	if (reply == 0) {
		delete_recipe( recipe_name);
		gtk_widget_hide( dlg);
	} else {
		gtk_widget_hide( dlg);
	}
	gtk_widget_hide( glade_xml_get_widget( xml, "recipe_srch_res_dlg"));
}

/* delete a recipe from the database. */
static void
delete_recipe( char *recipe_name)
{
	char *query;
	char *recipe_no;
	gboolean success;

	/* FIXME: why does the delete not happen immediately? Hmmm,
	 * I need to look at SQL docs. */
	query = g_strconcat( "SELECT recipe_no FROM recipe WHERE ",
		"recipe_name = '", recipe_name, "'", NULL);
	recipe_no = single_ret_val_query_db( query);
	g_assert( recipe_no);
	g_free( recipe_no);

	query = g_strconcat( "DELETE FROM recipe WHERE ",
		"recipe_no = '", recipe_no, "'", NULL);
	success = no_ret_val_query_db( query);
	g_assert( success);
	g_free( query);

	query = g_strconcat( "DELETE FROM ingredient WHERE ",
		"recipe_no = '", recipe_no, "'", NULL);
	success = no_ret_val_query_db( query);
	g_assert( success);
	g_free( query);

	/* there is a potential problem with deleting a recipe.
	 * what if it is part of a meal plan? */
	query = g_strconcat( "DELETE FROM recipe_plan WHERE ",
		"recipe_no = '", recipe_no, "'", NULL);
	success = no_ret_val_query_db( query);
	g_free( query);

	g_free( recipe_no);
}
