#include <string.h>
#include <gtk/gtk.h>
#include <gnet.h>

#include "gyrus-connection.h"

#include <config.h>

#define UI_FILE "gyrus-talk.xml"

/* Local prototypes */

void init_cb (gpointer a, gpointer b);
void reading_data_cb (gpointer a, gpointer b, gchar *g, gint i);
void make_connection (void);
void disconnect (void);
gboolean progress_bar_pulse_func (gpointer data);
void wait_response (void);
void response_done (void);
void send_command (void);
void log_append_text (const gchar *text);

/* For signals */
void on_window_main_delete_event (GtkWidget *w, gpointer data);
#ifdef HAVE_GNUTLS
void on_checkbutton_usetls_toggled (GtkWidget *w, gpointer data);
#endif
void on_button_connect_clicked (GtkButton *b, gpointer data);
void on_entry_cmd_activate (GtkWidget *w, gpointer data);
void on_button_send_clicked (GtkWidget *w, gpointer data);

/* Widgets */
GtkWidget *window_main;

GtkEntry *entry_host;
GtkCheckButton *checkbutton_usetls;
GtkSpinButton *spinbutton_port;
GtkButton *button_connect;

GtkHBox *hbox_inputs;
GtkEntry *entry_cmd;
GtkTextView *textview_log;
GtkProgressBar *progressbar;

guint pulse_func_id;

/* Connection data */

gboolean connected = FALSE;
/*gboolean gnutls_initialized = FALSE;
*/
GyrusConnection *conn = NULL;

/* Implementation */

void
on_window_main_delete_event (GtkWidget *w, gpointer data)
{
	gtk_main_quit ();
}

#ifdef HAVE_GNUTLS
void
on_checkbutton_usetls_toggled (GtkWidget *w, gpointer data)
{
	gtk_spin_button_set_value (spinbutton_port,
			gtk_toggle_button_get_active (
				GTK_TOGGLE_BUTTON (checkbutton_usetls)) ? 993 : 143);
}
#endif

void
on_button_connect_clicked (GtkButton *b, gpointer data)
{
	if (connected)
		disconnect ();
	else
		make_connection ();	
}

void
on_entry_cmd_activate (GtkWidget *w, gpointer data)
{
	send_command ();
}

void
on_button_send_clicked (GtkWidget *w, gpointer data)
{
	send_command ();
}

void
on_connect_response (GyrusConnection *conn, GyrusConnectionStatus status,
		gpointer user_data)
{
	gchar *str = g_strdup_printf ("*** Connection %s ! ***\n",
			(status == GYRUS_CONN_DONE) ? "done" : "failed");
	
	log_append_text (str);

	g_free (str);
	
	response_done ();

	gtk_widget_set_sensitive (GTK_WIDGET (button_connect), FALSE);
}

void
on_data_received (GyrusConnection *conn, const gchar *data,
		  gboolean eod, gpointer user_data)
{
	if (data)
		log_append_text (data);

	if (eod)
		response_done ();
}

void
on_connection_close (GyrusConnection *conn, gpointer user_data)
{
	GtkTextBuffer *buf = gtk_text_view_get_buffer (textview_log);

	/*gtk_text_buffer_set_text (buf, "", -1);*/

	log_append_text ("*** Connection close ***\n");
	
	gtk_widget_set_sensitive (GTK_WIDGET (button_connect), TRUE);
}

/* Application functions */

void
log_append_text (const gchar *text)
{
	GtkTextBuffer *buf = gtk_text_view_get_buffer (textview_log);
	GtkTextIter iter;

	gtk_text_buffer_get_end_iter (buf, &iter);

	gtk_text_buffer_insert (buf, &iter, text, -1);

	gtk_text_buffer_get_end_iter (buf, &iter);

	gtk_text_view_scroll_to_iter (textview_log, &iter, 0, FALSE, 0, 0);
}

void
make_connection (void)
{
	gchar *host;
	
	wait_response ();
	
	host = g_strdup (gtk_entry_get_text (entry_host));
		
	conn = gyrus_connection_new (host,
				     gtk_spin_button_get_value_as_int (spinbutton_port),
				     gtk_toggle_button_get_active (
					     GTK_TOGGLE_BUTTON (checkbutton_usetls)));
	
	g_free (host);

	/* Connect GyrusConnection signals */
	g_signal_connect (conn, "connect_response",
			G_CALLBACK (on_connect_response), NULL);
	g_signal_connect (conn, "data_received",
			G_CALLBACK (on_data_received), NULL);
	g_signal_connect (conn, "connection_close",
			G_CALLBACK (on_connection_close), NULL);

	/*
	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_usetls)) &&
			(!gnutls_initialized))
	{
		gnutls_global_init ();

		gnutls_initialized = TRUE;
	}
	*/
		
	gyrus_connection_connect (conn);
}

void disconnect (void)
{

}

/* Callback to move the progressbar while is waiting response */
gboolean
progress_bar_pulse_func (gpointer data)
{
	if (pulse_func_id == 0) {
		gtk_progress_bar_set_fraction (progressbar, 0.0);
		return FALSE;
	}
	
	gtk_progress_bar_pulse (progressbar);
	
	return TRUE;
}

/* Waiting for server response */
void
wait_response (void)
{
	gtk_widget_set_sensitive (GTK_WIDGET (hbox_inputs), FALSE);

	pulse_func_id = g_timeout_add (125, progress_bar_pulse_func, NULL);

	g_print ("pulse_func_id = %d\n", pulse_func_id);
}

void
response_done (void)
{
	gtk_widget_set_sensitive (GTK_WIDGET (hbox_inputs), TRUE);

	pulse_func_id = 0;

	gtk_window_set_focus (GTK_WINDOW (window_main),
	                      GTK_WIDGET (entry_cmd));
}

void
send_command (void)
{
	gyrus_connection_send (conn, gtk_entry_get_text (entry_cmd));

	gtk_entry_set_text (entry_cmd, "");

	wait_response ();
}

int
main (int argc, char *argv[])
{
	GtkBuilder *builder;
	GError *error = NULL;
	gnet_init ();
	
	gtk_init (&argc, &argv);

	builder = gtk_builder_new ();
	if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) {
		g_warning ("Couldn't load builder file: %s", error->message);
		g_error_free (error);
		error = NULL;
		return 1;
	}
	window_main = GTK_WIDGET (gtk_builder_get_object (builder, "window_main"));

	entry_host = GTK_ENTRY (gtk_builder_get_object (builder, "entry_host"));
	checkbutton_usetls = GTK_CHECK_BUTTON (gtk_builder_get_object (builder,
								       "checkbutton_usetls"));
#ifdef HAVE_GNUTLS
	g_signal_connect (checkbutton_usetls, "toggled",
			  G_CALLBACK (on_checkbutton_usetls_toggled),
			  NULL);
#endif
	spinbutton_port = GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
								 "spinbutton_port"));
	button_connect = GTK_BUTTON (gtk_builder_get_object (builder, "button_connect"));

	textview_log = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "textview_log"));

	hbox_inputs = GTK_HBOX (gtk_builder_get_object (builder, "hbox_inputs"));
	entry_cmd = GTK_ENTRY (gtk_builder_get_object (builder, "entry_cmd"));

	progressbar = GTK_PROGRESS_BAR (gtk_builder_get_object (builder, "progressbar"));

	gtk_progress_bar_set_text (progressbar, "Ready");

	gtk_builder_connect_signals (builder, NULL);

	g_object_unref (G_OBJECT (builder));

	gtk_widget_show_all (window_main);
#ifndef HAVE_GNUTLS
	gtk_widget_hide (GTK_WIDGET (checkbutton_usetls));
#endif

	gtk_main ();
	
	return 0;
}

