/*
 * UAE - the Un*x Amiga Emulator
 *
 * Yet Another User Interface for the X11 version
 *
 * Copyright 1997 Bernd Schmidt
 * 
 * The Tk GUI doesn't work.
 * The X Forms Library isn't available as source, and there aren't any
 * binaries compiled against glibc
 *
 * So let's try this...
 */

#include "sysconfig.h"
#include "sysdeps.h"

#include "config.h"
#include "options.h"
#include "uae.h"
#include "memory.h"
#include "custom.h"
#include "readcpu.h"
#include "gui.h"
#include "newcpu.h"
#include "threaddep/penguin.h"

#include <gtk/gtk.h>

static GtkWidget *disk_insert_widget[4], *disk_eject_widget[4], *disk_text_widget[4];
static char *led_bufs[5];
static int gcs_initialized = 0;

static char *disk_string[4];
static char *new_disk_string[4];

static GtkWidget *led_widgets[5];

static int nr_for_led (GtkWidget *led)
{
    int i;
    i = 0;
    while (led_widgets[i] != led)
	i++;
    return i;
}

static smp_comm_pipe to_gui_pipe, from_gui_pipe;
static uae_sem_t gui_sem, gui_quit_sem;

static volatile int quit_gui = 0, quitted_gui = 0;

static void enable_disk_buttons (int enable);

static unsigned int prevledstate;

static void draw_led (int nr)
{
    GtkWidget *thing = led_widgets[nr];
    int r = 0, g = 0, b = 0;
    int i, j, k;
    char *buf = led_bufs[nr];
    
    if (buf == 0)
	return;
    if (gui_ledstate & (1 << nr)) {
	if (nr == 4)
	    r = 0xCC;
	else
	    r = 0x88, g = 0xFF;
    }
    printf ("%dx%d\n", thing->allocation.width, thing->allocation.height);

    for (j = k = 0; j < thing->allocation.width; j++)
	buf[k++] = r, buf[k++] = g, buf[k++] = b;
    for (i = 0; i < thing->allocation.height; i++) {
	gtk_preview_draw_row (GTK_PREVIEW (thing), buf, 0, i, thing->allocation.width);
    }
    gtk_widget_draw (thing, 0);
}

static int my_idle (void)
{
    unsigned int leds = gui_ledstate;
    int i;

    /*printf("...\n");*/
    if (quit_gui) {
	printf("Foo...\n");
	gtk_main_quit ();
	goto out;
    }
    while (comm_pipe_has_data (&to_gui_pipe)) {
	int cmd = read_comm_pipe_int_blocking (&to_gui_pipe);
	int n;
	/*printf ("cmd %d\n", cmd);*/
	switch (cmd) {
	 case 0:
	    n = read_comm_pipe_int_blocking (&to_gui_pipe);
	    gtk_label_set (GTK_LABEL (disk_text_widget[n]), currprefs.df[n]);
	    break;
	}
    }
    
    for (i = 0; i < 5; i++) {
	unsigned int mask = 1 << i;
	GtkWidget *thing;
	int on = leds & mask;

	if (on == (prevledstate & mask))
	    continue;

	printf(": %d %d\n", i, on);
	draw_led (i);
    }
    prevledstate = leds;
out:
    return 1;
}

static void did_reset (void)
{
    if (quit_gui)
	return;
    
    write_comm_pipe_int (&from_gui_pipe, 2, 1);
}

static void did_debug (void)
{
    if (quit_gui)
	return;
    
    write_comm_pipe_int (&from_gui_pipe, 3, 1);
}

static void did_quit (void)
{
    if (quit_gui)
	return;
    
    write_comm_pipe_int (&from_gui_pipe, 4, 1);
}

static void did_eject (int n)
{ 
    if (quit_gui)
	return;
    
    write_comm_pipe_int (&from_gui_pipe, 0, 0);
    write_comm_pipe_int (&from_gui_pipe, n, 1);
}

static int filesel_active = -1;
static GtkWidget *selector;

static void did_close_insert (GtkObject *o, GtkWidget *w)
{
    filesel_active = -1;
    enable_disk_buttons (1);
}

static void did_cancel_insert (GtkObject *o)
{
    did_close_insert (o, GTK_WIDGET (o));
    gtk_widget_destroy (GTK_WIDGET (o));
}

static void did_insert_select (GtkObject *o)
{
    char *s = gtk_file_selection_get_filename (GTK_FILE_SELECTION (selector));
    
    if (quit_gui)
	return;
    
    uae_sem_wait (&gui_sem);
    if (new_disk_string[filesel_active] != 0)
	free (new_disk_string[filesel_active]);
    new_disk_string[filesel_active] = strdup (s);
    uae_sem_post (&gui_sem);
    write_comm_pipe_int (&from_gui_pipe, 1, 0);
    write_comm_pipe_int (&from_gui_pipe, filesel_active, 1);
    did_cancel_insert (o);
}

static void did_insert (int n)
{
    char buffer[100];

    if (filesel_active != -1)
	return;
    filesel_active = n;
    enable_disk_buttons (0);

    sprintf (buffer, "Select a disk image file for DF%d", n);
    selector = gtk_file_selection_new (buffer);
    gtk_signal_connect (GTK_OBJECT (selector), "destroy",
			(GtkSignalFunc) did_close_insert, selector);

    gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (selector)->ok_button),
			       "clicked", (GtkSignalFunc) did_insert_select,
			       GTK_OBJECT (selector));
    gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (selector)->cancel_button),
			       "clicked", (GtkSignalFunc) did_cancel_insert,
			       GTK_OBJECT (selector));

    printf("%p\n", selector);
    gtk_widget_show (selector);
}

static void did_eject_0 (void) { did_eject (0); }
static void did_eject_1 (void) { did_eject (1); }
static void did_eject_2 (void) { did_eject (2); }
static void did_eject_3 (void) { did_eject (3); }

static void did_insert_0 (void) { did_insert (0); }
static void did_insert_1 (void) { did_insert (1); }
static void did_insert_2 (void) { did_insert (2); }
static void did_insert_3 (void) { did_insert (3); }

static void enable_disk_buttons (int enable)
{
    int i;
    for (i = 0; i < 4; i++) {
	gtk_widget_set_sensitive (disk_insert_widget[i], enable);
	gtk_widget_set_sensitive (disk_eject_widget[i], enable);
    }
}

static gint driveled_event (GtkWidget *thing, GdkEvent *event)
{
    gint x, y;
    GtkStyle *style;
    int lednr = nr_for_led (thing);

    switch (event->type) {
     case GDK_MAP:
	draw_led (lednr);
	break;
     case GDK_EXPOSE:
	if (led_bufs[lednr] == 0) {
	    printf ("- %d\n", thing->allocation.width);
	    led_bufs[lednr] = (char *)xmalloc (3 * thing->allocation.width);
	    draw_led (lednr);
	}
	break;
     default:
	break;
    }

  return 0;
}

static GtkWidget *make_led (int nr)
{
    GtkWidget *subframe, *the_led, *thing;
    
    the_led = gtk_vbox_new (FALSE, 0);
    gtk_widget_set_usize (the_led, 20, -1);
    gtk_widget_show (the_led);

    thing = gtk_preview_new (GTK_PREVIEW_COLOR);
    gtk_box_pack_start (GTK_BOX (the_led), thing, TRUE, TRUE, 0);
    gtk_widget_show (thing);

    subframe = gtk_frame_new (NULL);
    gtk_box_pack_start (GTK_BOX (the_led), subframe, TRUE, TRUE, 0);
    gtk_widget_show (subframe);
    thing = gtk_preview_new (GTK_PREVIEW_COLOR);
    gtk_container_add (GTK_CONTAINER (subframe), thing);
    led_widgets[nr] = thing;
    gtk_signal_connect (GTK_OBJECT (thing), "event",
			(GtkSignalFunc) driveled_event, (gpointer) thing);
    gtk_widget_show (thing);

    thing = gtk_preview_new (GTK_PREVIEW_COLOR);
    gtk_box_pack_start (GTK_BOX (the_led), thing, TRUE, TRUE, 0);
    gtk_widget_show (thing);
    
    return the_led;
}

static void *gtk_penguin (void *dummy)
{
    GtkWidget *window;
    GtkWidget *buttonbox, *vbox;
    GtkWidget *thing;

    int i;

    int argc = 1;
    char *a[] = {"UAE"};
    char **argv = a;

    gtk_init (&argc, &argv);
    gtk_rc_parse ("uaegtkrc");

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_name (window, "UAE control");

    led_bufs[0] = led_bufs[1] = led_bufs[2] = led_bufs[3] = led_bufs[4] = 0;

    vbox = gtk_vbox_new (FALSE, 4);
    gtk_container_add (GTK_CONTAINER (window), vbox);

    /* Make a box with the Reset/Debug/Quit buttons and place it at the top
     * of our vbox.  */
    buttonbox = gtk_hbox_new (FALSE, 4);
    thing = gtk_button_new_with_label ("Reset");
    gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_reset, NULL);
    gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
    gtk_widget_show (thing);
    thing = gtk_button_new_with_label ("Debug");
    gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_debug, NULL);
    gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
    gtk_widget_show (thing);
    thing = gtk_button_new_with_label ("Quit");
    gtk_signal_connect (GTK_OBJECT (thing), "clicked", (GtkSignalFunc) did_quit, NULL);
    gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
    gtk_widget_show (thing);
    thing = make_led (4);
    gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
    gtk_widget_show (thing);
    gtk_box_pack_start (GTK_BOX (vbox), buttonbox, FALSE, TRUE, 0);
    gtk_widget_show (buttonbox);

    /* Place a separator below those three buttons.  */
    thing = gtk_hseparator_new ();
    gtk_box_pack_start (GTK_BOX (vbox), thing, FALSE, TRUE, 0);
    gtk_widget_show (thing);

    /* Now, the floppy disk control.  */
    for (i = 0; i < 4; i++) {
	GtkWidget *subthing, *subframe;
	char buf[5];
	sprintf (buf, "DF%d:", i);

	/* Each line: a frame with a hbox in it. The hbox contains
	 * the LED, the name of the drive and the diskfile in it, an
	 * Insert button, and an Eject button.  */
	buttonbox = gtk_frame_new (buf);
	thing = gtk_hbox_new (FALSE, 4);
	gtk_container_add (GTK_CONTAINER (buttonbox), thing);
        gtk_box_pack_start (GTK_BOX (vbox), buttonbox, FALSE, TRUE, 0);
	gtk_widget_show (buttonbox);
	gtk_widget_show (thing);
	buttonbox = thing;

	subthing = make_led (i);
	gtk_box_pack_start (GTK_BOX (buttonbox), subthing, FALSE, TRUE, 0);

	/* Make the "DF0:xxx" label.  */
	subframe = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (subframe), GTK_SHADOW_ETCHED_OUT);
	gtk_box_pack_start (GTK_BOX (buttonbox), subframe, FALSE, TRUE, 0);
	gtk_widget_show (subframe);

	subthing = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (subframe), subthing);
	gtk_widget_show (subthing);

	/* First, an invisible preview widget to set the horizontal size.  */
	thing = gtk_preview_new (GTK_PREVIEW_COLOR);
	gtk_widget_set_usize (thing, gdk_string_measure (subframe->style->font, "This is a very long name for a disk file, should be enough") + 7, 0);
	gtk_widget_show (thing);
	gtk_box_pack_start (GTK_BOX (subthing), thing, FALSE, TRUE, 0);

	/* Then, a label with the filename.  */
	thing = gtk_label_new ("frebnisia");
	disk_text_widget[i] = thing;
	gtk_widget_show (thing);
	gtk_box_pack_start (GTK_BOX (subthing), thing, FALSE, TRUE, 0);
	
	/* Now, the buttons.  */
	thing = gtk_button_new_with_label ("Eject");
	gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
	gtk_widget_show (thing);
	disk_eject_widget[i] = thing;
	gtk_signal_connect (GTK_OBJECT (thing), "clicked",
			    (GtkSignalFunc) (i == 0 ? did_eject_0 
					     : i == 1 ? did_eject_1 
					     : i == 2 ? did_eject_2 : did_eject_3),
			    NULL);

	thing = gtk_button_new_with_label ("Insert");
	gtk_box_pack_start (GTK_BOX (buttonbox), thing, FALSE, TRUE, 0);
	gtk_widget_show (thing);
	disk_insert_widget[i] = thing;
	gtk_signal_connect (GTK_OBJECT (thing), "clicked",
			    (GtkSignalFunc) (i == 0 ? did_insert_0 
					     : i == 1 ? did_insert_1 
					     : i == 2 ? did_insert_2 : did_insert_3),
			    NULL);
    }

    enable_disk_buttons (1);

    gtk_widget_show (vbox);
    gtk_widget_show (window);

    gtk_timeout_add (1000, (GtkFunction)my_idle, 0);
    gtk_main ();
    
    quitted_gui = 1;
    uae_sem_post (&gui_quit_sem);
    return 0;
}

void gui_changesettings(void)
{
    
}

int gui_init(void)
{
    penguin_id tid;

    init_comm_pipe (&to_gui_pipe, 20, 1);
    init_comm_pipe (&from_gui_pipe, 20, 1);
    uae_sem_init (&gui_sem, 0, 1);
    uae_sem_init (&gui_quit_sem, 0, 0);
    start_penguin (gtk_penguin, NULL, &tid);
    return 1;
}

int gui_update(void)
{
    return 0;
}

void gui_exit(void)
{
    quit_gui = 1;
    uae_sem_wait (&gui_quit_sem);
}

void gui_led(int num, int on)
{
/*    if (num == 0)
	return;
    printf("LED %d %d\n", num, on);
    write_comm_pipe_int (&to_gui_pipe, 1, 0);
    write_comm_pipe_int (&to_gui_pipe, num == 0 ? 4 : num - 1, 0);
    write_comm_pipe_int (&to_gui_pipe, on, 1);
    printf("#LED %d %d\n", num, on);
   */ 
}

void gui_filename(int num, const char *name)
{
    write_comm_pipe_int (&to_gui_pipe, 0, 0);
    write_comm_pipe_int (&to_gui_pipe, num, 1);
    
    gui_update ();
}

void gui_handle_events(void)
{
    while (comm_pipe_has_data (&from_gui_pipe)) {
	int cmd = read_comm_pipe_int_blocking (&from_gui_pipe);
	int n;
	switch (cmd) {
	 case 0:
	    n = read_comm_pipe_int_blocking (&from_gui_pipe);
	    changed_prefs.df[n][0] = '\0';
	    break;
	 case 1:
	    n = read_comm_pipe_int_blocking (&from_gui_pipe);
	    uae_sem_wait (&gui_sem);
	    strncpy (changed_prefs.df[n], new_disk_string[n], 255);
	    changed_prefs.df[n][255] = '\0';
	    uae_sem_post (&gui_sem);
	    break;
	 case 2:
	    uae_reset ();
	    break;
	 case 3:
	    activate_debugger ();
	    break;
	 case 4:
	    uae_quit ();
	    break;
	}
    }
    
}
