/*  gnutrition - a nutrition and diet analysis program.
 *  Copyright (C) 2000 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 <gnome-xml/parser.h>
#include <gnome-xml/tree.h>
#include <ctype.h>

#include "support.h"
#include "text_util.h"
#include "food.h"
#include "recipe.h"
#include "load_data.h"
#include "nutrgoal_io.h"
#include "recipe_win.h"
#include "food_srch_dlg.h"
#include "food_srch_res.h"
#include "messages.h"

typedef struct Constr_s {
	gchar *nutr_desc;
	gchar *val;
} Constr_t;

static GladeXML *xml = NULL;
static gint selected_row_clist_max;
static gint selected_row_clist_min;
static gint n_rows_clist_max;
static gint n_rows_clist_min;

static GList *gnutr_search_food_text( gchar *, gchar *);
static GList *gnutr_search_food_nutrient( void);
static gboolean gnutr_check_no_nutr_match( GtkCList *, gchar *, gint);
static GList *gnutr_nutrient_constraint_search( gchar *, gchar *, gint, GList*);
static gint gnutr_find_nutr_index_from_desc( gchar *);
static void gnutr_add_to_food_list_score( GList **, Food_t *, gdouble, 
                                          gint, gint *);

gint compare_food_score( Score_t *, Score_t *);

/* Show the food selection/search dialog and initialize all
 * the relevant widgets. */
void
gnutr_show_srch_dlg()
{
	GList *desc_list, *ptr, *food_group_glist, *nutr_glist;
	static gboolean loaded_xml = FALSE;
	GtkWidget *dlg;

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

		if (  xml != NULL)
		{
			glade_xml_signal_autoconnect( xml);
		}
		else
		{
			g_log( "Gnutrition", G_LOG_LEVEL_ERROR,
					"gnutr_show_srch_dlg: cannot load glade file\n");
			return;
		}
	}

	/* get the dialog widget. */
	dlg = glade_xml_get_widget( xml, "gnutr_food_srch_dlg");

	/* Initialize all the widgets in the text search notebook page. */

	/* reset any text entries to empty. */
	gtk_entry_set_text( GTK_ENTRY( glade_xml_get_widget( 
			xml, "gnutr_srch_txt_fd_entry")), "");

	/* extract the food group descriptions and put in the combo box. */
	food_group_glist = gnutr_create_food_group_glist();

	desc_list = NULL;
	for ( ptr = g_list_first( food_group_glist); ptr; ptr = g_list_next( ptr))
	{
		desc_list = g_list_prepend( desc_list,
				(( Food_Group_t *)ptr->data)->gp_desc);	
	}
	gtk_combo_set_popdown_strings( GTK_COMBO( glade_xml_get_widget( 
			xml, "gnutr_srch_txt_fg_combo")), desc_list);

	/* Initialize all the widgets in the nutrient search notebook page. */

	/* set the food group combo box. */
	gtk_combo_set_popdown_strings( GTK_COMBO( glade_xml_get_widget(
			xml, "gnutr_srch_nut_fg_combo")), desc_list);

	gnutr_free_food_group_glist( &food_group_glist);
	g_list_free( desc_list);

	/* set the nutrient combo boxes. */
	nutr_glist = gnutr_ret_nutr_glist();

	desc_list = NULL;
	for ( ptr = g_list_first( nutr_glist); ptr; ptr = g_list_next( ptr))
	{
		desc_list = g_list_prepend( desc_list,
				(( Nutr_t *)ptr->data)->nutr_desc);
	}
	desc_list = g_list_reverse( desc_list);

	gtk_combo_set_popdown_strings( GTK_COMBO( glade_xml_get_widget(
			xml, "gnutr_srch_nut_max_combo")), desc_list);
	gtk_combo_set_popdown_strings( GTK_COMBO( glade_xml_get_widget(
			xml, "gnutr_srch_nut_min_combo")), desc_list);

	/* reset the max and min selected clist rows as unselected. */
	selected_row_clist_max = -1;
	selected_row_clist_min = -1;

	/* reset the number of rows in the clists to zero. */
	n_rows_clist_max = 0;
	n_rows_clist_min = 0;

	/* clear any existing clist entries. */
	gtk_clist_clear( ( GtkCList *)glade_xml_get_widget( 
			xml, "gnutr_srch_nut_max_clist"));
	gtk_clist_clear( ( GtkCList *)glade_xml_get_widget( 
			xml, "gnutr_srch_nut_min_clist"));

	/* reset the spin buttons to their default values. */
	gtk_spin_button_set_value( GTK_SPIN_BUTTON( glade_xml_get_widget( 
			xml, "gnutr_srch_nut_max_spin")), 1);
	gtk_spin_button_set_value( GTK_SPIN_BUTTON( glade_xml_get_widget( 
			xml, "gnutr_srch_nut_min_spin")), -1);

	/* reset the number of foods to be found. */
	gtk_entry_set_text( GTK_ENTRY( glade_xml_get_widget( 
				xml, "gnutr_srch_nut_no_fd_entry")), "40");

	/* show the search dialog. */
	gtk_widget_show( dlg);
}

/* Create a new clist of the foods in the Search Dialog that match the 
 * search criteria. The returning glist contains a list of Food_t*. */
static GList *
gnutr_search_food_text( gchar *search_text, gchar *fd_gp_no)
{
	GList *ret_glist = NULL, *ptr;
	Food_t *food = NULL;

	GList *food_glist = gnutr_ret_food_glist();

	/* return if search string is not defined. */
	if ( strcmp( search_text, "") ==0) return NULL;

	for ( ptr = g_list_first( food_glist); ptr; ptr = g_list_next( ptr))
	{
		food = ( Food_t *)ptr->data;

		/* Is the food in the selected food group, or has the group
		 * "All Foods" been selected? */
		if( strcmp( fd_gp_no, food->group->gp_no) == 0 ||
				strcmp( fd_gp_no, "0001\0") == 0)
		{
			if( text_match( search_text, food->desc->fd_desc))
			{
				ret_glist = g_list_prepend( ret_glist, food);
			}
		}
	}
	return ret_glist;
}

/* The callback when the "search" button is pressed in the food
 * search dialog. */
void
on_gnutr_srch_search_button_released( GtkButton *button,
                                      gpointer   user_data)
{
/*	GtkWidget *search_dialog = glade_xml_get_widget( 
			xml, "gnutr_food_srch_dlg"); */
	GList *food_res_glist;

	/* find out what notebook is showing when the button is pressed. */
	gint page = gtk_notebook_get_current_page( GTK_NOTEBOOK(
			glade_xml_get_widget( xml, "gnutr_srch_notebook")));

	if ( page == 0)    /* search for foods by text match. */
	{
		gchar *group_no, *group_desc, *search_text;

		search_text = gtk_entry_get_text( GTK_ENTRY( glade_xml_get_widget(
				xml, "gnutr_srch_txt_fd_entry")));
		group_desc = gtk_entry_get_text( GTK_ENTRY( glade_xml_get_widget(
				xml, "gnutr_srch_txt_fg_combo_entry")));

		group_no = gnutr_find_food_group_number( group_desc);

		food_res_glist = gnutr_search_food_text( search_text, group_no);

		g_free( group_no);
		if ( !food_res_glist) return;

		gnutr_show_search_result_dlg( food_res_glist);
	}
	else    /* search for foods by nutrient composition. */
	{
		/* check that search constraints have been specified, else show
		 * a warning message. */
		if ( n_rows_clist_max == 0 && n_rows_clist_min == 0)
		{
			gnutr_show_msg_no_nutrients_selected();
			return;
		}

		food_res_glist = gnutr_search_food_nutrient();
		gnutr_show_search_result_dlg( food_res_glist);
	}
}

/* The callback when the "cancel" button is pressed in the food
 * search dialog. Close the dialog, and the search result dialog
 * if ti visible. */
void
on_gnutr_srch_cancel_button_released( GtkButton *button,
                                      gpointer   user_data)
{	
	GtkWidget *search_dialog = glade_xml_get_widget( 
			xml, "gnutr_food_srch_dlg");

	gtk_widget_hide( search_dialog);
	gnutr_hide_srch_result_dialog();
}

/* when the "Add" button for the nutrients to maximize is
 * released in the nutrient search dialog. */
void
on_gnutr_srch_nut_max_add_button_released( GtkButton *button,
                                           gpointer user_data)
{
	gchar *clist_text[2];
	gboolean match;
	GtkWidget *entry = glade_xml_get_widget( xml, 
			"gnutr_srch_nut_max_combo_entry");
	GtkWidget *spin = glade_xml_get_widget( xml, "gnutr_srch_nut_max_spin");
	GtkCList *clist_max = ( GtkCList *)glade_xml_get_widget( xml,
			"gnutr_srch_nut_max_clist");
	GtkCList *clist_min = ( GtkCList *)glade_xml_get_widget( xml,
			"gnutr_srch_nut_min_clist");

	/* get the text to append to the clist. */
	gchar *nutrient_text = gtk_entry_get_text( GTK_ENTRY( entry));
	gint nutrient_weighting = gtk_spin_button_get_value_as_int(
			GTK_SPIN_BUTTON( spin));

	/* check that the entry to be added does not already exist
	 * in the maximize clist. */
	if ( n_rows_clist_max != 0)
	{
		match = gnutr_check_no_nutr_match( clist_max, nutrient_text,
				n_rows_clist_max);

		if ( match == TRUE)
		{
			gnutr_show_msg_nutrient_already_selected();
			return;
		}
	}

	/* check that the entry to be added does not already exist
	 * in the minimize clist. */
	if ( n_rows_clist_min != 0)
	{
		match = gnutr_check_no_nutr_match( clist_min, nutrient_text,
				n_rows_clist_min);

		if ( match == TRUE)
		{
			gnutr_show_msg_cannot_max_min();
			return;
		}
    }

	clist_text[0] = nutrient_text;
	clist_text[1] = itoa( nutrient_weighting);

	/* append to the clist. */
	gtk_clist_append( clist_max, clist_text);
	n_rows_clist_max++;
}

/* when the "Remove" button for the nutrients to maximize is
 * released. */
void
on_gnutr_srch_nut_max_remove_button_released( GtkButton *button,
                                              gpointer user_data)
{
	/* check that a row has been selected. */
	if ( selected_row_clist_max != -1)
	{
		GtkCList *clist = ( GtkCList *)glade_xml_get_widget( xml,
				"gnutr_srch_nut_max_clist");
		gtk_clist_remove( clist, selected_row_clist_max);
		selected_row_clist_max = -1;
		n_rows_clist_max--;
	}
	else
	{
		/* if no row has been selected, call a warning dialog. */
		gnutr_show_msg_no_row_selected();
	}
}

/* when the "Add" button for the nutrients to minimize is
 *  * released. */
void
on_gnutr_srch_nut_min_add_button_released( GtkButton *button,
                                           gpointer user_data)
{
	gchar *clist_text[2];
	gboolean match;
	GtkWidget *entry = glade_xml_get_widget( xml, 
			"gnutr_srch_nut_min_combo_entry");
	GtkWidget *spin = glade_xml_get_widget( xml, "gnutr_srch_nut_min_spin");
	GtkCList *clist_min = ( GtkCList *)glade_xml_get_widget( xml,
			"gnutr_srch_nut_min_clist");
	GtkCList *clist_max = ( GtkCList *)glade_xml_get_widget( xml,
			"gnutr_srch_nut_max_clist");

	/* get the text to append to the clist. */
	gchar *nutrient_text = gtk_entry_get_text( GTK_ENTRY( entry));
	gint nutrient_weighting = gtk_spin_button_get_value_as_int(
			GTK_SPIN_BUTTON( spin));

	clist_text[0] = nutrient_text;
	clist_text[1] = itoa( nutrient_weighting);

	/* check that the entry to be added does not already exist
	 * in the clist. */
	if ( n_rows_clist_min != 0)
	{
		match = gnutr_check_no_nutr_match( clist_min, nutrient_text,
				n_rows_clist_min);

		if ( match == TRUE)
		{
			gnutr_show_msg_nutrient_already_selected();
			return;
		}
	}

	/* check that the entry to be added does not already exist
	 * in the clist. */
	if ( n_rows_clist_max != 0)
	{
		match = gnutr_check_no_nutr_match( clist_max, nutrient_text,
				n_rows_clist_max);

		if ( match == TRUE)
		{
			gnutr_show_msg_cannot_max_min();
			return;
		}
	}

	/* append to the clist. */
	gtk_clist_append( clist_min, clist_text);
	n_rows_clist_min++;
}

/* when the "Remove" button for the nutrients to minimize is
 * released. */
void
on_gnutr_srch_nut_min_remove_button_released( GtkButton *button,
                                              gpointer user_data)
{
	/* check that a row has been selected. */
	if ( selected_row_clist_min != -1)
	{
		GtkCList *clist = ( GtkCList *)glade_xml_get_widget( xml,
				"gnutr_srch_nut_min_clist");
		gtk_clist_remove( clist, selected_row_clist_min);
		selected_row_clist_min = -1;
		n_rows_clist_min--;
	}
	else
	{
		/* if no row has been selected, call a warning dialog. */
		gnutr_show_msg_no_row_selected();
	}
}

/* callback when a row is selected from the clist of nutrients to
 * maximize. */
void
on_gnutr_srch_nut_max_clist_select_row( GtkCList *clist, 
                                        gint row, 
                                        gint column)
{
	selected_row_clist_max = row;
}

/* callback when a row is unselected from the clist of nutrients to
 * maximize. */
void
on_gnutr_srch_nut_max_clist_unselect_row( GtkCList *clist, 
                                          gint row, 
                                          gint column)
{
	selected_row_clist_max = -1;
}

/* callback when a row is selected from the clist of nutrients to
 * minimize. */
void
on_gnutr_srch_nut_min_clist_select_row( GtkCList *clist, 
                                        gint row, 
                                        gint column)
{
	selected_row_clist_min = row;
}

/* callback when a row is unselected from the clist of nutrients to
 * minimize. */
void
on_gnutr_srch_nut_min_clist_unselect_row( GtkCList *clist, 
                                          gint row, 
                                          gint column)
{
	selected_row_clist_min = -1;
}

/* check that the text to be added to the clist does not already
 * exist in the clist. If it does, return TRUE. */
static gboolean
gnutr_check_no_nutr_match( GtkCList *clist, gchar *text, gint n_rows)
{
	gchar *clist_text;
	gint row;

	for ( row=0; row<n_rows; row++)
	{
		gtk_clist_get_text( clist, row, 0, &clist_text);

		if ( strcmp( clist_text, text) == 0)
		{
			return TRUE;
		}
	}
	return FALSE;
}

/* gather the info necessary to perform the search of foods, perform
 * the search, return the result. */
static GList *
gnutr_search_food_nutrient()
{
	GtkWidget *option_menu;
	gchar *norm_option_text, *food_group_text, *no_foods_text, *text;
	gint no_foods_to_list, row;
	Constr_t *elm;
	GtkCList *clist;
	GList *food_score_glist, *ret_food_glist = NULL, *ptr;
	GList *constr_glist = NULL;

	/* get the selected food group. */
	food_group_text = gtk_entry_get_text( GTK_ENTRY( glade_xml_get_widget(
					xml, "gnutr_srch_nut_fg_combo_entry")));

	/* get the label of the active menu item in the GtkOptionMenu */
	option_menu = glade_xml_get_widget( xml, "gnutr_srch_nut_optionmenu");

	if ( GTK_BIN( option_menu)->child)
	{
		GtkWidget *child = GTK_BIN( option_menu)->child;

		if ( GTK_IS_LABEL( child))
		{
			gtk_label_get( GTK_LABEL( child), &norm_option_text);
		}
	}

	/* get the number of foods to display in search result. */
	no_foods_text = gtk_entry_get_text( GTK_ENTRY( glade_xml_get_widget( 
			xml, "gnutr_srch_nut_no_fd_entry")));

	no_foods_to_list = atoi( no_foods_text);

	/* get the constraint data, and put into a glist. */
	clist = ( GtkCList *)glade_xml_get_widget( 
			xml, "gnutr_srch_nut_max_clist");
	for ( row = 0; row < n_rows_clist_max; row++)
	{
		elm = ( Constr_t *)g_malloc( sizeof( Constr_t));

		gtk_clist_get_text( clist, row, 0, &text);
		elm->nutr_desc = g_strdup( text);

		gtk_clist_get_text( clist, row, 1, &text);
		elm->val = g_strdup( text);

		constr_glist = g_list_prepend( constr_glist, ( gpointer)elm);
	}

	clist = ( GtkCList *)glade_xml_get_widget( 
			xml, "gnutr_srch_nut_min_clist");
	for ( row = 0; row < n_rows_clist_min; row++)
	{
		elm = ( Constr_t *)g_malloc( sizeof( Constr_t));

		gtk_clist_get_text( clist, row, 0, &text);
		elm->nutr_desc = g_strdup( text);

		gtk_clist_get_text( clist, row, 1, &text);
		elm->val = g_strdup( text);

		constr_glist = g_list_prepend( constr_glist, ( gpointer)elm);
	}

	/* perform the search. */
	food_score_glist = gnutr_nutrient_constraint_search( food_group_text, 
			norm_option_text, no_foods_to_list, constr_glist);

	/* food_score_glist contains Score_t* pointers, need to return 
	 * a glist of Food_t* pointers. */
	for( ptr = g_list_first( food_score_glist); ptr;
			ptr = g_list_next( ptr))
	{
		ret_food_glist = g_list_append( ret_food_glist, 
				(( Score_t *)ptr->data)->food);
	}

	/* we can now free the glist of Score_t* pointers. */
	for( ptr = g_list_first( food_score_glist); ptr;
			ptr = g_list_next( ptr))
	{
		/* free what each link points to. These Score_t* pointers
		 * have been dynamically allocated. */
		g_free( ( Score_t *)ptr->data);
	}
	g_list_free( food_score_glist);

	return ret_food_glist;
}

/* find the nutrient number from its text description. */
static gint
gnutr_find_nutr_index_from_desc( gchar *nutr_desc)
{
	gint nutr_no = 0;
	Nutr_t *elm;
	GList *ptr;
	GList *nutr_glist = gnutr_ret_nutr_glist();

	/* let's be clear here: We are not after the nutrient number
	 * from the nutrient text, instead we are after its index (0-80)
	 * in the array. */

	for ( ptr = g_list_first( nutr_glist); ptr; ptr = g_list_next( ptr))
	{
		elm = ( Nutr_t *)ptr->data;

		if ( strcmp( elm->nutr_desc, nutr_desc) == 0) return nutr_no;

		nutr_no++;
	}

	g_assert_not_reached();
	return 0;
}

/* perform the search of the foods, and list those that satisfy the
 * constraints in order. */
static GList *
gnutr_nutrient_constraint_search( gchar *food_group_text,
                                  gchar *norm_option_text, 
                                  gint   no_foods_to_list,
                                  GList *constr_glist)
{
	GList *food_glist = gnutr_ret_food_glist();
	GList *constr_ptr = NULL, *list_food_ptr;
	GList *food_score_glist = NULL;
	Food_t *food;
	Constr_t *constraint;
	gdouble food_score, norm, val, constr_val;
	gdouble mean_nutr_val[NO_NUTR], total_nutr_val[NO_NUTR];
	gint i, no_foods = 0, nutr_no;
	gint no_foods_in_score_list = 0;

	for ( i = 0; i<NO_NUTR; i++) 
	{
		mean_nutr_val[i] = 0.0;
		total_nutr_val[i] = 0.0;
	}

	/* sum the nutrient value of all foods, for each nutrient. */
	list_food_ptr = g_list_first( food_glist);
	while ( list_food_ptr)
	{
		food = ( Food_t *)list_food_ptr->data;

		/* the nutrient values are per 100gm. If the value per
		 * calorie is selected, all values are normalized by the
		 * calorie value. Any foods that do do have a calorie
		 * value are excluded. */
		if ( strcmp( norm_option_text, "calorie") == 0)
		{
			nutr_no = gnutr_find_nutr_index_from_desc( "Energy");
			norm = ( gdouble)food->nutrs->value[nutr_no];

			if ( norm == 0.0) 
			{
				list_food_ptr = g_list_next( list_food_ptr);
				continue;
			}
		}
		else
		{
			norm = 1.0;
		}

		for ( i = 0; i<NO_NUTR; i++)
		{
			total_nutr_val[i] += ( ( gdouble)food->nutrs->value[i] / norm);
		}

		no_foods++;
		list_food_ptr = g_list_next( list_food_ptr);
	}

	/* compute the mean nutrient value. */
	for ( i = 0; i<NO_NUTR; i++)
	{
		mean_nutr_val[i] = total_nutr_val[i] / ( gdouble)no_foods;
	}

	/* compute the food nutrient score on the basis of the given
	 * constraints. */
	for ( list_food_ptr = g_list_first( food_glist); list_food_ptr;
			list_food_ptr = g_list_next( list_food_ptr))
	{
		food = ( Food_t *)list_food_ptr->data;

		/* the nutrient values are per 100gm. If the value per
		 * calorie is selected, all values are normalized by the
		 * calorie value. Any foods that do do have a calorie
		 * value are excluded. */
		if ( strcmp( norm_option_text, "calorie") == 0)
		{
			nutr_no = gnutr_find_nutr_index_from_desc( "Energy");
			norm = ( gdouble)food->nutrs->value[nutr_no];

			if ( norm == 0.0) 
			{
				list_food_ptr = g_list_next( list_food_ptr);
				continue;
			}
		}
		else
		{
			norm = 1.0;
		}

		/* only search for those foods that are in the selected
		 * food group. */
		if ( strcmp( "All Foods", food_group_text) != 0 &&
				strcmp( food->group->gp_desc, food_group_text) != 0)
		{
			continue;
		}

		/* the food score is based upon the sum of the constraints. */
		food_score = 0.0;
		for ( constr_ptr = g_list_first( constr_glist); constr_ptr;
				constr_ptr = g_list_next( constr_ptr))
		{
			constraint = ( Constr_t *)constr_ptr->data;

			/* get the nutrient array index from the constraint nutrient
			 * description. */
			nutr_no = gnutr_find_nutr_index_from_desc( constraint->nutr_desc);

			val = ( gdouble)food->nutrs->value[nutr_no] / norm;
			constr_val = ( gdouble)atof( constraint->val);

			food_score += ( constr_val * val) / mean_nutr_val[nutr_no];
		}

		gnutr_add_to_food_list_score( &food_score_glist, food, food_score, 
				no_foods_to_list, &no_foods_in_score_list);
	}
	return food_score_glist;
}

/* The compare function (*GCompareFunc) used in g_list_insert_sorted(). */
gint
compare_food_score( Score_t *a, Score_t *b)
{
	/* by reversing the normal return values for the comparison, the 
	 * list is sorted in the reverse order expected by qsort() - the
	 * highest is first rather than last. */
	if ( a->food_score < b->food_score) return 1;
	if ( a->food_score > b->food_score) return -1;
	return 0;
}

/* compare food score with those already in list. If the score is above
 * any in the list, insert food in order. */
static void
gnutr_add_to_food_list_score( GList   **food_score_glist, 
                              Food_t  *food, 
                              gdouble  food_score, 
                              gint     no_foods_to_list,
							  gint    *no_foods_in_score_list)
{
	Score_t *elm;
	GList *list_ptr;
	gint length;

	elm = (Score_t *)g_malloc( sizeof( Score_t));
	elm->food = food;
	elm->food_score = food_score;

	length = g_list_length( *food_score_glist);

	if ( *no_foods_in_score_list == 0)
	{
		*food_score_glist = g_list_append( *food_score_glist, elm);
		(*no_foods_in_score_list)++;
	}
	else if ( *no_foods_in_score_list < no_foods_to_list)
	{
		*food_score_glist = g_list_insert_sorted( *food_score_glist, elm,
				( GCompareFunc)compare_food_score);
		(*no_foods_in_score_list)++;
	}
	else
	{
		/* if the food score is higher than the lowest value in the
		 * list, insert it into the list in order, and remove the lowest 
		 * scoring food from the list. */
		list_ptr = g_list_last( *food_score_glist);
		if ( elm->food_score > ((Score_t *)list_ptr->data)->food_score)
		{
			*food_score_glist = g_list_insert_sorted( *food_score_glist, elm,
					( GCompareFunc)compare_food_score);

			/* Note: I am removing the Score_t*, but not the Food_t* it
			 * points to. This is correct - we don't want to loose
			 * foods. */
			g_free( ( Score_t *)list_ptr->data);
			g_list_remove_link( *food_score_glist, list_ptr);
		}
		else
		{
			g_free( elm);
		}
	}
}

/* Hide the search dialog if it is visible. */
void
gnutr_hide_srch_dlg()
{
	if ( xml != NULL)    /* check that the interface has been loaded. */
	{
		GtkWidget *dlg = glade_xml_get_widget( xml, "gnutr_food_srch_dlg");

		if ( GTK_WIDGET_VISIBLE( dlg)) gtk_widget_hide( dlg);
	}
}
