/*  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 "food.h"
#include "base_win.h"
#include "wrap_mysql.h"
#include "init_database.h"
#include "gnutr_druid.h"
#include "rdi.h"
#include "nutr_goal.h"
#include "person.h"

static GladeXML *xml = NULL;
static void load_xml( void);
static void connect_signals( void);
static gboolean user_name_exists( char *);

static gboolean on_create_db_next( GnomeDruidPage *);
static gboolean on_user_setup_next( GnomeDruidPage *);
static gboolean on_finish( GnomeDruidPage *);
static gboolean on_page_cancel( GnomeDruidPage *);
static gboolean on_db_error_next( GnomeDruidPage *);
static gboolean on_user_setup_next( GnomeDruidPage *);
static gboolean on_user_setup_back( GnomeDruidPage *);
static gboolean on_user_error_next( GnomeDruidPage *);
static gboolean on_page_personal_next( GnomeDruidPage *);
static gboolean on_page_personal_back( GnomeDruidPage *);
static gboolean on_personal_error_next( GnomeDruidPage *);
static gboolean on_finish_back( GnomeDruidPage *);
static void on_female_radio_toggled( GtkWidget *, gpointer);

/* 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 "/gnutr_druid.glade", NULL);
		loaded_xml = TRUE;
		if(xml) {
			connect_signals();
		} else {
			g_log( "Gnutrition", G_LOG_LEVEL_ERROR,
				"cannot load glade file: gnutr_druid.glade\n");
			return;
		}
	}
}

/* connect the signals. */
static void
connect_signals()
{
	gtk_signal_connect( GTK_OBJECT(
		glade_xml_get_widget( xml, "page_start")),
		"cancel", GTK_SIGNAL_FUNC( on_page_cancel), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_create_db")),
		"next", GTK_SIGNAL_FUNC( on_create_db_next), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_create_db")),
		"cancel", GTK_SIGNAL_FUNC( on_page_cancel), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_db_error")),
		"next", GTK_SIGNAL_FUNC( on_db_error_next), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_db_error")),
		"cancel", GTK_SIGNAL_FUNC( on_page_cancel), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_user")),
		"next", GTK_SIGNAL_FUNC( on_user_setup_next), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_user")),
		"back", GTK_SIGNAL_FUNC( on_user_setup_back), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_user")),
		"cancel", GTK_SIGNAL_FUNC( on_page_cancel), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_user_error")),
		"next", GTK_SIGNAL_FUNC( on_user_error_next), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_user_error")),
		"cancel", GTK_SIGNAL_FUNC( on_page_cancel), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_personal")),
		"next", GTK_SIGNAL_FUNC( on_page_personal_next), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_personal")),
		"back", GTK_SIGNAL_FUNC( on_page_personal_back), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_personal")),
		"cancel", GTK_SIGNAL_FUNC( on_page_cancel), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_personal_error")),
		"next", GTK_SIGNAL_FUNC( on_personal_error_next), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_personal_error")),
		"cancel", GTK_SIGNAL_FUNC( on_page_cancel), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_end")),
		"finish", GTK_SIGNAL_FUNC( on_finish_back), NULL);
	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "page_end")),
		"finish", GTK_SIGNAL_FUNC( on_finish), NULL);

	gtk_signal_connect( GTK_OBJECT( 
		glade_xml_get_widget( xml, "female_radio")),
		"toggled", GTK_SIGNAL_FUNC( on_female_radio_toggled), NULL);
}

/* show the druid window. */
void
gnutr_show_druid_win()
{
	GtkWidget *druid_win;
	GtkWidget *pg1, *pg2, *pg3, *pg4, *pg5, *pg6, *pg7, *pg8;
	char *uname = g_get_user_name();
	char *fn_pixmap;
	GdkImlibImage *image;

	if ( !xml) load_xml();

	/* set some default values. */
	gtk_entry_set_text( GTK_ENTRY(
		glade_xml_get_widget( xml, "root_username_entry")), "root");
	gtk_entry_set_text( GTK_ENTRY(
		glade_xml_get_widget( xml, "username_entry")), uname);

	druid_win = glade_xml_get_widget( xml, "druid_win");

	pg1 = glade_xml_get_widget( xml, "page_start");
	pg2 = glade_xml_get_widget( xml, "page_create_db");
	pg3 = glade_xml_get_widget( xml, "page_db_error");
	pg4 = glade_xml_get_widget( xml, "page_user");
	pg5 = glade_xml_get_widget( xml, "page_user_error");
	pg6 = glade_xml_get_widget( xml, "page_personal");
	pg7 = glade_xml_get_widget( xml, "page_personal_error");
	pg8 = glade_xml_get_widget( xml, "page_end");

	/* add the pixmaps here rather in glade. */
	fn_pixmap = g_strdup( GNUTRITION_ICONDIR "/cake.png");
	image = gdk_imlib_load_image( fn_pixmap);
	gnome_druid_page_start_set_logo( GNOME_DRUID_PAGE_START( pg1), image);
	gnome_druid_page_standard_set_logo( GNOME_DRUID_PAGE_STANDARD( pg2), 
		image);
	gnome_druid_page_standard_set_logo( GNOME_DRUID_PAGE_STANDARD( pg3), 
		image);
	gnome_druid_page_standard_set_logo( GNOME_DRUID_PAGE_STANDARD( pg4), 
		image);
	gnome_druid_page_standard_set_logo( GNOME_DRUID_PAGE_STANDARD( pg5), 
		image);
	gnome_druid_page_standard_set_logo( GNOME_DRUID_PAGE_STANDARD( pg6), 
		image);
	gnome_druid_page_standard_set_logo( GNOME_DRUID_PAGE_STANDARD( pg7), 
		image);
	gnome_druid_page_finish_set_logo( GNOME_DRUID_PAGE_FINISH( pg8), image);

	gtk_widget_show( druid_win);
}

/* when the "Next" button is pressed on the "Creating the Database" page. */
static gboolean 
on_create_db_next( GnomeDruidPage *druidpage)
{
	GtkWidget *drd = glade_xml_get_widget( xml, "druid");
	GtkWidget *username_entry;
	GtkWidget *password_entry;
	GtkWidget *pg;
	char *uname;
	char *pword;
	gboolean success;

	username_entry = glade_xml_get_widget( xml, "root_username_entry");
	password_entry = glade_xml_get_widget( xml, "root_password_entry");
	uname = gtk_entry_get_text( GTK_ENTRY( username_entry));
	pword = gtk_entry_get_text( GTK_ENTRY( password_entry));

	/* check that the text entries contain text, if so, stay
	 * at the same page. */
	if ( strlen( uname) == 0 || strlen( pword) == 0) {
		pg = glade_xml_get_widget( xml, "page_create_db");

		gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
		return TRUE;
	}

	success = initialize_db( uname, pword);

	/* if the initialization of the database fails, go to the
	 * "Error: Database Creation Failed." page. */
	if ( !success) {
		pg = glade_xml_get_widget( xml, "page_db_error");

		gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
		return TRUE;
	}

	/* skip the next page, since it is the error page, and no
	 * errors have occurred. */
	pg = glade_xml_get_widget( xml, "page_user");
	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}

/* when the "Finish" button is pressed on the last page. */
static gboolean 
on_finish( GnomeDruidPage *druidpage)
{
	/* hide the druid. */
	gtk_widget_hide( glade_xml_get_widget( xml, "druid_win"));

	/* show the main app window. */
	gnutr_show_base_win();

	return FALSE;
}

/* when a "Cancel" button is pressed in the Druid. */
static gboolean 
on_page_cancel( GnomeDruidPage *druid_page)
{
	GtkWidget *win = glade_xml_get_widget( xml, "druid_win");
	gtk_widget_hide( win);
	gtk_main_quit();
	return FALSE;
}

static gboolean 
on_db_error_next( GnomeDruidPage *druid_page)
{
	GtkWidget *drd = glade_xml_get_widget( xml, "druid");
	GtkWidget *pg = glade_xml_get_widget( xml, "page_create_db");

	/* when the "Next" button is pressed on the error page, go
	 * back to the database setup page. i.e "Next" and "Back" do the
	 * same thing. */
	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}

static gboolean 
on_user_setup_next( GnomeDruidPage *druid_page)
{
	GtkWidget *uname_entry = glade_xml_get_widget( xml, "username_entry");
	GtkWidget *pword_entry = glade_xml_get_widget( xml, "password_entry");
	char *uname = gtk_entry_get_text( GTK_ENTRY( uname_entry));
	char *pword = gtk_entry_get_text( GTK_ENTRY( pword_entry));
	GtkWidget *drd; 
	GtkWidget *pg;

	drd = glade_xml_get_widget( xml, "druid");

	/* check that all the entries have been filled in, or stay
	 * on the same page. */
	if ( strlen( uname) == 0 || strlen( pword) == 0) {
		pg = glade_xml_get_widget( xml, "page_user");

		gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
		return TRUE;
	}

	/* There are two possibilities here. either the user is
	 * setting his user name and password for the first time, or
	 * his info is already in the database but the files in
	 * "~/.gnutrition" are not present. */

	/* first check that the user name is not already in the
	 * database. If it is, we try to connect the provided password. */
	if ( user_name_exists( uname)) {
		/* change the connection to the database from 'root'
		 * to the normal user. */
		if ( change_user_db( uname, pword, "gnutr_db")) {
			char *real_name;

			pg = glade_xml_get_widget( xml, "page_end");

			/* re-write file to "~/.gnutrition" */
			gnutr_write_access_cfg( uname, pword);

			real_name = get_name_from_db( uname);
			gnutr_write_person_name_cfg( real_name);
			g_free( real_name);

			/* initialize a series of temporary tables for
			 * the user. */
			gnutr_user_initialize();

			gnome_druid_set_page( GNOME_DRUID( drd), 
				GNOME_DRUID_PAGE( pg));
			return TRUE;
		} else {
			/* the next page is the "error: user setup" page. */
			return FALSE;
		}
	}

	/* add the user to the databse access privileges, and write the
	 * mysql_access.xml file to the "~/.gnutrition" directory. */
	gnutr_write_access_cfg( uname, pword);
	add_user_db( uname, pword);

	/* change the connection to the database from 'root' to the
	 * normal user. */
	change_user_db( uname, pword, "gnutr_db");

	pg = glade_xml_get_widget( xml, "page_personal");
	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));

	return TRUE;
}

static gboolean 
on_user_setup_back( GnomeDruidPage *druid_page)
{
	GtkWidget *drd = glade_xml_get_widget( xml, "druid");
	GtkWidget *pg = glade_xml_get_widget( xml, "page_create_db");

	/* When the "Back" button is pressed, skip over the previous
	 * page, the database error page, back to the database setup
	 * page. */
	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}

/* When "female" button toggled */
static void
on_female_radio_toggled( GtkWidget *radio,
                         gpointer   data)
{
	GtkWidget *preg, *lac, *neither;

	preg = glade_xml_get_widget( xml, "pregnant_radio");
	lac = glade_xml_get_widget( xml, "lactating_radio");
	neither = glade_xml_get_widget( xml, "neither_radio");

	if ( GTK_TOGGLE_BUTTON( radio)->active) {
		gtk_widget_set_sensitive( preg, TRUE);
		gtk_widget_set_sensitive( lac, TRUE);
		gtk_widget_set_sensitive( neither, TRUE);
	} else {	/* "Male" is selected, so not valid */
		gtk_widget_set_sensitive( preg, FALSE);
		gtk_widget_set_sensitive( lac, FALSE);
		gtk_widget_set_sensitive( neither, FALSE);
		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( neither), 
			TRUE);
	}
}

static gboolean 
on_page_personal_next( GnomeDruidPage *druid_page)
{
	GtkWidget *entry;
	GtkWidget *option_menu;
	char *name, *age_txt, *weight_txt;
	float age, weight;
	gboolean female, lactating, pregnant;
	GList *goal_list = NULL;
	GtkWidget *drd, *pg;

	entry = glade_xml_get_widget( xml, "name_entry");
	name = gtk_entry_get_text( GTK_ENTRY( entry));
	entry = glade_xml_get_widget( xml, "age_entry");
	age_txt = gtk_entry_get_text( GTK_ENTRY( entry));
	age = atof( age_txt);
	entry = glade_xml_get_widget( xml, "weight_entry");
	weight_txt = gtk_entry_get_text( GTK_ENTRY( entry));
	weight = atof( weight_txt);

	drd = glade_xml_get_widget( xml, "druid");

	/* check that all the entries have been filled in, or stay
	 * on the same page. */
	if ( strlen( name) == 0 || strlen( age_txt) == 0 ||
			strlen( weight_txt) == 0) 
	{
		pg = glade_xml_get_widget( xml, "page_personal");
		gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
		return TRUE;
	}

	/* store the person's name. */
	gnutr_write_person_name_cfg( name);

	/* add the person's name to the 'person' table. */
	add_name_to_person_table( name);

	/* initialize a series of temporary tables for the user. */
	gnutr_user_initialize();

	/* convert pounds into kilos if the "lbs." menu option is chosen. */
	option_menu = glade_xml_get_widget( xml, "weight_menu");
	if ( GTK_BIN( option_menu)->child) {
		GtkWidget *child = GTK_BIN( option_menu)->child;
		char *option_menu_text;

		if ( GTK_IS_LABEL( child)) {
			gtk_label_get( GTK_LABEL( child), &option_menu_text);
		}
		if ( strcmp( option_menu_text, "lbs.") == 0) {
			weight *= 0.4536;
		}
	}

	/* find which radio buttons are checked. */
	entry = glade_xml_get_widget( xml, "female_radio");
	female = GTK_TOGGLE_BUTTON( entry)->active;
	if ( female) {
		entry = glade_xml_get_widget( xml, "pregnant_radio");
		pregnant = GTK_TOGGLE_BUTTON( entry)->active;
		entry = glade_xml_get_widget( xml, "lactating_radio");
		lactating = GTK_TOGGLE_BUTTON( entry)->active;
	} else {
		pregnant = FALSE;
		lactating = FALSE;
	}

	/* compute the nutrient goal. */
	goal_list = rdi_calc_rdi( age, weight, female, pregnant, lactating);

	/* save the nutrient computed nutrient goal to the database. */
	gnutr_save_nutr_goal( goal_list);

	pg = glade_xml_get_widget( xml, "page_end");
	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}

/* check to see if the provided user name is already in the database. */
static gboolean 
user_name_exists( char *user_name)
{
	char *query;
	char *name;
	gboolean success;

	g_return_val_if_fail( user_name, FALSE);

	success = no_ret_val_query_db( "use mysql");
	g_assert( success);

	query = g_strconcat( "SELECT User FROM user WHERE ",
		"User = '", user_name, "'", NULL);
	name = single_ret_val_query_db( query);
	g_free( query);

	if ( name) {
		g_free( name);
		return TRUE;
	}
	return FALSE;
}

/* when the "Next" button is pressed on the error page, go
 * back to the user setup page. i.e "Next" and "Back" do the
 * same thing. */
static gboolean 
on_user_error_next( GnomeDruidPage *druid_page)
{
	GtkWidget *drd = glade_xml_get_widget( xml, "druid");
	GtkWidget *pg = glade_xml_get_widget( xml, "page_user");

	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}

/* when the "Next" button is pressed on the error page, go
 * back to the "personal details" page. i.e "Next" and "Back" do the
 * same thing. */
static gboolean 
on_personal_error_next( GnomeDruidPage *druid_page)
{
	GtkWidget *drd = glade_xml_get_widget( xml, "druid");
	GtkWidget *pg = glade_xml_get_widget( xml, "page_personal_user");

	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}

/* When the "Back" button is pressed, skip over the "error:
 * user setup" page to the "user setup" page. */
static gboolean 
on_page_personal_back( GnomeDruidPage *druid_page)
{
	GtkWidget *drd = glade_xml_get_widget( xml, "druid");
	GtkWidget *pg = glade_xml_get_widget( xml, "page_user");

	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}

/* When the "Back" button is pressed, skip over the "error:
 * user setup" page to the "personal details" page. */
static gboolean 
on_finish_back( GnomeDruidPage *druid_page)
{
	GtkWidget *drd = glade_xml_get_widget( xml, "druid");
	GtkWidget *pg = glade_xml_get_widget( xml, "page_personal");

	gnome_druid_set_page( GNOME_DRUID( drd), GNOME_DRUID_PAGE( pg));
	return TRUE;
}
