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

#include <stdio.h>
#include <ctype.h>
#include <time.h>

#include "support.h"
#include "main.h"
#include "qsodata.h"
#include "macro.h"
#include "prefs.h"
#include "interface.h"
#include "trx.h"

#define	NUMMACROS	12

struct macro {
	gchar name[16];
	gchar *text;
};

static struct macro macros[NUMMACROS];

#define confcpy(d,s)	{ strncpy((d),(s),sizeof(d)); d[sizeof(d)-1] = 0; }

static GtkWidget *macroconfigwin = NULL;   

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

static void set_macro_button_names(void)
{
	GtkButton *button;
	GtkLabel *label;
	gchar *str;
	gint i;

	for (i = 0; i < NUMMACROS; i++) {
		str = g_strdup_printf("macrobutton%d", i + 1);
		button = GTK_BUTTON(lookup_widget(appwindow, str));
		label = GTK_LABEL(GTK_BIN(button)->child);
		g_free(str);

		str = g_strdup_printf("%s (F%d)", macros[i].name, i + 1);
		gtk_label_set_text(label, str);
		g_free(str);
	}
}

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

static void fill_macroconfig(GtkWidget *win, gint n)
{
	GtkEntry *entry;
	GtkText *text;
	gchar *str;

	/* should not happen... */
	if (n < 1 || n > NUMMACROS) {
		g_print("fill_macroconfig: invalid macro number %d\n", n);
		return;
	}

	str = g_strdup_printf("macro %d", n);
	gtk_window_set_title(GTK_WINDOW(win), str);
	g_free(str);

	n--;

	entry = GTK_ENTRY(lookup_widget(win, "macroconfigentry"));
	gtk_entry_set_text(entry, macros[n].name);

	/* This seems to be the only way to really control the font used */
	text = GTK_TEXT(lookup_widget(win, "macroconfigtext"));
	if (macros[n].text[0] == 0) {
		gtk_text_insert(text, rxfont, NULL, NULL, " ", -1);
		gtk_editable_delete_text(GTK_EDITABLE(text), 0, -1);
	} else {
		gtk_text_insert(text, rxfont, NULL, NULL, macros[n].text, -1);
	}
}

static void apply_macroconfig(GtkWidget *win)
{
	GtkEditable *editable;
	gchar *str;
	gchar *s;
	gint n;

	/* the window title is "macro n" */
	n = atoi(GTK_WINDOW(win)->title + 6);

	if (n < 1 || n > NUMMACROS) {
		g_print("apply_macroconfig: invalid macro number %d\n", n);
		return;
	}

	editable = GTK_EDITABLE(lookup_widget(win, "macroconfigentry"));
	s = gtk_editable_get_chars(editable, 0, -1);
	strncpy(macros[n - 1].name, s, 16);
	macros[n - 1].name[15] = 0;
	g_free(s);

	editable = GTK_EDITABLE(lookup_widget(win, "macroconfigtext"));
	s = gtk_editable_get_chars(editable, 0, -1);
	g_free(macros[n - 1].text);
	macros[n - 1].text = s;

	str = g_strdup_printf("/gMFSK/macro/name%d", n);
	gnome_config_set_string(str, macros[n - 1].name);
	g_free(str);

	str = g_strdup_printf("/gMFSK/macro/text%d", n);
	gnome_config_set_string(str, macros[n - 1].text);
	g_free(str);

	gnome_config_sync();

	set_macro_button_names();
}

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

void macroconfig_load(void)
{
	gchar *p;

	p = gnome_config_get_string("/gMFSK/macro/name1=" MACRODEF1NAME);
	confcpy(macros[0].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text1=" MACRODEF1TEXT);
	macros[0].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name2=" MACRODEF2NAME);
	confcpy(macros[1].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text2=" MACRODEF2TEXT);
	macros[1].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name3=" MACRODEF3NAME);
	confcpy(macros[2].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text3=" MACRODEF3TEXT);
	macros[2].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name4=" MACRODEF4NAME);
	confcpy(macros[3].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text4=" MACRODEF4TEXT);
	macros[3].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name5=" MACRODEF5NAME);
	confcpy(macros[4].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text5=" MACRODEF5TEXT);
	macros[4].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name6=" MACRODEF6NAME);
	confcpy(macros[5].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text6=" MACRODEF6TEXT);
	macros[5].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name7=" MACRODEF7NAME);
	confcpy(macros[6].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text7=" MACRODEF7TEXT);
	macros[6].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name8=" MACRODEF8NAME);
	confcpy(macros[7].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text8=" MACRODEF8TEXT);
	macros[7].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name9=" MACRODEF9NAME);
	confcpy(macros[8].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text9=" MACRODEF9TEXT);
	macros[8].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name10=" MACRODEF10NAME);
	confcpy(macros[9].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text10=" MACRODEF10TEXT);
	macros[9].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name11=" MACRODEF11NAME);
	confcpy(macros[10].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text11=" MACRODEF11TEXT);
	macros[10].text = p;

	p = gnome_config_get_string("/gMFSK/macro/name12=" MACRODEF12NAME);
	confcpy(macros[11].name, p);
	g_free(p);
	p = gnome_config_get_string("/gMFSK/macro/text12=" MACRODEF12TEXT);
	macros[11].text = p;

	set_macro_button_names();
}

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

void macroconfig(gint n)
{
	if (macroconfigwin)
		return;

	macroconfigwin = create_macroconfigwindow();
	fill_macroconfig(macroconfigwin, n);
	gtk_widget_show(macroconfigwin);
}

void macroconfig_clear(void)
{
	GtkWidget *widget;

	if (!macroconfigwin)
		return;

	widget = lookup_widget(macroconfigwin, "macroconfigentry");
	gtk_editable_delete_text(GTK_EDITABLE(widget), 0, -1);

	widget = lookup_widget(macroconfigwin, "macroconfigtext");
	gtk_editable_delete_text(GTK_EDITABLE(widget), 0, -1);
}

void macroconfig_close(gboolean save)
{
	if (!macroconfigwin)
		return;

	if (save == TRUE)
		apply_macroconfig(macroconfigwin);

	gtk_widget_destroy(macroconfigwin);
	macroconfigwin = NULL;
}

void macroconfig_delete(void)
{
	macroconfigwin = NULL;
}

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

#define	CMDBUFSIZE	4096

static void run_command(gchar *cmd)
{
	gchar buf[CMDBUFSIZE];
	FILE *fp;
	gint len;

	cmd++;				/* skip   '('	*/
	cmd[strlen(cmd) - 1] = 0;	/* delete ')'	*/

	if ((fp = popen(cmd, "r")) == NULL) {
		errmsg("run_command: popen: %m");
		return;
	}

	len = fread(buf, sizeof(gchar), CMDBUFSIZE - 1, fp);

	/* delete the last end-of-line if there is one */
	if (buf[len - 1] == '\n')
		buf[len - 1] = 0;

	/* just to be sure... */
	buf[len] = 0;

	send_string(buf);

	pclose(fp);
}

static void send_time(const gchar *fmt, gboolean utc)
{
	gchar buf[256];
	struct tm *tm;
	time_t t;

	time(&t);

	if (utc)
		tm = gmtime(&t);
	else
		tm = localtime(&t);

	strftime(buf, sizeof(buf), fmt, tm);
	buf[sizeof(buf) - 1] = 0;

	send_string(buf);
}

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

static gchar *getword(gchar **ptr)
{
	gchar *word, *p;

	if (**ptr == '(') {
		if ((p = strchr(*ptr, ')')) == NULL)
			return NULL;
		p++;
	} else {
		for (p = *ptr; *p && isalnum(*p); p++)
			;
	}

	word = g_memdup(*ptr, p - *ptr + 1);
	word[p - *ptr] = 0;

	*ptr = p;

	return word;
}

void send_macro(gint n)
{
	gchar *p, *word;

	/* should not happen... */
	if (n < 1 || n > NUMMACROS) {
		g_print("send_macro: invalid macro number %d\n", n);
		return;
	}

	p = macros[n - 1].text;

	while (p && *p) {
		if (*p == '$') {
			p++;
			word = getword(&p);

			if (word == NULL)
				continue;

			if (word[0] == '(')
				run_command(word);

			if (!strcasecmp(word, "$"))
				send_char('$');

			if (!strcasecmp(word, "soft"))
				send_string(SoftString);

			/*
			 * Buttons
			 */
			if (!strcasecmp(word, "tx")) {
				trx_set_state_wait(TRX_STATE_TX);
				push_button("txbutton");
			}

			if (!strcasecmp(word, "rx"))
				push_button("rxbutton");

			if (!strcasecmp(word, "pause"))
				push_button("pausebutton");

			if (!strcasecmp(word, "abort"))
				push_button("abortbutton");

			/*
			 * My station info
			 */
			if (!strcasecmp(word, "mycall"))
				send_string(prefs.mycall);

			if (!strcasecmp(word, "myname"))
				send_string(prefs.myname);

			if (!strcasecmp(word, "myqth"))
				send_string(prefs.myqth);

			if (!strcasecmp(word, "myloc"))
				send_string(prefs.myloc);

			if (!strcasecmp(word, "myemail"))
				send_string(prefs.myemail);

			/*
			 * Time and date
			 */
			if (!strcasecmp(word, "time"))
				send_time(prefs.timefmt, FALSE);

			if (!strcasecmp(word, "utctime"))
				send_time(prefs.timefmt, TRUE);

			if (!strcasecmp(word, "date"))
				send_time(prefs.datefmt, FALSE);

			if (!strcasecmp(word, "utcdate"))
				send_time(prefs.datefmt, TRUE);

			/*
			 * QSO data
			 */
			if (!strcasecmp(word, "call"))
				send_string(get_qsocall());

			if (!strcasecmp(word, "band"))
				send_string(get_qsoband());

			if (!strcasecmp(word, "rxrst"))
				send_string(get_qsorxrst());

			if (!strcasecmp(word, "txrst"))
				send_string(get_qsotxrst());

			if (!strcasecmp(word, "name"))
				send_string(get_qsoname());

			if (!strcasecmp(word, "qth"))
				send_string(get_qsoqth());

			if (!strcasecmp(word, "notes"))
				send_string(get_qsonotes());

			/* an unknown macro gets ignored */

			g_free(word);
			continue;
		}

		send_char(*p++);
	}
}

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