#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>
#include <ctype.h>
#include <errno.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"

#include "main.h"
#include "trx.h"
#include "wf.h"
#include "macro.h"
#include "prefs.h"
#include "qsodata.h"
#include "log.h"

static GtkWidget *txfileselectwin = NULL;
static GtkWidget *rxfileselectwin = NULL;
static gchar *popupselection = NULL;

/* ---------------------------------------------------------------------- */

gboolean
on_appwindow_delete_event              (GtkWidget       *widget,
                                        GdkEvent        *event,
                                        gpointer         user_data)
{
	trx_set_state(TRX_STATE_ABORT);
	gtk_main_quit();

	return TRUE;
}


void
on_exit1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	trx_set_state(TRX_STATE_ABORT);
	gtk_main_quit();
}


void
on_preferences1_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GtkWidget *propertybox;

	propertybox = create_propertybox();
	fill_config(propertybox);
	gtk_widget_show(propertybox);
}


void
on_about1_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GtkWidget *aboutwindow;

	aboutwindow = create_aboutwindow();
	gtk_widget_show(aboutwindow);
}

/* ---------------------------------------------------------------------- */

gboolean
on_waterfall_motion_notify_event       (GtkWidget       *widget,
                                        GdkEventMotion  *event,
                                        gpointer         user_data)
{
	Waterfall *wfall;

	wfall = WATERFALL(lookup_widget(appwindow, "waterfall"));
	waterfall_setmarker1(wfall, event->x);

	return FALSE;
}


gboolean
on_waterfall_leave_notify_event        (GtkWidget       *widget,
                                        GdkEventCrossing *event,
                                        gpointer         user_data)
{
	Waterfall *wfall;

	wfall = WATERFALL(lookup_widget(appwindow, "waterfall"));
	waterfall_setmarker1(wfall, -1);

	return FALSE;
}


gboolean
on_waterfall_button_press_event        (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	gfloat freq;

	/* button 3 over waterfall toggles waterfall pause */
	if (event->button == 3) {
		wf_togglepause();
		return FALSE;
	}

	/* any other button sets trx frequency */
	freq = wf_xtof(event->x);
	trx_set_freq(freq);

	return FALSE;
}

/* ---------------------------------------------------------------------- */

gboolean
on_txtext_key_press_event              (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data)
{
	GtkText *text = GTK_TEXT(widget);

	/* ignore if CTRL or ALT is pressed (reserved for accelerators) */
	if ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_MOD1_MASK))
		return FALSE;

	switch (event->keyval) {
	case GDK_Return:
		send_char('\n');
		break;
	case GDK_BackSpace:
		trx_put_tx_char(8);
		gtk_text_backward_delete(text, 1);
		gtk_text_backward_delete(text, 1);
		gtk_text_insert(text, NULL, NULL, NULL, "_", -1);
		break;
	default:
		if (event->keyval < 256)
			send_char(event->keyval);
		break;
	}

	return FALSE;
}


gboolean
on_rxtext_key_release_event            (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data)
{
	return FALSE;
}

/* ---------------------------------------------------------------------- */

void
on_freqspinbutton_changed              (GtkEditable     *editable,
                                        gpointer         user_data)
{
	GtkSpinButton *spin;
	gfloat freq;

	spin = GTK_SPIN_BUTTON(editable);
	freq = gtk_spin_button_get_value_as_float(spin);
	trx_set_freq(freq);
}


void
on_afcbutton_toggled                   (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	trx_set_afc(gtk_toggle_button_get_active(togglebutton));
}


void
on_squelchbutton_toggled               (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	trx_set_squelch(gtk_toggle_button_get_active(togglebutton));
}


void
on_reversebutton_toggled               (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	trx_set_reverse(gtk_toggle_button_get_active(togglebutton));
}

/* ---------------------------------------------------------------------- */

void
on_macrobutton_clicked                 (GtkButton       *button,
                                        gpointer         user_data)
{
	send_macro(GPOINTER_TO_INT(user_data));
}


gboolean
on_macrobutton_button_press_event      (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	/* we are only interested in button 3 */
	if (event->button != 3)
		return FALSE;

	macroconfig(GPOINTER_TO_INT(user_data));

	return FALSE;
}


void
on_macroconfigclear_clicked            (GtkButton       *button,
                                        gpointer         user_data)
{
	macroconfig_clear();
}


void
on_macroconfigok_clicked               (GtkButton       *button,
                                        gpointer         user_data)
{
	macroconfig_close(TRUE);
}


void
on_macroconfigcancel_clicked           (GtkButton       *button,
                                        gpointer         user_data)
{
	macroconfig_close(FALSE);
}


gboolean
on_macroconfigwindow_delete_event      (GtkWidget       *widget,
                                        GdkEvent        *event,
                                        gpointer         user_data)
{
	macroconfig_delete();

	return FALSE;
}

/* ---------------------------------------------------------------------- */

void
on_propertybox_apply                   (GnomePropertyBox *gnomepropertybox,
                                        gint             arg1,
                                        gpointer         user_data)
{
	/* only apply on the last page */
	if (arg1 == -1)
		apply_config(GTK_WIDGET(gnomepropertybox));
}

/* ---------------------------------------------------------------------- */

void
on_pausebutton_toggled                 (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	gboolean b = gtk_toggle_button_get_active(togglebutton);

	if (b && trx_get_state() != TRX_STATE_ABORT)
		trx_set_state(TRX_STATE_PAUSE);
}


void
on_rxbutton_toggled                    (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	gboolean b = gtk_toggle_button_get_active(togglebutton);

	if (b)	trx_set_state(TRX_STATE_RX);
}


void
on_txbutton_toggled                    (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	GtkWidget *widget;
	gboolean b = gtk_toggle_button_get_active(togglebutton);

	if (b) {
		trx_set_state(TRX_STATE_TX);

		/* set focus to the tx text widget */
		widget = lookup_widget(appwindow, "txtext");
		gtk_widget_grab_focus(widget);
	}
}


void
on_abortbutton_clicked                 (GtkButton       *button,
                                        gpointer         user_data)
{
	gint state = trx_get_state();

	if (state != TRX_STATE_ABORT && state != TRX_STATE_PAUSE) {
		trx_set_state_wait(TRX_STATE_ABORT);
		/* clear tx typeahead buffer */
		while (trx_get_tx_char() != -1);
		/* switch to rx */
		trx_set_state_wait(TRX_STATE_RX);
		push_button("rxbutton");
	}
}


static gint
tune_timeout_cb                        (gpointer unused)
{
	gdk_threads_enter();
	if (trx_get_state() == TRX_STATE_TUNE)
		push_button("rxbutton");
	gdk_threads_leave();

	return FALSE;
}


void
on_tunebutton_toggled                  (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	gboolean b = gtk_toggle_button_get_active(togglebutton);

	if (b) {
		trx_set_state(TRX_STATE_TUNE);
		gtk_timeout_add(30000, tune_timeout_cb, NULL);
	}
}

/* ---------------------------------------------------------------------- */

gboolean
on_rxtext_button_press_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	GtkText *text = GTK_TEXT(widget);
	GtkEditable *edit = GTK_EDITABLE(widget);
	GdkEvent bevent;
	gint pos, start, stop, len;

	/* we are only interested in button 3 */
	if (event->button != 3)
		return FALSE;

	/* must send the text widget a release event or else it's confused */
	bevent.button = *event;
	bevent.button.type = GDK_BUTTON_RELEASE;
	gtk_widget_event(widget, &bevent);

	/* find the word */
	pos = gtk_editable_get_position(edit);

	if (isspace(GTK_TEXT_INDEX(text, pos)))
		return FALSE;

	len = gtk_text_get_length(text);

	start = pos;
	while (!isspace(GTK_TEXT_INDEX(text, start)) && start > 0)
		start--;

	if (isspace(GTK_TEXT_INDEX(text, start)))
		start++;

	stop = pos;
	while (!isspace(GTK_TEXT_INDEX(text, stop)) && stop < len)
		stop++;

	if (stop == len)
		stop--;

	/* save the selected text */
	g_free(popupselection);
	popupselection = gtk_editable_get_chars(edit, start, stop);

	/* select it */
	gtk_editable_select_region(edit, start, stop);

	/* pop the menu up */
	gtk_menu_popup(GTK_MENU(PopupMenu), NULL, NULL, NULL, NULL,
		       event->button, event->time);

	return FALSE;
}


void
on_callsign1_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	set_qsocall(popupselection);

	g_free(popupselection);
	popupselection = NULL;
}


void
on_qth1_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	set_qsoqth(popupselection);

	g_free(popupselection);
	popupselection = NULL;
}


void
on_name1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	set_qsoname(popupselection);

	g_free(popupselection);
	popupselection = NULL;
}


void
on_received_rst1_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	set_qsorxrst(popupselection);

	g_free(popupselection);
	popupselection = NULL;
}


void
on_sent_rst1_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	set_qsotxrst(popupselection);

	g_free(popupselection);
	popupselection = NULL;
}


void
on_notes1_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	set_qsonotes(popupselection);

	g_free(popupselection);
	popupselection = NULL;
}


void
on_band1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	set_qsoband(popupselection);

	g_free(popupselection);
	popupselection = NULL;
}


void
on_logbutton_clicked                   (GtkButton       *button,
                                        gpointer         user_data)
{
	log_qsodata();
}


void
on_newbutton_clicked                   (GtkButton       *button,
                                        gpointer         user_data)
{
	clear_qsodata();
}


void
on_qsoentry_changed                    (GtkEditable     *editable,
                                        gpointer         user_data)
{
	set_qsotime();
}

/* ---------------------------------------------------------------------- */

gboolean
on_txtext_button_press_event           (GtkWidget       *widget,
                                        GdkEventButton  *event,
                                        gpointer         user_data)
{
	static GdkAtom targets_atom = GDK_NONE;

	/* we are interested in the middle button */
	if (event->button != 2)
		return TRUE;

	/* STRING targets */
	if (targets_atom == GDK_NONE)
		targets_atom = gdk_atom_intern("STRING", FALSE);

	/* And request the "STRING" target for the primary selection */
        gtk_selection_convert(widget, GDK_SELECTION_PRIMARY,
			      targets_atom, GDK_CURRENT_TIME);

	return TRUE;
}


void
on_txtext_selection_received           (GtkWidget       *widget,
                                        GtkSelectionData *data,
                                        guint            time,
                                        gpointer         user_data)
{
	/* we don't want the default handlers to run no matter what */
	gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "selection_received");

	if (data->length < 0) {
		g_print("Selection retrieval failed\n");
		return;
	}

	/* Make sure we got the data in the expected form */
	if (data->type != GDK_SELECTION_TYPE_STRING) {
		g_print("Selection not returned in expected form\n");
		return;
	}

	send_string(data->data);
}

/* ---------------------------------------------------------------------- */

void
on_send_file1_activate                 (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	if (txfileselectwin)
		return;

	txfileselectwin = create_txfileselection();
	gtk_widget_show(txfileselectwin);
}

void
on_log_to_file1_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	gchar *name;

	if (rxfileselectwin)
		return;

	if ((name = log_to_file_get_name()) != NULL) {
		errmsg("Already logging to file \"%s\" !", name);
		return;
	}

	rxfileselectwin = create_rxfileselection();
	gtk_widget_show(rxfileselectwin);
}


void
on_stop_logging1_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	log_to_file_stop();
}


void
on_clear_tx_window1_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
        GtkEditable *editable;

	editable = GTK_EDITABLE(lookup_widget(appwindow, "txtext"));
	gtk_editable_delete_text(editable, 0, -1);

	/* clear tx typeahead buffer */
	while (trx_get_tx_char() != -1);
}


void
on_clear_rx_window1_activate           (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
        GtkEditable *editable;

	editable = GTK_EDITABLE(lookup_widget(appwindow, "rxtext"));
	gtk_editable_delete_text(editable, 0, -1);
}

/* ---------------------------------------------------------------------- */

void
on_macroconfig1_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(1);
}


void
on_macroconfig2_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(2);
}


void
on_macroconfig3_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(3);
}


void
on_macroconfig4_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(4);
}


void
on_macroconfig5_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(5);
}


void
on_macroconfig6_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(6);
}


void
on_macroconfig7_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(7);
}


void
on_macroconfig8_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(8);
}


void
on_macroconfig9_activate               (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(9);
}


void
on_macroconfig10_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(10);
}


void
on_macroconfig11_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(11);
}


void
on_macroconfig12_activate              (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	macroconfig(12);
}

/* ---------------------------------------------------------------------- */

void
on_txfileselect_ok_button_clicked      (GtkButton       *button,
                                        gpointer         user_data)
{
	GtkFileSelection *fs;
	gchar *fname, line[1024];
	FILE *fp;

	g_return_if_fail(txfileselectwin);

	fs = GTK_FILE_SELECTION(txfileselectwin);
	fname = g_strdup(gtk_file_selection_get_filename(fs));

	gtk_widget_destroy(txfileselectwin);
	txfileselectwin = NULL;

	if ((fp = fopen(fname, "r")) == NULL) {
		errmsg("fopen: %s: %s", fname, strerror(errno));
		g_free(fname);
		return;
	}

	while (fgets(line, sizeof(line) - 1, fp) > 0) {
		line[sizeof(line) - 1] = 0;
		send_string(line);
	}

	g_free(fname);
}


void
on_txfileselect_cancel_button_clicked  (GtkButton       *button,
                                        gpointer         user_data)
{
	g_return_if_fail(txfileselectwin);

	gtk_widget_destroy(txfileselectwin);
	txfileselectwin = NULL;
}


gboolean
on_txfileselection_delete_event        (GtkWidget       *widget,
                                        GdkEvent        *event,
                                        gpointer         user_data)
{
	g_return_val_if_fail(txfileselectwin, FALSE);

	gtk_widget_destroy(txfileselectwin);
	txfileselectwin = NULL;

	return FALSE;
}


void
on_rxfileselect_ok_button_clicked      (GtkButton       *button,
                                        gpointer         user_data)
{
	GtkFileSelection *fs;
	gchar *fname;

	g_return_if_fail(rxfileselectwin);

	fs = GTK_FILE_SELECTION(rxfileselectwin);
	fname = g_strdup(gtk_file_selection_get_filename(fs));

	gtk_widget_destroy(rxfileselectwin);
	rxfileselectwin = NULL;

	if (log_to_file_start(fname) < 0)
		errmsg("Log to file failed: %s: %m", fname);

	g_free(fname);
}


void
on_rxfileselect_cancel_button_clicked  (GtkButton       *button,
                                        gpointer         user_data)
{
	g_return_if_fail(rxfileselectwin);

	gtk_widget_destroy(rxfileselectwin);
	rxfileselectwin = NULL;
}


gboolean
on_rxfileselection_delete_event        (GtkWidget       *widget,
                                        GdkEvent        *event,
                                        gpointer         user_data)
{
	g_return_val_if_fail(rxfileselectwin, FALSE);

	gtk_widget_destroy(rxfileselectwin);
	rxfileselectwin = NULL;

	return FALSE;
}

/* ---------------------------------------------------------------------- */

void
on_mfsk1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM(menuitem);
        Waterfall *wfall;
	gint state;

        wfall = WATERFALL(lookup_widget(appwindow, "waterfall"));

	if (item->active && trx_get_mode() != MODE_MFSK16) {
		state = trx_get_state();
		trx_set_state_wait(TRX_STATE_ABORT);
		trx_set_mode(MODE_MFSK16);
		trx_set_state_wait(state);
		gtk_widget_set_sensitive(lookup_widget(appwindow, "squelchbutton"), TRUE);
		waterfall_setcenter(wfall, FALSE);
	}
}


void
on_rtty1_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM(menuitem);
        Waterfall *wfall;
	gint state;

        wfall = WATERFALL(lookup_widget(appwindow, "waterfall"));

	if (item->active && trx_get_mode() != MODE_RTTY) {
		state = trx_get_state();
		trx_set_state_wait(TRX_STATE_ABORT);
		trx_set_mode(MODE_RTTY);
		trx_set_state_wait(state);
		trx_set_metric(0.0);
		gtk_widget_set_sensitive(lookup_widget(appwindow, "squelchbutton"), FALSE);
		waterfall_setcenter(wfall, FALSE);
	}
}


void
on_throb1_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM(menuitem);
        Waterfall *wfall;
	gint state;

        wfall = WATERFALL(lookup_widget(appwindow, "waterfall"));

	if (item->active && trx_get_mode() != MODE_THROB1) {
		state = trx_get_state();
		trx_set_state_wait(TRX_STATE_ABORT);
		trx_set_mode(MODE_THROB1);
		trx_set_state_wait(state);
		trx_set_metric(0.0);
		gtk_widget_set_sensitive(lookup_widget(appwindow, "squelchbutton"), FALSE);
		waterfall_setcenter(wfall, TRUE);
	}
}


void
on_throb2_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM(menuitem);
        Waterfall *wfall;
	gint state;

        wfall = WATERFALL(lookup_widget(appwindow, "waterfall"));

	if (item->active && trx_get_mode() != MODE_THROB2) {
		state = trx_get_state();
		trx_set_state_wait(TRX_STATE_ABORT);
		trx_set_mode(MODE_THROB2);
		trx_set_state_wait(state);
		trx_set_metric(0.0);
		gtk_widget_set_sensitive(lookup_widget(appwindow, "squelchbutton"), FALSE);
		waterfall_setcenter(wfall, TRUE);
	}
}


void
on_throb4_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
	GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM(menuitem);
        Waterfall *wfall;
	gint state;

        wfall = WATERFALL(lookup_widget(appwindow, "waterfall"));

	if (item->active && trx_get_mode() != MODE_THROB4) {
		state = trx_get_state();
		trx_set_state_wait(TRX_STATE_ABORT);
		trx_set_mode(MODE_THROB4);
		trx_set_state_wait(state);
		trx_set_metric(0.0);
		gtk_widget_set_sensitive(lookup_widget(appwindow, "squelchbutton"), FALSE);
		waterfall_setcenter(wfall, TRUE);
	}
}

/* ---------------------------------------------------------------------- */

void
on_mag1button_toggled                  (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	if (gtk_toggle_button_get_active(togglebutton))
		init_wf(2048, trx_get_freq() + trx_get_bandwidth() / 2.0);
}


void
on_mag2button_toggled                  (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	if (gtk_toggle_button_get_active(togglebutton))
		init_wf(4096, trx_get_freq() + trx_get_bandwidth() / 2.0);
}


void
on_mag4button_toggled                  (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
	if (gtk_toggle_button_get_active(togglebutton))
		init_wf(8192, trx_get_freq() + trx_get_bandwidth() / 2.0);
}

/* ---------------------------------------------------------------------- */

