/*  Tilem, TI-Linux Emulator
 *  Copyright (C) 2001 Solignac Julien <x1cygnus@xcalc.org>
 *  Portions copyright (C) 2004 Benjamin Moody <benjamin@ecg.mit.edu>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "../../../config.h"

#include<gtk/gtk.h>
#ifndef __WIN32__
# include<pthread.h>
# include<unistd.h>
#else
# include<io.h>
#endif
#include<string.h>
#include<stdlib.h>
#include<stdio.h>

/* >>> dependencies */
#include "../core/Z80.h"
/* dependencies <<< */


#include "changehw.h"
/* >>> Imported */
#include "screen.h"
#include "files.h"
#include "../main.h"
#include "../tools.h"
#include "commands.h"
#include "../symbols.h"
#include "../core/dep/inter.h"
/* Imported <<<*/


/* >>> Static */
static void gui_changehw(GtkWidget *dlg)
{
	extern struct hwmodel hwmodels[nummodels];
	extern char *romfile, *savfile;

	const char *text;
	byte i;
	char calcname[16], romname[256];
	char *p;

	text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(gtk_object_get_user_data(GTK_OBJECT(dlg))));
	if (!text)
		return;

	strncpy(calcname, text, 16);
	if ((p = strchr(calcname, '(')))
		*(p-1) = 0;
	p = strchr(text, '(');

	if (romfile) {
		free(romfile);
		romfile = NULL;
	}
	if (savfile) {
		free(savfile);
		savfile = NULL;
	}

	for (i = 0; i < nummodels; i++) {
		if (!(strcmp(calcname, hwmodels[i].name))) {
			if (p) {
				sprintf(romname, "%s%c%s", hwmodels[i].direct,
					G_DIR_SEPARATOR, p+1);
				romname[strlen(romname)-1] = 0;
				p = g_filename_from_utf8(romname, -1, NULL,
							 NULL, NULL);

				romfile = ahome(p);
				strcpy(strrchr(p, '.'), ".sav");
				savfile = ahome(p);
				g_free(p);
			}

			switchhw(i, NULL);
			gtk_widget_destroy(dlg);
			return;
		}
	}

	fprintf(stderr,"No calculator selected.\n");
	exit(1);
}
/* Static <<< */


/* >>> Exported */
void switchhw(byte modelcode, GtkWidget *set_screen)
{
	extern struct hwmodel hwmodels[nummodels];
	extern byte iskeyb, autosave, savecode;
	extern struct hardware *hw;
	G_LOCK_EXTERN(running);
	G_LOCK_EXTERN(runctrl);

	static GtkWidget *Screen = NULL;

/* despise global variables */
	if (modelcode == 0x88) {
		Screen = set_screen;
		return;
	}

	/* if (hw == hwmodels[modelcode].hx) return; */

	G_LOCK(running);
	G_LOCK(runctrl);
	savecode = autosave;
	cleanmem();

	hw = hwmodels[modelcode].hx;
	clearsymbols();

	if (!initmem())
		exit(-1);
	Z80_Reset();

	if (Screen) {
		gtk_timeout_remove((guint) gtk_object_get_user_data(GTK_OBJECT(Screen)));
		gtk_signal_disconnect_by_func(GTK_OBJECT(Screen), GTK_SIGNAL_FUNC(exit_emulator), (gpointer) -1);
		gtk_widget_destroy(Screen);
	}

	create_Screen(iskeyb);

	Rezet(1);
	G_UNLOCK(runctrl);
	G_UNLOCK(running);
}

void add_rom(char *fname, gpointer data)
{
	extern struct hwmodel hwmodels[nummodels];
	FILE *rfile, *newfile;
	char *newfilename;
	char *s;
	unsigned long len, count;
	int i;
	char romname[256];

	GtkWidget *selector;

	if (!(rfile = fopen(fname, "rb"))) {
		g_message("unable to open %s", fname);
		return;
	}

	fseek(rfile, 0L, SEEK_END);
	len = ftell(rfile);
	fclose(rfile);

	for (i = 0; i < nummodels; i++)
		if (hwmodels[i].hx->romsize <= len
		    && (hwmodels[i].hx->romsize * 2) > len
		    && ((hwmodels[i].hx->xcheckrom)(fname)))
			break;

	if (i < nummodels) {
		if (!(rfile = fopen(fname, "rb"))) {
			g_message("unable to open %s", fname);
			return;
		}

		if ((s = strrchr(fname, G_DIR_SEPARATOR)))
			s++;
		else
			s = fname;
		snprintf(romname, 256, "%s%c%s", hwmodels[i].direct,
			 G_DIR_SEPARATOR, s);
		newfilename = ahome(romname);
		if (!(newfile = fopen(newfilename, "wb"))) {
			g_message("unable to open %s", newfilename);
			free(newfilename);
			fclose(rfile);
			return;
		}

		fseek(rfile, 0L, SEEK_SET);

		for (count = 0; count < (hwmodels[i].hx->romsize)/256; count++) {
			fread(romname, 256, 1, rfile);
			fwrite(romname, 256, 1, newfile);
		}

		fclose(newfile);
		fclose(rfile);

		selector = gtk_object_get_user_data(GTK_OBJECT(data));

		s = g_filename_to_utf8(s, -1, NULL, NULL, NULL);
		snprintf((char*)romname, 256, "%s (%s)", hwmodels[i].name, s);
		gtk_combo_box_append_text(GTK_COMBO_BOX(selector),
					  (char*)romname);
		g_free(s);

		free(newfilename);
	}
	else
		g_message("Unknown ROM size (%lu)", len);
}

void changehw(void)
{
	extern struct hwmodel hwmodels[nummodels];

	byte i, fname[7];
	GtkWidget *dlg;
	char *filen;
	GDir *gdir;

	GtkWidget *vis, *frame, *selector, *dialog_aa, *bbox,
		*button1, *button2, *button3, *vbox;

	resetkeyb();

	dlg = gtk_dialog_new();
		gtk_window_set_title(GTK_WINDOW(dlg), "Emulated Calculator");
		gtk_window_set_modal(GTK_WINDOW(dlg), TRUE);

	button1 = gtk_button_new_with_label("Import ROM...");
	gtk_widget_show(button1);

	button2 = gtk_button_new_with_label("Ok");
	gtk_widget_show(button2);

	button3 = gtk_button_new_with_label("Cancel");
	gtk_widget_show(button3);

	bbox = gtk_hbutton_box_new();
		gtk_container_add(GTK_CONTAINER(bbox), button2);
		gtk_container_add(GTK_CONTAINER(bbox), button3);
	gtk_widget_show(bbox);

	dialog_aa = GTK_DIALOG(dlg)->action_area;
		gtk_container_set_border_width(GTK_CONTAINER(dialog_aa), 10);
		gtk_box_pack_start(GTK_BOX(dialog_aa), bbox, TRUE, TRUE, 0);
	gtk_widget_show(dialog_aa);

	selector = gtk_combo_box_new_text();
		gtk_container_set_border_width(GTK_CONTAINER(selector), 5);

		for (i = 0; i < nummodels; i++) {
			snprintf((char*)fname, 7, "x%c.rom", hwmodels[i].hx->model);
			
			filen = ahome((char*)fname);
			if (!(access(filen, R_OK)))
				gtk_combo_box_append_text(GTK_COMBO_BOX(selector),
							  hwmodels[i].name);
			free(filen);

			filen = ahome(hwmodels[i].direct);
			gdir = g_dir_open(filen, 0, NULL);
			free(filen);
			while (gdir && (filen = next_rom_file(gdir))
			       && (filen = g_filename_to_utf8(filen, -1, NULL,
							      NULL, NULL))) {
				snprintf((char*)fname, 256, "%s (%s)",
					 hwmodels[i].name, filen);
				gtk_combo_box_append_text(GTK_COMBO_BOX(selector),
							  (char*)fname);
				g_free(filen);
			}
		}
	gtk_widget_show(selector);

	vbox = gtk_vbox_new(FALSE, 5);
		gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
		gtk_box_pack_start(GTK_BOX(vbox), selector, TRUE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(vbox), button1, TRUE, FALSE, 0);
	gtk_widget_show(vbox);

	frame = gtk_frame_new("Pick calculator");
		gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
		gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_widget_show(frame);

	vis = GTK_DIALOG(dlg)->vbox;
		gtk_box_pack_start(GTK_BOX(vis), frame, TRUE, TRUE, 0);
	gtk_widget_show(vis);

		gtk_signal_connect_object(GTK_OBJECT(button1), "clicked", GTK_SIGNAL_FUNC(create_romdlg), GTK_OBJECT(dlg));
		gtk_signal_connect_object(GTK_OBJECT(button2), "clicked", GTK_SIGNAL_FUNC(gui_changehw), GTK_OBJECT(dlg));
		gtk_signal_connect_object(GTK_OBJECT(button3), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dlg));
		gtk_signal_connect_object(GTK_OBJECT(dlg), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dlg));
		gtk_widget_grab_focus(dlg);
		gtk_object_set_user_data(GTK_OBJECT(dlg), (gpointer) selector);
	gtk_widget_show(dlg);
}
/* Exported <<< */
