/*****************************************************************************/

/*
 *      eppfm.c  --  EPP modem virtual transceiver.
 *
 *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
 *
 *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Please note that the GPL allows you to use the driver, NOT the radio.
 *  In order to use the radio, you need a license from the communications
 *  authority of your country.
 *
 */

/*****************************************************************************/

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

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "getopt.h"
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "eppfm.h"

#include <gtk/gtk.h>

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

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

struct adapter_config cfg = { 19666600, 9600, 0, 0, 0, 1, 1, 0, 1 };

static unsigned verboselevel = 0;
static unsigned syslogmsg = 0;

static unsigned int ptt = 0;
static unsigned int squelch = 0;

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

/*OutputDebugStringA*/
int lprintf(unsigned vl, const char *format, ...)
{
        va_list ap;
        int r;

        if (vl > verboselevel)
                return 0;
        va_start(ap, format);
#ifdef HAVE_VSYSLOG
        if (syslogmsg) {
                static const int logprio[] = { LOG_ERR, LOG_INFO };
                vsyslog((vl > 1) ? LOG_DEBUG : logprio[vl], format, ap);
                r = 0;
        } else
#endif
                r = vfprintf(stderr, format, ap);
        va_end(ap);
        return r;
}

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

GtkWidget *ioconfig;
GtkWidget *mainwindow;
GtkWidget *aboutdialog;
GtkWidget *dtmfwindow;
GtkWidget *scopewindow;
GtkWidget *spectrumwindow;


void gui_addsamples(unsigned int num, const int16_t *y)
{
	Scope *scope;
	Spectrum *spec;

	scope = SCOPE(gtk_object_get_data(GTK_OBJECT(scopewindow), "scope"));
	spec = SPECTRUM(gtk_object_get_data(GTK_OBJECT(spectrumwindow), "spec"));
	scope_addvalues(scope, num, NULL, y);
	spectrum_addvalues(spec, num, y);
}

void gui_updatevu(float meter1, float meter2)
{
	GtkProgress *pb1, *pb2;

	pb1 = GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(mainwindow), "progressbar1"));
	pb2 = GTK_PROGRESS(gtk_object_get_data(GTK_OBJECT(mainwindow), "progressbar2"));
	gtk_progress_set_value(pb1, meter1);
	gtk_progress_set_value(pb2, meter2);
}

void on_dtmf_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(dtmfwindow);
}

void on_oscilloscope_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(scopewindow);
}

void on_spectrum_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(spectrumwindow);
}

void on_quit_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_main_quit();
}

void on_about_activate(GtkMenuItem *menuitem, gpointer user_data)
{
	gtk_widget_show(aboutdialog);
}

void on_dtmfclear_clicked(GtkButton *button, gpointer user_data)
{
	GtkEntry *entry;
	
	entry = GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(dtmfwindow), "dtmfentry"));
	gtk_entry_set_text(entry, "");
}

static gint dtmfkeyfunc(gpointer data)
{
	return on_dtmfwindow_key_event(NULL, NULL, data);
}

gboolean on_dtmfwindow_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
	static const char dtmfkeys[] = "0123456789ABCD*#";
	static guint tmo = 0;
	static guint lastkey = -1;
	static guint currentkey = 0;
	GtkButton *but;
	gchar bname[6] = "dtmf0";
	char *cp, c;

	if (!event) {
		tmo = 0;
		lastkey = currentkey;
		bname[4] += lastkey & 15;
		if ((lastkey & 15) >= 10)
			bname[4] += 'a'-'0'-10;
		but = GTK_BUTTON(gtk_object_get_data(GTK_OBJECT(dtmfwindow), bname));
		if (lastkey & 16)
			gtk_button_pressed(but);
		else
			gtk_button_released(but);
		return FALSE;  /* don't get called again */
	}
	c = event->keyval;
	if (c >= 'a' && c <= 'z')
		c += 'A'-'a';
	if (!(cp = strchr(dtmfkeys, c)))
		return FALSE;
	currentkey = cp - dtmfkeys + (event->type == GDK_KEY_PRESS ? 16 : 0);
	if (tmo)
		gtk_timeout_remove(tmo);
	if (currentkey != lastkey)
		tmo = gtk_timeout_add(10, dtmfkeyfunc, NULL);
	return TRUE;
}

void on_dtmf_key(GtkButton *button, gpointer user_data)
{
	static const char dtmfkeys[] = "0123456789ABCD*#";
	GtkEntry *entry;
	gchar txt[2];
	guint key = (guint)user_data;
		
	printf("DTMF key: %u\n", key);
	if (key & 16)
		ptt |= 2;
	else 
		ptt &= ~2;
	audio_ptt(ptt);
	audio_setsquelch(squelch);
	audio_dtmf(key);
	if (key < 0x10 || key > 0x1f)
		return;
	txt[0] = dtmfkeys[key & 0xf];
	txt[1] = 0;
	entry = GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(dtmfwindow), "dtmfentry"));
	gtk_entry_append_text(entry, txt);
}

void on_configok_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_show(mainwindow);
	gtk_widget_hide(ioconfig);
}

void on_configquit_clicked(GtkButton *button, gpointer user_data)
{
	gtk_main_quit();
}

gboolean on_mainwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	return FALSE;
}

void on_mainwindow_destroy(GtkObject *object, gpointer user_data)
{
	gtk_main_quit();
}

static gint pttkeyfunc(gpointer data)
{
	return on_mainwindow_key_event(NULL, NULL, data);
}

gboolean on_mainwindow_key_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
	static guint tmo = 0;
	static guint laststate = -1;
	static guint currentstate = 0;
	GtkToggleButton *ptt;

	if (!event) {
		tmo = 0;
		laststate = currentstate;
		ptt = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "buttonptt"));
		gtk_toggle_button_set_active(ptt, laststate);
		printf("gtk_toggle_button_set_active: %d\n", laststate);
		return FALSE;  /* don't get called again */
	}
	if (event->keyval == 32) {
		currentstate = event->type == GDK_KEY_PRESS;
		if (tmo)
			gtk_timeout_remove(tmo);
		if (currentstate != laststate)
			tmo = gtk_timeout_add(100, pttkeyfunc, NULL);
		return TRUE;
	}
	printf("Mainwindow key%s: time %u state %u keyval %u len %d\n",
	       event->type == GDK_KEY_PRESS ? "press" : "release",
	       event->time, event->state, event->keyval, event->length);
	return FALSE;
}

void on_mainptt_toggled(GtkToggleButton *togglebutton, gpointer user_data)
{
	GtkToggleButton *pttb;
	unsigned int ptts;

	pttb = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(mainwindow), "buttonptt"));
	ptts = gtk_toggle_button_get_active(pttb);
	printf("Toggle button active: %d\n", ptts);
	ptt = (ptt & ~1) | (ptts & 1);
	audio_ptt(ptt);
	audio_setsquelch(squelch);
}

void on_maindtmf_clicked(GtkButton *button, gpointer user_data)
{
	if (GTK_WIDGET_VISIBLE(dtmfwindow))
		gtk_widget_hide(dtmfwindow);
	else
		gtk_widget_show(dtmfwindow);
}

void on_mainscope_clicked(GtkButton *button, gpointer user_data)
{
	if (GTK_WIDGET_VISIBLE(scopewindow))
		gtk_widget_hide(scopewindow);
	else
		gtk_widget_show(scopewindow);
}

void on_mainspectrum_clicked(GtkButton *button, gpointer user_data)
{
	if (GTK_WIDGET_VISIBLE(spectrumwindow))
		gtk_widget_hide(spectrumwindow);
	else
		gtk_widget_show(spectrumwindow);
}

void on_aboutok_clicked(GtkButton *button, gpointer user_data)
{
	gtk_widget_hide(aboutdialog);
}

gboolean on_aboutdialog_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(aboutdialog);
	return TRUE;
}

gboolean on_dtmfwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(dtmfwindow);
	return TRUE;
}

gboolean on_scopewindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(scopewindow);
	return TRUE;
}


gboolean on_spectrumwindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
	gtk_widget_hide(spectrumwindow);
	return TRUE;
}

void on_buttonsquelch_clicked(GtkButton *button, gpointer user_data)
{
	GtkWidget *sqbl;
	
	squelch++;
	if (squelch > 1)
		squelch = 0;
	audio_setsquelch(squelch);
	/* set label text */
	sqbl = GTK_BIN(gtk_object_get_data(GTK_OBJECT(mainwindow), "buttonsquelch"))->child;
	gtk_label_set_text(GTK_LABEL(sqbl), squelch ? _("Squelch on") : _("Squelch off") );	
}

void on_button1750_pressed(GtkButton *button, gpointer user_data)
{
	ptt |= 4;
	audio_ptt(ptt);
	audio_1750(1);
	audio_setsquelch(squelch);
}


void on_button1750_released(GtkButton *button, gpointer user_data)
{
	ptt &= ~4;
	audio_ptt(ptt);
	audio_1750(0);
	audio_setsquelch(squelch);
}

int main(int argc, char *argv[])
{
        static const struct option long_options[] = {
#ifdef HAVE_PPUSER
                { "ppuser", 1, 0, 0x400 },
                { "ppdev", 1, 0, 0x402 },
#endif
#ifdef HAVE_PPKDRV
                { "ppkdrv", 1, 0, 0x401 },
#endif
#ifdef WIN32
                { "ppgenport", 0, 0, 0x403 },
                { "ppwin", 1, 0, 0x404 },
                { "pplpt", 1, 0, 0x404 },
                { "ppring0", 0, 0, 0x405 },
#endif
		{ "ppforcehwepp", 0, 0, 0x410 },
		{ "ppswemulepp", 0, 0, 0x411 },
		{ "ppswemulecp", 0, 0, 0x412 },
		{ 0, 0, 0, 0 }
        };
        int c, err = 0;
        unsigned int iobase = 0x378, ntddkgenport = 0, ntdrv = 0, w9xring0 = 0, ppflags = 0;
	const char *snd = NULL;
	const char *ppuser = NULL, *ppkdrv = NULL, *ppdev = NULL;

        printf("EPP virtual transceiver  (c) 1998-2000 by Thomas Sailer, HB9JNX/AE4WA\n");
	bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
	textdomain(PACKAGE);

	gtk_set_locale();
	gtk_init(&argc, &argv);

	add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps");
	add_pixmap_directory(PACKAGE_SOURCE_DIR "/pixmaps");

        while ((c = getopt_long(argc, argv, "svp:m:a:", long_options, NULL)) != EOF) {
                switch (c) {
		case 0x400:
			ppuser = optarg;
			ppkdrv = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 0;
			break;

		case 0x401:
			ppkdrv = optarg;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 0;
			break;

		case 0x402:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = optarg;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 0;
			break;

		case 0x403:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 1;
                        ntdrv = 0;
                        w9xring0 = 0;
                        break;

		case 0x404:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = strtoul(optarg, NULL, 0);
                        w9xring0 = 0;
			break;

		case 0x405:
			ppkdrv = NULL;
			ppuser = NULL;
			ppdev = NULL;
			ntddkgenport = 0;
                        ntdrv = 0;
                        w9xring0 = 1;
			break;

		case 0x410:
			ppflags |= PPFLAG_FORCEHWEPP;
			break;

		case 0x411:
			ppflags |= PPFLAG_SWEMULEPP;
			break;

		case 0x412:
			ppflags |= PPFLAG_SWEMULECP;
			break;

		case 'a':
			snd = optarg;
			break;

                case 'p': 
                        iobase = strtoul(optarg, NULL, 0);
                        if (iobase <= 0 || iobase >= 0x3f8)
                                err++;
                        break;

                case 'm':
                        parseconfig(&cfg, optarg);
                        break;

                case 'v':
                        verboselevel++;
                        break;

#if defined(HAVE_SYSLOG) && defined(HAVE_VSYSLOG)
                case 's':
                        if (syslogmsg)
                                break;
                        openlog("eppfpga", LOG_PID, LOG_USER);
                        syslogmsg = 1;
                        break;
#endif

                default:
                        err++;
                        break;
                }
        }
        if (err) {
                g_message("usage: %s [-v] [-p <portaddr>] [-m <modestr>]\n", argv[0]);
                exit(1);
        }
	if (audio_drvinit(snd)) {
                g_error("Sound Initialisation error\n");
                exit(1);
	}
#ifdef HAVE_PPUSER
	if (ppkdrv) {
		if (parport_init_ppkdrv(ppkdrv)) {
			fprintf(stderr, "no kernel interface %s driver found\n", ppkdrv);
			exit(1);
		}
	} else
#endif
#ifdef HAVE_PPUSER
		if (ppdev) {
			if (parport_init_ppdev(ppdev)) {
				fprintf(stderr, "no ppdev driver found at %s\n", ppdev);
				exit(1);
			}
		} else if (ppuser) {
			if (parport_init_ppuser(ppuser)) {
				fprintf(stderr, "no ppuser driver found at %s\n", ppuser);
				exit(1);
			}
		} else
#endif
#ifdef WIN32
                        if (ntdrv) {
                                if (parport_init_win_flags(ntdrv-1, ppflags)) {
                                        fprintf(stderr, "no eppflex.sys/vxd driver found\n");
                                        exit(1);
                                }
                        } else if (ntddkgenport) {
                                if (parport_init_ntddkgenport()) {
                                        fprintf(stderr, "no NTDDK genport.sys driver found\n");
                                        exit(1);
                                }
                        } else if (w9xring0) {
                                if (parport_init_w9xring0_flags(iobase, ppflags)) {
                                        fprintf(stderr, "no parport found at 0x%x\n", iobase);
                                        exit(1);
                                }
                        } else
#endif
                                if (parport_init_direct_flags(iobase, ppflags)) {
                                        g_error("no parport found at 0x%x\n", iobase);
                                        exit(1);
                                }
	/*
	 * The following code was added by Glade to create one of each component
	 * (except popup menus), just so that you see something after building
	 * the project. Delete any components that you don't want shown initially.
	 */
	aboutdialog = create_aboutdialog();
	//ioconfig = create_ioconfiglinux();
	mainwindow = create_mainwindow();
	aboutdialog = create_aboutdialog();
	dtmfwindow = create_dtmfwindow();
	scopewindow = create_scopewindow();
	spectrumwindow = create_spectrumwindow();
	gtk_widget_show(mainwindow);
	audio_ptt(ptt);
	audio_setsquelch(squelch);
	gtk_main();
	reset_modem();
	return 0;
}
