#include "wx-utils.h"
#include "wx-sdl2.h"
#include "wx-joystickconfig.h"

#include "ibm.h"
#include "ide.h"
#include "cpu.h"
#include "device.h"
#include "fdd.h"
#include "gameport.h"
#include "hdd.h"
#include "lpt.h"
#include "model.h"
#include "mouse.h"
#include "mem.h"
#include "nethandler.h"
#include "nvr.h"
#include "scsi_cd.h"
#include "sound.h"
#include "video.h"
#include "vid_voodoo.h"
#include "wx-config-eventbinder.h"

#include "minivhd/minivhd.h"

//#define MAX_CYLINDERS ((((1 << 28)-1) / 16) / 63)
#define MAX_CYLINDERS 265264 /*Award 430VX won't POST with a larger drive*/
extern int pause;

extern int is486;
static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX],
	modeltolist[ROM_MAX];
static int settings_sound_to_list[20], settings_list_to_sound[20];
static int settings_mouse_to_list[20], settings_list_to_mouse[20];
#ifdef USE_NETWORKING
static int settings_network_to_list[20], settings_list_to_network[20];
#endif
static char *hdd_names[16];
static void *eventBinder;

int has_been_inited = 0;

static int hd_changed = 0;

static char hd_new_name[512];
static int hd_new_spt, hd_new_hpc, hd_new_cyl;
static int hd_new_type;
static int new_cdrom_channel;
static int new_zip_channel;

extern int pause;

static int memspin_old;

extern void deviceconfig_open(void *hwnd, device_t *device);
extern int hdconf_init(void *hdlg);
extern int hdconf_update(void *hdlg);

static int hdd_controller_selected_is_ide(void *hdlg);
static int hdd_controller_selected_is_scsi(void *hdlg);
static int hdd_controller_selected_has_config(void *hdlg);
static device_t *hdd_controller_selected_get_device(void *hdlg);

static int mouse_valid(int type, int model) {
	if (((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_PS2)
		&& !(models[model]->flags & MODEL_PS2))
		return 0;
	if (((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_AMSTRAD)
		&& !(models[model]->flags & MODEL_AMSTRAD))
		return 0;
	if (((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_OLIM24)
		&& !(models[model]->flags & MODEL_OLIM24))
		return 0;
	return 1;
}

/*static int mpu401_available(int sound_card)
{
        char* name = sound_card_get_internal_name(sound_card);
        if (name && (!strcmp(name, "sb16") || !strcmp(name, "sbawe32")))
                return TRUE;

        return FALSE;
}*/

static void recalc_fpu_list(void *hdlg, int model, int manu, int cpu, int fpu) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU"));
	int c = 0;

	wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
	wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);

	while (1) {
		const char *name = fpu_get_name_from_index(model, manu, cpu, c);
		int type = fpu_get_type_from_index(model, manu, cpu, c);
		if (!name)
			break;

		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)name);
		if (!c || type == fpu)
			wx_sendmessage(h, WX_CB_SETCURSEL, c, 0);

		c++;
	}
	if (c > 1)
		wx_enablewindow(h, TRUE);
	else
		wx_enablewindow(h, FALSE);
}

static void recalc_vid_list(void *hdlg, int model, int force_builtin_video) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID"));
	int c = 0, d = 0;
	int found_card = 0;
	int cur_gfxcard = gfxcard;
	int romset = model_getromset_from_model(model);

	wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
	wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);

	if (model_has_fixed_gfx(model)) {
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Built-in video");
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
		wx_enablewindow(h, FALSE);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID"));
		wx_enablewindow(h, video_card_has_config(gfxcard, romset));
		return;
	}

	if (model_has_optional_gfx(model)) {
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Built-in video");
		if (gfxcard == GFX_BUILTIN || force_builtin_video) {
			wx_sendmessage(h, WX_CB_SETCURSEL, d, 0);
			found_card = 1;
			cur_gfxcard = GFX_BUILTIN;
		}
		d++;
	}

	if (cur_gfxcard == GFX_BUILTIN && !model_has_fixed_gfx(model) && !model_has_optional_gfx(model))
		cur_gfxcard = 0;

	while (1) {
		char *s = video_card_getname(c);

		if (!s[0])
			break;

		if (video_card_available(c) && gfx_present[video_new_to_old(c)] &&
			((models[model]->flags & MODEL_PCI) || !(video_card_getdevice(c, romset)->flags & DEVICE_PCI)) &&
			((models[model]->flags & MODEL_MCA) || !(video_card_getdevice(c, romset)->flags & DEVICE_MCA)) &&
			(!(models[model]->flags & MODEL_MCA) || (video_card_getdevice(c, romset)->flags & DEVICE_MCA))
			) {
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
			if (video_new_to_old(c) == gfxcard && !found_card) {
				wx_sendmessage(h, WX_CB_SETCURSEL, d, 0);
				found_card = 1;
			}

			d++;
		}

		c++;
	}
	if (!found_card)
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
	wx_enablewindow(h, TRUE);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID"));
	if (video_card_has_config(video_old_to_new(cur_gfxcard), romset))
		wx_enablewindow(h, TRUE);
	else
		wx_enablewindow(h, FALSE);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKVOODOO"));
	wx_enablewindow(h, (models[model]->flags & MODEL_PCI) ? TRUE : FALSE);
	h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVOODOO"));
	wx_enablewindow(h, (models[model]->flags & MODEL_PCI) ? TRUE : FALSE);
}

static void recalc_snd_list(void *hdlg, int model) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND"));
	int c = 0, d = 0;

	wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);

	while (1) {
		char *s = sound_card_getname(c);

		if (!s[0])
			break;

		settings_sound_to_list[c] = d;

		if (sound_card_available(c)) {
			device_t *sound_dev = sound_card_getdevice(c);

			if (!sound_dev || (sound_dev->flags & DEVICE_MCA) == (models[model]->flags & MODEL_MCA)) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
				settings_list_to_sound[d] = c;
				d++;
			}
		}

		c++;
	}
	wx_sendmessage(h, WX_CB_SETCURSEL, settings_sound_to_list[sound_card_current], 0);
}

static void recalc_hdd_list(void *hdlg, int model, int use_selected_hdd, int force_ide) {
	void *h;
	char *s;
	int valid = 0;
	char old_name[16];
	int c, d;
	int hdd_type;

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));

	if (force_ide)
		strcpy(old_name, "ide");
	else if (use_selected_hdd) {
		c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

		if (c != -1 && hdd_names[c])
			strncpy(old_name, hdd_names[c], sizeof(old_name) - 1);
		else {
			if (models[model]->flags & MODEL_HAS_IDE)
				strcpy(old_name, "none");
			else
				strcpy(old_name, "ide");
		}
	} else
		strncpy(old_name, hdd_controller_name, sizeof(old_name) - 1);

	wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
	c = d = 0;
	while (1) {
		s = hdd_controller_get_name(c);
		if (s[0] == 0)
			break;
		if ((((hdd_controller_get_flags(c) & DEVICE_AT) && !(models[model]->flags & MODEL_AT)) ||
			(hdd_controller_get_flags(c) & DEVICE_MCA) != (models[model]->flags & MODEL_MCA)) && c) {
			c++;
			continue;
		}
		if ((((hdd_controller_get_flags(c) & DEVICE_PS1) && models[model]->id != ROM_IBMPS1_2011) ||
			(!(hdd_controller_get_flags(c) & DEVICE_PS1) && models[model]->id == ROM_IBMPS1_2011)) && c) {
			c++;
			continue;
		}
		if (!hdd_controller_available(c)) {
			c++;
			continue;
		}
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
		hdd_names[d] = hdd_controller_get_internal_name(c);

		if (!strcmp(old_name, hdd_names[d])) {
			wx_sendmessage(h, WX_CB_SETCURSEL, d, 0);
			valid = 1;
		}
		c++;
		d++;
	}

	if (!valid)
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);

	wx_enablewindow(h, TRUE);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREHDD"));
	if (hdd_controller_selected_has_config(hdlg))
		wx_enablewindow(h, TRUE);
	else
		wx_enablewindow(h, FALSE);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));
	hdd_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	h = wx_getdlgitem(hdlg, WX_ID("IDC_HDCBOOK"));

	while (wx_sendmessage(h, WX_CHB_GETPAGECOUNT, 0, 0))
		wx_sendmessage(h, WX_CHB_REMOVEPAGE, 0, 0);

	for (c = 0; c < 7; c++) {
		void *page;
		char s[80];

		sprintf(s, "IDC_HDPANEL[%i]", c);

		page = wx_getdlgitem(hdlg, WX_ID(s));
		wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0);
		wx_sendmessage(h, WX_CHB_ADDPAGE, (LONG_PARAM)page, (LONG_PARAM)"dummy name");
	}
	if (hdd_controller_is_scsi(hdd_names[hdd_type])) {
		for (c = 0; c < 7; c++) {
			void *page;
			char s[80];

			sprintf(s, "IDC_HDPANEL[%i]", c);
			page = wx_getdlgitem(hdlg, WX_ID(s));
			wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0);
			sprintf(s, "SCSI ID %i (%c:)", c, 'C' + c);
			wx_sendmessage(h, WX_CHB_SETPAGETEXT, c, (LONG_PARAM)s);
		}
	} else if (hdd_controller_is_ide(hdd_names[hdd_type])) {
		for (c = 0; c < 4; c++) {
			void *page;
			char s[80];

			sprintf(s, "IDC_HDPANEL[%i]", c);
			page = wx_getdlgitem(hdlg, WX_ID(s));
			wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0);
			sprintf(s, "Drive %i %s %s (%c:)", c, (c & 2) ? "Secondary" : "Primary", (c & 1) ? "Slave" : "Master", 'C' + c);
			wx_sendmessage(h, WX_CHB_SETPAGETEXT, c, (LONG_PARAM)s);
		}
		for (c = 6; c >= 4; c--) {
			wx_sendmessage(h, WX_CHB_REMOVEPAGE, c, 0);
		}
	} else {
		for (c = 0; c < 2; c++) {
			void *page;
			char s[80];

			sprintf(s, "IDC_HDPANEL[%i]", c);
			page = wx_getdlgitem(hdlg, WX_ID(s));
			wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0);
			sprintf(s, "Drive %i %s (%c:)", c, (c & 1) ? "Secondary" : "Primary", 'C' + c);
			wx_sendmessage(h, WX_CHB_SETPAGETEXT, c, (LONG_PARAM)s);
		}
		for (c = 6; c >= 2; c--) {
			wx_sendmessage(h, WX_CHB_REMOVEPAGE, c, 0);
		}
	}
}

// TODO: split this into model/speed recalcs?
static void recalc_cd_list(void *hdlg, int cur_speed, char *cur_model) {
	int temp_model = -1;
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL"));
	int c = 0;
	int found = 0;

	wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
	if (hdd_controller_selected_is_ide(hdlg) || hdd_controller_selected_is_scsi(hdlg))
		wx_enablewindow(h, TRUE);
	else
		wx_enablewindow(h, FALSE);
	while (c < MAX_CD_MODEL) {
		char s[40];
		char *model;

		if ((cd_get_model_interfaces(c) == CD_MODEL_INTERFACE_ALL) ||
			(cd_get_model_interfaces(c) == CD_MODEL_INTERFACE_IDE && hdd_controller_selected_is_ide(hdlg)) ||
			(cd_get_model_interfaces(c) == CD_MODEL_INTERFACE_SCSI && hdd_controller_selected_is_scsi(hdlg))) {

			model = cd_get_model(c);
			sprintf(s, "%s", model);
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);

			if (!strncmp(s, cur_model, 40)) {
				wx_sendmessage(h, WX_CB_SETCURSEL, c, 0);
				temp_model = c;
				found = 1;
			}
		}

		c++;
	}
	if (!found)
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); // assume that there is always at least one TODO: is this necessary?


	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED"));
	c = 0;
	found = 0;

	wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
	if (temp_model >= 0 && cd_get_model_speed(temp_model) != -1) {
		// this model has a specific speed
		wx_enablewindow(h, FALSE);
		cur_speed = cd_get_model_speed(temp_model);
	} else if (hdd_controller_selected_is_ide(hdlg) || hdd_controller_selected_is_scsi(hdlg))
		wx_enablewindow(h, TRUE);
	else
		wx_enablewindow(h, FALSE);
	while (1) {
		char s[8];
		int speed;

		speed = cd_get_speed(c);
		sprintf(s, "%iX", speed);
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);

		if (speed == cur_speed) {
			wx_sendmessage(h, WX_CB_SETCURSEL, c, 0);
			found = 1;
		}

		c++;
		if (speed >= MAX_CD_SPEED)
			break;
	}
	if (!found)
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); // fall back TODO: is this necessary?
}

#ifdef USE_NETWORKING
static void recalc_net_list(void *hdlg, int model)
{
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD"));
	int c = 0, d = 0;
	int found_card = 0;

	wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);

	while (1)
	{
		char *s = network_card_getname(c);
		device_t *dev;

		if (!s[0])
			break;

		settings_network_to_list[c] = d;

		dev = network_card_getdevice(c);

		if (network_card_available(c) &&
		    (!dev || (models[model]->flags & MODEL_PCI) || !(dev->flags & DEVICE_PCI)))
		{
			device_t *network_dev = network_card_getdevice(c);

			if (!network_dev || (network_dev->flags & DEVICE_MCA) == (models[model]->flags & MODEL_MCA))
			{
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
				settings_list_to_network[d] = c;
				if (c == network_card_current)
				{
					wx_sendmessage(h, WX_CB_SETCURSEL, d, 0);
					found_card = 1;
				}
				d++;
			}
		}

		c++;
	}
	if (!found_card)
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
}
#endif

int config_dlgsave(void *hdlg) {
	char temp_str[256];
	void *h;
	int c;
	int gfx;//, fpu;
	int temp_cpu, temp_cpu_m, temp_model, temp_fpu;
	int temp_GAMEBLASTER, temp_GUS, temp_SSI2001, temp_voodoo, temp_sound_card_current;
	int temp_dynarec;
	int temp_fda_type, temp_fdb_type;
	int temp_mouse_type;
	int temp_lpt1_device;
	int temp_joystick_type;
#ifdef USE_NETWORKING
	int temp_network_card;
#endif
	int hdd_changed = 0;
	char s[260];
	PcemHDC hd[7];

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
	temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

	h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN"));
	int mem = wx_sendmessage(h, WX_UDM_GETPOS, 0, 0);
	mem &= ~(models[temp_model]->ram_granularity - 1);
	if (mem < models[temp_model]->min_ram)
		mem = models[temp_model]->min_ram;
	else if (mem > models[temp_model]->max_ram)
		mem = models[temp_model]->max_ram;
	if ((models[temp_model]->flags & MODEL_AT) && models[temp_model]->ram_granularity < 128)
		mem *= 1024;

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID"));
	wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0),
		       (LONG_PARAM)temp_str);
	gfx = video_new_to_old(video_card_getid(temp_str));

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM"));
	temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3"));
	temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
//        fpu = (models[temp_model]->cpu[temp_cpu_m].cpus[temp_cpu].cpu_type
//        >= CPU_i486DX) ? 1 : 0;

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU"));
	temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0));

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECK3"));
	temp_GAMEBLASTER = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKGUS"));
	temp_GUS = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSSI"));
	temp_SSI2001 = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSYNC"));
	enable_sync = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKVOODOO"));
	temp_voodoo = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND"));
	temp_sound_card_current = settings_list_to_sound[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
	temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRA"));
	temp_fda_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRB"));
	temp_fdb_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY"));
	temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOMOUSE"));
	temp_mouse_type = settings_list_to_mouse[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));
	c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	if (hdd_names[c])
		hdd_changed = strncmp(hdd_names[c], hdd_controller_name, sizeof(hdd_controller_name) - 1);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOLPT1"));
	temp_lpt1_device = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

#ifdef USE_NETWORKING
	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD"));
	temp_network_card = settings_list_to_network[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];
#endif

	if (temp_model != model || gfx != gfxcard || mem != mem_size || temp_fpu != fpu_type ||
		temp_GAMEBLASTER != GAMEBLASTER || temp_GUS != GUS ||
		temp_SSI2001 != SSI2001 || temp_sound_card_current != sound_card_current ||
		temp_voodoo != voodoo_enabled || temp_dynarec != cpu_use_dynarec ||
		temp_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1) ||
		temp_mouse_type != mouse_type || hdd_changed || hd_changed || cdrom_channel != new_cdrom_channel ||
		zip_channel != new_zip_channel || lpt1_current != temp_lpt1_device
#ifdef USE_NETWORKING
		|| temp_network_card != network_card_current
#endif
		) {
		if (!has_been_inited || confirm()) {
			savenvr();
			model = temp_model;
			romset = model_getromset();
			gfxcard = gfx;
			mem_size = mem;
			cpu_manufacturer = temp_cpu_m;
			cpu = temp_cpu;
			fpu_type = temp_fpu;
			GAMEBLASTER = temp_GAMEBLASTER;
			GUS = temp_GUS;
			SSI2001 = temp_SSI2001;
			sound_card_current = temp_sound_card_current;
			lpt1_current = temp_lpt1_device;
			voodoo_enabled = temp_voodoo;
			cpu_use_dynarec = temp_dynarec;
			mouse_type = temp_mouse_type;
			strcpy(lpt1_device_name, lpt_device_get_internal_name(temp_lpt1_device));
#ifdef USE_NETWORKING
			network_card_current = temp_network_card;
#endif

			fdd_set_type(0, temp_fda_type);
			fdd_set_type(1, temp_fdb_type);

			if (hdd_names[c])
				strncpy(hdd_controller_name, hdd_names[c], sizeof(hdd_controller_name) - 1);
			else
				strcpy(hdd_controller_name, "none");

			for (c = 0; c < 7; c++) {
				sprintf(s, "IDC_EDIT_SPT[%i]", c);
				h = wx_getdlgitem(hdlg, WX_ID(s));
				wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
				sscanf(s, "%i", &hd[c].spt);
				sprintf(s, "IDC_EDIT_HPC[%i]", c);
				h = wx_getdlgitem(hdlg, WX_ID(s));
				wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
				sscanf(s, "%i", &hd[c].hpc);
				sprintf(s, "IDC_EDIT_CYL[%i]", c);
				h = wx_getdlgitem(hdlg, WX_ID(s));
				wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
				sscanf(s, "%i", &hd[c].tracks);
				sprintf(s, "IDC_EDIT_FN[%i]", c);
				h = wx_getdlgitem(hdlg, WX_ID(s));
				wx_sendmessage(h, WX_WM_GETTEXT, 511, (LONG_PARAM)ide_fn[c]);

				hdc[c] = hd[c];
			}

			cdrom_channel = new_cdrom_channel;
			zip_channel = new_zip_channel;

			if (has_been_inited) {
				mem_alloc();
				loadbios();
				resetpchard();
			}
		} else
			return TRUE;
	}

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSPD"));
	video_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0) - 1;

	cpu_manufacturer = temp_cpu_m;
	cpu = temp_cpu;
	cpu_set();

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS"));
	cpu_waitstates = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	cpu_update_waitstates();

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED"));
	cd_speed = cd_get_speed(wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0));
	cd_set_speed(cd_speed);

	h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL"));
	cd_model = cd_get_model(wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0));
	cd_set_model(cd_model);

	if (has_been_inited)
		saveconfig(NULL);

	speedchanged();

	joystick_type = temp_joystick_type;
	gameport_update_joystick_type();

	return TRUE;
}

static int prev_model;
int config_dlgproc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) {
	char temp_str[256];
	void *h;
	int c, d;
	int gfx, mem;
	int temp_cpu, temp_cpu_m, temp_model, temp_fpu;
	int temp_sound_card_current;
	int temp_dynarec;
	int cpu_flags;
	int cpu_type;
	int temp_cd_model, temp_cd_speed;
	int temp_mouse_type;
	int temp_lpt1_current;
#ifdef USE_NETWORKING
	int temp_network_card;
#endif

	switch (message) {
	case WX_INITDIALOG: {
		pause = 1;
		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
		for (c = 0; c < ROM_MAX; c++)
			romstolist[c] = 0;
		c = d = 0;
		while (models[c] != NULL) {
			pclog("INITDIALOG : %i %i %i\n", c, models[c]->id,
			      romspresent[models[c]->id]);
			if (romspresent[models[c]->id]) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)models[c]->name);
				modeltolist[c] = d;
				listtomodel[d] = c;
				romstolist[models[c]->id] = d;
				romstomodel[models[c]->id] = c;
				d++;
			}
			c++;
		}
		wx_sendmessage(h, WX_CB_SETCURSEL, modeltolist[model], 0);
		model = listtomodel[modeltolist[model]];
		romset = model_getromset();
		prev_model = model;

		recalc_vid_list(hdlg, romstomodel[romset], 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM"));
		c = 0;
		while (models[romstomodel[romset]]->cpu[c].cpus != NULL && c < 4) {
			wx_sendmessage(h, WX_CB_ADDSTRING, 0,
				       (LONG_PARAM)models[romstomodel[romset]]->cpu[c].name);
			c++;
		}
		wx_enablewindow(h, TRUE);
		wx_sendmessage(h, WX_CB_SETCURSEL, cpu_manufacturer, 0);
		if (c == 1)
			wx_enablewindow(h, FALSE);
		else
			wx_enablewindow(h, TRUE);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3"));
		c = 0;
		while (models[romstomodel[romset]]->cpu[cpu_manufacturer].cpus[c].cpu_type != -1) {
			wx_sendmessage(h, WX_CB_ADDSTRING, 0,
				       (LONG_PARAM)models[romstomodel[romset]]->cpu[cpu_manufacturer].cpus[c].name);
			c++;
		}
		wx_enablewindow(h, TRUE);
		wx_sendmessage(h, WX_CB_SETCURSEL, cpu, 0);

		recalc_fpu_list(hdlg, romstomodel[romset], cpu_manufacturer, cpu, fpu_type);

		recalc_snd_list(hdlg, romstomodel[romset]);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECK3"));
		wx_sendmessage(h, WX_BM_SETCHECK, GAMEBLASTER, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKGUS"));
		wx_sendmessage(h, WX_BM_SETCHECK, GUS, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSSI"));
		wx_sendmessage(h, WX_BM_SETCHECK, SSI2001, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSYNC"));
		wx_sendmessage(h, WX_BM_SETCHECK, enable_sync, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKVOODOO"));
		wx_sendmessage(h, WX_BM_SETCHECK, voodoo_enabled, 0);

		cpu_flags =
			models[romstomodel[romset]]->cpu[cpu_manufacturer].cpus[cpu].cpu_flags;
		h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
		if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC))
			wx_enablewindow(h, FALSE);
		else
			wx_enablewindow(h, TRUE);
		wx_sendmessage(h, WX_BM_SETCHECK,
			       ((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec)
				       || (cpu_flags & CPU_REQUIRES_DYNAREC), 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSPD"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Default");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"8-bit");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Slow 16-bit");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Fast 16-bit");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Slow VLB/PCI");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Mid  VLB/PCI");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Fast VLB/PCI");
		wx_sendmessage(h, WX_CB_SETCURSEL, video_speed + 1, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN"));
		printf("%d\n", models[model]->ram_granularity);
		wx_sendmessage(h, WX_UDM_SETRANGE, 0,
			       (models[romstomodel[romset]]->min_ram << 16)
				       | models[romstomodel[romset]]->max_ram);
		wx_sendmessage(h, WX_UDM_SETINCR, 0, models[model]->ram_granularity);
		if (!((models[model]->flags & MODEL_AT) && models[model]->ram_granularity < 128)) {
			wx_sendmessage(h, WX_UDM_SETPOS, 0, mem_size);
			memspin_old = mem_size;
		} else {
			wx_sendmessage(h, WX_UDM_SETPOS, 0, mem_size / 1024);
			memspin_old = mem_size / 1024;
		}

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREMOD"));
		if (model_getdevice(model))
			wx_enablewindow(h, TRUE);
		else
			wx_enablewindow(h, FALSE);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURESND"));
		if (sound_card_has_config(sound_card_current))
			wx_enablewindow(h, TRUE);
		else
			wx_enablewindow(h, FALSE);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURELPT1"));
		if (lpt_device_has_config(lpt1_current))
			wx_enablewindow(h, TRUE);
		else
			wx_enablewindow(h, FALSE);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRA"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"None");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 360k");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M Dual RPM");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 720k");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M 3-Mode");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 2.88M");
		wx_sendmessage(h, WX_CB_SETCURSEL, fdd_get_type(0), 0);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRB"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"None");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 360k");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M Dual RPM");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 720k");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M 3-Mode");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 2.88M");
		wx_sendmessage(h, WX_CB_SETCURSEL, fdd_get_type(1), 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT_MB"));
		if ((models[model]->flags & MODEL_AT) && (models[model]->ram_granularity < 128))
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"MB");
		else
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"KB");

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY"));
		c = 0;
		while (joystick_get_name(c)) {
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)joystick_get_name(c));
			c++;
		}
		wx_enablewindow(h, TRUE);
		wx_sendmessage(h, WX_CB_SETCURSEL, joystick_type, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY1"));
		wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 1) ? TRUE : FALSE);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY2"));
		wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 2) ? TRUE : FALSE);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY3"));
		wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 3) ? TRUE : FALSE);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY4"));
		wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 4) ? TRUE : FALSE);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"System default");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"0 W/S");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"1 W/S");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"2 W/S");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3 W/S");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"4 W/S");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5 W/S");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"6 W/S");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"7 W/S");
		wx_sendmessage(h, WX_CB_SETCURSEL, cpu_waitstates, 0);
		cpu_type =
			models[romstomodel[romset]]->cpu[cpu_manufacturer].cpus[cpu].cpu_type;
		if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX))
			wx_enablewindow(h, TRUE);
		else
			wx_enablewindow(h, FALSE);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOMOUSE"));
		c = d = 0;
		while (1) {
			char *s = mouse_get_name(c);
			int type;

			if (!s)
				break;

			type = mouse_get_type(c);

			settings_mouse_to_list[c] = d;

			if (mouse_valid(type, model)) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);

				settings_list_to_mouse[d] = c;
				d++;
			}
			c++;
		}
		wx_sendmessage(h, WX_CB_SETCURSEL, settings_mouse_to_list[mouse_type], 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOLPT1"));
		c = d = 0;
		while (1) {
			char *s = lpt_device_get_name(c);

			if (!s)
				break;

			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
			if (!strcmp(lpt1_device_name, lpt_device_get_internal_name(c)))
				if (lpt1_current == c)
					d = c;

			c++;
		}
		wx_sendmessage(h, WX_CB_SETCURSEL, d, 0);

		recalc_hdd_list(hdlg, romstomodel[romset], 0, 0);

		hd_changed = 0;
		new_cdrom_channel = cdrom_channel;
		new_zip_channel = zip_channel;

		hdconf_init(hdlg);

		for (c = 0; c < 7; c++) {
			char s[80];

			sprintf(s, "IDC_COMBODRIVETYPE[%i]", c);
			h = wx_getdlgitem(hdlg, WX_ID(s));
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Hard drive");
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"CD-ROM");
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Iomega Zip");
			if (cdrom_channel == c)
				wx_sendmessage(h, WX_CB_SETCURSEL, 1, 0);
			else if (zip_channel == c)
				wx_sendmessage(h, WX_CB_SETCURSEL, 2, 0);
			else
				wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
		}

		recalc_cd_list(hdlg, cd_speed, cd_model);

#ifdef USE_NETWORKING
		recalc_net_list(hdlg, romstomodel[romset]);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURE_NETCARD"));
		if (network_card_has_config(network_card_current))
			wx_enablewindow(h, TRUE);
		else
			wx_enablewindow(h, FALSE);
#endif

		return TRUE;
	}
		break;
	case WX_COMMAND: {
		if (wParam == WX_ID("IDC_COMBO1")) {
			int force_ide = 0;
			int force_builtin_video = 0;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

			if (temp_model == prev_model)
				break;

			if ((models[temp_model]->flags & MODEL_HAS_IDE) && !(models[prev_model]->flags & MODEL_HAS_IDE))
				force_ide = 1;
			if (model_has_optional_gfx(temp_model))
				force_builtin_video = 1;

			prev_model = temp_model;

			/*Rebuild manufacturer list*/
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM"));
			temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
			c = 0;
			while (models[temp_model]->cpu[c].cpus != NULL && c < 4) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0,
					       (LONG_PARAM)models[temp_model]->cpu[c].name);
				c++;
			}
			if (temp_cpu_m >= c)
				temp_cpu_m = c - 1;
			wx_sendmessage(h, WX_CB_SETCURSEL, temp_cpu_m, 0);
			if (c == 1)
				wx_enablewindow(h, FALSE);
			else
				wx_enablewindow(h, TRUE);

			/*Rebuild CPU list*/
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3"));
			temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
			c = 0;
			while (models[temp_model]->cpu[temp_cpu_m].cpus[c].cpu_type != -1) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0,
					       (LONG_PARAM)models[temp_model]->cpu[temp_cpu_m].cpus[c].name);
				c++;
			}
			if (temp_cpu >= c)
				temp_cpu = c - 1;
			wx_sendmessage(h, WX_CB_SETCURSEL, temp_cpu, 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU"));
			temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0));
			recalc_fpu_list(hdlg, temp_model, temp_cpu_m, temp_cpu, temp_fpu);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
			temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

			cpu_flags =
				models[temp_model]->cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags;
			h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
			if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC))
				wx_enablewindow(h, FALSE);
			else
				wx_enablewindow(h, TRUE);
			wx_sendmessage(h, WX_BM_SETCHECK,
				       ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec)
					       || (cpu_flags & CPU_REQUIRES_DYNAREC), 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT_MB"));
			if ((models[temp_model]->flags & MODEL_AT) && models[temp_model]->ram_granularity < 128)
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"MB");
			else
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"KB");

			h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN"));
			mem = wx_sendmessage(h, WX_UDM_GETPOS, 0, 0);
			wx_sendmessage(h, WX_UDM_SETRANGE, 0,
				       (models[temp_model]->min_ram << 16)
					       | models[temp_model]->max_ram);
			mem &= ~(models[temp_model]->ram_granularity - 1);
			if (mem < models[temp_model]->min_ram)
				mem = models[temp_model]->min_ram;
			else if (mem > models[temp_model]->max_ram)
				mem = models[temp_model]->max_ram;
			wx_sendmessage(h, WX_UDM_SETPOS, 0, mem);
			wx_sendmessage(h, WX_UDM_SETINCR, 0, models[temp_model]->ram_granularity);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS"));
			cpu_type =
				models[temp_model]->cpu[temp_cpu_m].cpus[temp_cpu].cpu_type;
			if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX)
				wx_enablewindow(h, TRUE);
			else
				wx_enablewindow(h, FALSE);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREMOD"));
			if (model_getdevice(temp_model))
				wx_enablewindow(h, TRUE);
			else
				wx_enablewindow(h, FALSE);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOMOUSE"));
			temp_mouse_type = settings_list_to_mouse[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];
			wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
			c = d = 0;
			while (1) {
				char *s = mouse_get_name(c);
				int type;

				if (!s)
					break;

				type = mouse_get_type(c);
				settings_mouse_to_list[c] = d;

				if (mouse_valid(type, temp_model)) {
					wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);

					settings_list_to_mouse[d] = c;
					d++;
				}

				c++;
			}

			if (mouse_valid(mouse_get_type(temp_mouse_type), temp_model))
				wx_sendmessage(h, WX_CB_SETCURSEL, settings_mouse_to_list[temp_mouse_type], 0);
			else
				wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);

			recalc_vid_list(hdlg, temp_model, force_builtin_video);

			recalc_hdd_list(hdlg, temp_model, 1, force_ide);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL"));
			temp_cd_model = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED"));
			temp_cd_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			recalc_cd_list(hdlg, cd_get_speed(temp_cd_speed), cd_get_model(temp_cd_model));

			recalc_snd_list(hdlg, temp_model);
#ifdef USE_NETWORKING
			recalc_net_list(hdlg, temp_model);
#endif
		} else if (wParam == WX_ID("IDC_COMBOCPUM")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM"));
			temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

			/*Rebuild CPU list*/
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3"));
			temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);
			c = 0;
			while (models[temp_model]->cpu[temp_cpu_m].cpus[c].cpu_type != -1) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0,
					       (LONG_PARAM)models[temp_model]->cpu[temp_cpu_m].cpus[c].name);
				c++;
			}
			if (temp_cpu >= c)
				temp_cpu = c - 1;
			wx_sendmessage(h, WX_CB_SETCURSEL, temp_cpu, 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU"));
			temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0));
			recalc_fpu_list(hdlg, temp_model, temp_cpu_m, temp_cpu, temp_fpu);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
			temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

			cpu_flags =
				models[temp_model]->cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags;
			h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
			if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC))
				wx_enablewindow(h, FALSE);
			else
				wx_enablewindow(h, TRUE);
			wx_sendmessage(h, WX_BM_SETCHECK,
				       ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec)
					       || (cpu_flags & CPU_REQUIRES_DYNAREC), 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS"));
			cpu_type =
				models[temp_model]->cpu[temp_cpu_m].cpus[temp_cpu].cpu_type;
			if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX)
				wx_enablewindow(h, TRUE);
			else
				wx_enablewindow(h, FALSE);

		} else if (wParam == WX_ID("IDC_COMBO3")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM"));
			temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3"));
			temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU"));
			temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0));
			recalc_fpu_list(hdlg, temp_model, temp_cpu_m, temp_cpu, temp_fpu);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
			temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0);

			cpu_flags =
				models[temp_model]->cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags;
			h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC"));
			if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC))
				wx_enablewindow(h, FALSE);
			else
				wx_enablewindow(h, TRUE);
			wx_sendmessage(h, WX_BM_SETCHECK,
				       ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec)
					       || (cpu_flags & CPU_REQUIRES_DYNAREC), 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS"));
			cpu_type =
				models[temp_model]->cpu[temp_cpu_m].cpus[temp_cpu].cpu_type;
			if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX)
				wx_enablewindow(h, TRUE);
			else
				wx_enablewindow(h, FALSE);
		} else if (wParam == WX_ID("IDC_CONFIGUREMOD")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

			deviceconfig_open(hdlg, (void *)model_getdevice(temp_model));
		} else if (wParam == WX_ID("IDC_CONFIGUREVID")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID"));
			wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0), (LONG_PARAM)temp_str);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

			deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(temp_str), model_getromset_from_model(temp_model)));
		} else if (wParam == WX_ID("IDC_COMBOVID")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID"));
			wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0),
				       (LONG_PARAM)temp_str);
			gfx = video_card_getid(temp_str);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID"));
			if (video_card_has_config(gfx, model_getromset_from_model(temp_model)))
				wx_enablewindow(h, TRUE);
			else
				wx_enablewindow(h, FALSE);
		} else if (wParam == WX_ID("IDC_CONFIGURESND")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND"));
			temp_sound_card_current = settings_list_to_sound[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

			deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card_current));
		} else if (wParam == WX_ID("IDC_COMBOSND")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND"));
			temp_sound_card_current = settings_list_to_sound[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

			h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURESND"));
			if (sound_card_has_config(temp_sound_card_current))
				wx_enablewindow(h, TRUE);
			else
				wx_enablewindow(h, FALSE);
		} else if (wParam == WX_ID("IDC_CONFIGUREVOODOO")) {
			deviceconfig_open(hdlg, (void *)&voodoo_device);
		} else if (wParam == WX_ID("IDC_COMBOHDD")) {
			hdconf_update(hdlg);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];
			recalc_hdd_list(hdlg, temp_model, 1, 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL"));
			temp_cd_model = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED"));
			temp_cd_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			recalc_cd_list(hdlg, cd_get_speed(temp_cd_speed), cd_get_model(temp_cd_model));
		} else if (wParam == WX_ID("IDC_CONFIGUREHDD")) {
			deviceconfig_open(hdlg, (void *)hdd_controller_selected_get_device(hdlg));
		} else if (wParam == WX_ID("IDC_COMBO_CDMODEL")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL"));
			temp_cd_model = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED"));
			temp_cd_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			recalc_cd_list(hdlg, cd_get_speed(temp_cd_speed), cd_get_model(temp_cd_model));
		}
#ifdef USE_NETWORKING
			else if (wParam == WX_ID("IDC_COMBO_NETCARD"))
			{
				h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD"));
				temp_network_card = settings_list_to_network[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

				h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURE_NETCARD"));
				if (network_card_has_config(temp_network_card))
					wx_enablewindow(h, TRUE);
				else
					wx_enablewindow(h, FALSE);
			}
			else if (wParam == WX_ID("IDC_CONFIGURE_NETCARD"))
			{
				h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD"));
				temp_network_card = settings_list_to_network[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

				deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_network_card));
			}
#endif
		else if (wParam == WX_ID("IDC_COMBOJOY")) {
			int temp_joystick_type;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY"));
			temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY1"));
			wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 1) ? TRUE : FALSE);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY2"));
			wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 2) ? TRUE : FALSE);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY3"));
			wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 3) ? TRUE : FALSE);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY4"));
			wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 4) ? TRUE : FALSE);
		} else if (wParam == WX_ID("IDC_JOY1")) {
			int temp_joystick_type;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY"));
			temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			joystickconfig_open(hdlg, 0, temp_joystick_type);
		} else if (wParam == WX_ID("IDC_JOY2")) {
			int temp_joystick_type;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY"));
			temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			joystickconfig_open(hdlg, 1, temp_joystick_type);
		} else if (wParam == WX_ID("IDC_JOY3")) {
			int temp_joystick_type;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY"));
			temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			joystickconfig_open(hdlg, 2, temp_joystick_type);
		} else if (wParam == WX_ID("IDC_JOY4")) {
			int temp_joystick_type;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY"));
			temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			joystickconfig_open(hdlg, 3, temp_joystick_type);
		} else if (wParam == WX_ID("IDC_CONFIGURELPT1")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOLPT1"));
			temp_lpt1_current = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

			deviceconfig_open(hdlg, (void *)lpt_get_device(temp_lpt1_current));
		} else if (wParam == WX_ID("IDC_COMBOLPT1")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOLPT1"));
			temp_lpt1_current = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURELPT1"));
			if (lpt_device_has_config(temp_lpt1_current))
				wx_enablewindow(h, TRUE);
			else
				wx_enablewindow(h, FALSE);
		}
#ifndef __WXGTK__
			/*Emulate spinner granularity on systems that don't implement wxSpinCtrl->SetIncrement()*/
		else if (wParam == WX_ID("IDC_MEMSPIN")) {
			int mem;
			int granularity;
			int granularity_mask;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1"));
			temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)];

			granularity = models[temp_model]->ram_granularity;
			granularity_mask = granularity - 1;

			h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN"));
			mem = wx_sendmessage(h, WX_UDM_GETPOS, 0, 0);
			if (mem < memspin_old) {
				/*Assume decrease*/
				mem &= ~granularity_mask;
			} else {
				/*Assume increase*/
				mem = (mem + granularity_mask) & ~granularity_mask;
			}
			wx_sendmessage(h, WX_UDM_SETPOS, 0, mem);
			memspin_old = mem;
		}
#endif
		return 0;
	}
	}
	return 0;
}

static struct {
	int cylinders;
	int heads;
} hd_types[] =
	{
		{306, 4}, {615, 4}, {615, 6}, {940, 8},
		{940, 6}, {615, 4}, {462, 8}, {733, 5},
		{900, 15}, {820, 3}, {855, 5}, {855, 7},
		{306, 8}, {733, 7}, {0, 0}, {612, 4},
		{977, 5}, {977, 7}, {1024, 7}, {733, 5},
		{733, 7}, {733, 5}, {306, 4}, {925, 7},
		{925, 9}, {754, 7}, {754, 11}, {699, 7},
		{823, 10}, {918, 7}, {1024, 11}, {1024, 15},
		{1024, 5}, {612, 2}, {1024, 9}, {1024, 8},
		{615, 8}, {987, 3}, {462, 7}, {820, 6},
		{977, 5}, {981, 5}, {830, 7}, {830, 10},
		{917, 15}, {1224, 15}
	};

static int hdd_controller_selected_is_mfm(void *hdlg) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));
	int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	if (hdd_names[c])
		return hdd_controller_is_mfm(hdd_names[c]);
	return 0;
}
static int hdd_controller_selected_is_ide(void *hdlg) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));
	int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	if (hdd_names[c])
		return hdd_controller_is_ide(hdd_names[c]);
	return 0;
}
static int hdd_controller_selected_is_scsi(void *hdlg) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));
	int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	if (hdd_names[c])
		return hdd_controller_is_scsi(hdd_names[c]);
	return 0;
}
static int hdd_controller_selected_has_config(void *hdlg) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));
	int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	if (hdd_names[c])
		return hdd_controller_has_config(hdd_names[c]);
	return 0;
}
static device_t *hdd_controller_selected_get_device(void *hdlg) {
	void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD"));
	int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	if (hdd_names[c])
		return hdd_controller_get_device(hdd_names[c]);
	return NULL;
}

static void check_hd_type(void *hdlg, off64_t sz) {
	int c;

	hd_new_type = 0;

	if (hdd_controller_selected_is_mfm(hdlg)) {
		for (c = 0; c < 46; c++) {
			if ((hd_types[c].cylinders * hd_types[c].heads * 17 * 512) == sz) {
				hd_new_spt = 17;
				hd_new_hpc = hd_types[c].heads;
				hd_new_cyl = hd_types[c].cylinders;
				hd_new_type = c + 1;
				return;
			}
		}
		hd_new_spt = 63;
		hd_new_hpc = 16;
		hd_new_cyl = ((sz / 512) / 16) / 63;
	} else {
		if ((sz % 17) == 0 && sz <= 142606336) {
			hd_new_spt = 17;

			if (sz <= 26738688)
				hd_new_hpc = 4;
			else if ((sz % 3072) == 0 && sz <= 53477376)
				hd_new_hpc = 6;
			else {
				for (c = 5; c < 16; c++) {
					if ((sz % (c * 512)) == 0 && sz <= 1024 * c * 17 * 512)
						break;
					if (c == 5)
						c++;
				}
				hd_new_hpc = c;
			}
			hd_new_cyl = (int)((sz / 512) / hd_new_hpc) / 17;
		} else {
			hd_new_spt = 63;
			hd_new_hpc = 16;
			hd_new_cyl = ((sz / 512) / 16) / 63;
		}
	}
}

static void update_hdd_cdrom(void *hdlg) {
	void *h;
	int i, j, b;
	char s[25];

	int is_mfm = hdd_controller_selected_is_mfm(hdlg);

	for (i = 0; i < 7; ++i) {
		b = !is_mfm && ((new_cdrom_channel == i) || (new_zip_channel == i));
		pclog("update_hdd_cdrom: i=%i b=%i new_cdrom_channel=%i new_zip_channel=%i\n", i, b, new_cdrom_channel, new_zip_channel);
		sprintf(s, "IDC_COMBODRIVETYPE[%d]", i);
		h = wx_getdlgitem(hdlg, WX_ID(s));
		if (i == new_cdrom_channel)
			wx_sendmessage(h, WX_CB_SETCURSEL, 1, 0);
		else if (i == new_zip_channel)
			wx_sendmessage(h, WX_CB_SETCURSEL, 2, 0);
		else
			wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
		sprintf(s, "IDC_EDIT_FN[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		sprintf(s, "IDC_FILE[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		sprintf(s, "IDC_EJECT[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		sprintf(s, "IDC_NEW[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		sprintf(s, "IDC_EDIT_SPT[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		sprintf(s, "IDC_EDIT_HPC[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		sprintf(s, "IDC_EDIT_CYL[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		sprintf(s, "IDC_TEXT_SIZE[%d]", i);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		for (j = 1; j < 6; ++j) {
			sprintf(s, "IDC_HDD_LABEL[%d]", i * 10 + j);
			wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b);
		}
	}
}

static volatile int create_drive_pos;
static int create_drive_raw(void *data) {
	int c;
	uint8_t buf[512];
	FILE *f = (FILE *)data;
	memset(buf, 0, 512);
	for (c = 0; c < (hd_new_cyl * hd_new_hpc * hd_new_spt); c++) {
		create_drive_pos = c;
		fwrite(buf, 512, 1, f);
	}

	fclose(f);

	return 1;
}

static void vhd_progress_callback(uint32_t current_sector, uint32_t total_sectors) {
	create_drive_pos = (int)current_sector;
}

/* If the disk geometry requested in the PCem GUI is not compatible with the internal VHD geometry,
 * we adjust it to the next-largest size that is compatible. On average, this will be a difference
 * of about 21 MB, and should only be necessary for VHDs larger than 31.5 GB, so should never be more
 * than a tenth of a percent change in size.
 */
static void adjust_pcem_geometry_for_vhd(MVHDGeom *vhd_geometry) {
	if (hd_new_cyl <= 65535)
		return;

	int desired_sectors = hd_new_cyl * hd_new_hpc * hd_new_spt;
	if (desired_sectors > 267321600)
		desired_sectors = 267321600;

	int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */
	if (remainder > 0)
		desired_sectors += (85680 - remainder);

	hd_new_cyl = desired_sectors / (16 * 63);
	hd_new_hpc = 16;
	hd_new_spt = 63;

	vhd_geometry->cyl = desired_sectors / (16 * 255);
	vhd_geometry->heads = 16;
	vhd_geometry->spt = 255;
}

static void adjust_vhd_geometry_for_pcem() {
	if (hd_new_spt <= 63)
		return;

	int desired_sectors = hd_new_cyl * hd_new_hpc * hd_new_spt;
	if (desired_sectors > 267321600)
		desired_sectors = 267321600;

	int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */
	if (remainder > 0)
		desired_sectors -= remainder;

	hd_new_cyl = desired_sectors / (16 * 63);
	hd_new_hpc = 16;
	hd_new_spt = 63;
}

static int create_drive_vhd_fixed(void *data) {
	MVHDGeom geometry = {.cyl = hd_new_cyl, .heads = hd_new_hpc, .spt = hd_new_spt};
	adjust_pcem_geometry_for_vhd(&geometry);

	int vhd_error = 0;
	MVHDMeta *vhd = mvhd_create_fixed(hd_new_name, geometry, &vhd_error, vhd_progress_callback);
	if (vhd == NULL) {
		return 0;
	} else {
		mvhd_close(vhd);
		return 1;
	}
}

static int create_drive_vhd_dynamic(int blocksize) {
	MVHDGeom geometry = {.cyl = hd_new_cyl, .heads = hd_new_hpc, .spt = hd_new_spt};
	adjust_pcem_geometry_for_vhd(&geometry);
	int vhd_error = 0;
	MVHDCreationOptions options;
	options.block_size_in_sectors = blocksize;
	options.path = hd_new_name;
	options.size_in_bytes = 0;
	options.geometry = geometry;
	options.type = MVHD_TYPE_DYNAMIC;

	MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error);
	if (vhd == NULL) {
		return 0;
	} else {
		mvhd_close(vhd);
		return 1;
	}
}

static int create_drive_vhd_diff(char *parent_filename, int blocksize) {
	int vhd_error = 0;
	MVHDCreationOptions options;
	options.block_size_in_sectors = blocksize;
	options.path = hd_new_name;
	options.parent_path = parent_filename;
	options.type = MVHD_TYPE_DIFF;

	MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error);
	if (vhd == NULL) {
		return 0;
	} else {
		MVHDGeom vhd_geom = mvhd_get_geometry(vhd);

		if (vhd_geom.spt > 63) {
			hd_new_cyl = mvhd_calc_size_sectors(&vhd_geom) / (16 * 63);
			hd_new_hpc = 16;
			hd_new_spt = 63;
		} else {
			hd_new_cyl = vhd_geom.cyl;
			hd_new_hpc = vhd_geom.heads;
			hd_new_spt = vhd_geom.spt;
		}

		mvhd_close(vhd);
		return 1;
	}
}

static int hdnew_dlgproc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) {
	char s[260];
	void *h;
	int c;
	PcemHDC hd[7];
	FILE *f;
	int hd_type, hd_format, hd_blocksize;
	int size;

	switch (message) {
	case WX_INITDIALOG:h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
		sprintf(s, "%i", 63);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
		sprintf(s, "%i", 16);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
		sprintf(s, "%i", 511);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_EDITC"));
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"");

		h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4"));
		sprintf(s, "%i", (((511 * 16 * 63) * 512) / 1024) / 1024);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

//                hd_type = 0;
		h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Custom type");
		for (c = 1; c <= 46; c++) {
			sprintf(s,
				"Type %02i : cylinders=%i, heads=%i, size=%iMB",
				c,
				hd_types[c - 1].cylinders,
				hd_types[c - 1].heads,
				(hd_types[c - 1].cylinders * hd_types[c - 1].heads * 17 * 512) / (1024 * 1024));
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
		}
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Raw (.img)");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Fixed-size VHD (.vhd)");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Dynamic-size VHD (.vhd)");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Differencing VHD (.vhd)");
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Large blocks (2 MB)");
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Small blocks (512 KB)");
		wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
		wx_sendmessage(h, WX_WM_SHOW, 0, (LONG_PARAM)0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZELABEL"));
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)" ");

		return TRUE;
	case WX_COMMAND:
		if (wParam == wxID_OK) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDITC"));
			wx_sendmessage(h, WX_WM_GETTEXT, 511, (LONG_PARAM)hd_new_name);
			if (!hd_new_name[0]) {
				wx_messagebox(hdlg, "Please enter a valid filename", "PCem error", WX_MB_OK);
				return TRUE;
			}
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd_new_spt);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd_new_hpc);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd_new_cyl);

			if (hd_new_spt > 63) {
				wx_messagebox(hdlg, "Drive has too many sectors (maximum is 63)", "PCem error", WX_MB_OK);
				return TRUE;
			}
			if (hd_new_hpc > 16) {
				wx_messagebox(hdlg, "Drive has too many heads (maximum is 16)", "PCem error", WX_MB_OK);
				return TRUE;
			}
			if (hd_new_cyl > MAX_CYLINDERS) {
				char s[256];
				sprintf(s, "Drive has too many cylinders (maximum is %i)", MAX_CYLINDERS);
				wx_messagebox(hdlg, s, "PCem error", WX_MB_OK);
				return TRUE;
			}

			h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT"));
			hd_format = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE"));
			hd_blocksize = (wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0) == 0) ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL;

			if (hd_format == 0) /* Raw .img */
			{
				f = fopen64(hd_new_name, "wb");
				if (!f) {
					wx_messagebox(hdlg, "Can't open file for write", "PCem error", WX_MB_OK);
					return TRUE;
				}
				wx_progressdialog(hdlg, "PCem", "Creating drive, please wait...", create_drive_raw, f, hd_new_cyl * hd_new_hpc * hd_new_spt, &create_drive_pos);
			} else if (hd_format == 1) /* Fixed VHD */
			{
				if (!wx_progressdialog(hdlg, "PCem", "Creating drive, please wait...", create_drive_vhd_fixed, NULL, hd_new_cyl * hd_new_hpc * hd_new_spt, &create_drive_pos)) {
					wx_messagebox(hdlg, "Can't create VHD", "PCem error", WX_MB_OK);
					return TRUE;
				}
			} else if (hd_format == 2) /* Dynamic VHD */
			{
				if (!create_drive_vhd_dynamic(hd_blocksize)) {
					wx_messagebox(hdlg, "Can't create VHD", "PCem error", WX_MB_OK);
					return TRUE;
				}
			} else if (hd_format == 3) /* Differencing VHD */
			{
				if (!getfilewithcaption(hdlg, "VHD file (*.vhd)|*.vhd|All files (*.*)|*.*", "", "Select the parent VHD")) {
					if (!create_drive_vhd_diff(openfilestring, hd_blocksize)) {
						wx_messagebox(hdlg, "Can't create VHD", "PCem error", WX_MB_OK);
						return TRUE;
					}
				}
				wx_messagebox(hdlg, "Differencing VHD image created.\n\n"
						    "WARNING: Do not open or modify the parent image(s) while this file exists.", "PCem", WX_MB_OK);
			}
			if (hd_format != 3) {
				wx_messagebox(hdlg, "Drive created, remember to partition and format the new drive.", "PCem", WX_MB_OK);
			}

			wx_enddialog(hdlg, 1);
			return TRUE;
		} else if (wParam == wxID_CANCEL) {
			wx_enddialog(hdlg, 0);
			return TRUE;
		} else if (ID_IS("IDC_CFILE")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT"));
			hd_format = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			if (!getsfile(hdlg,
				      hd_format == 0 ? "Raw Hard disc image (*.img)|*.img|All files (*.*)|*.*" : "VHD file (*.vhd)|*.vhd|All files (*.*)|*.*",
				      "",
				      NULL,
				      hd_format == 0 ? "img" : "vhd")) {
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDITC"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)openfilestring);
			}
			return TRUE;
		} else if (ID_IS("IDC_EDIT1") || ID_IS("IDC_EDIT2") || ID_IS("IDC_EDIT3")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			pclog("EDIT1: %s\n", s);
			sscanf(s, "%i", &hd[0].spt);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			pclog("EDIT2: %s\n", s);
			sscanf(s, "%i", &hd[0].hpc);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			pclog("EDIT3: %s\n", s);
			sscanf(s, "%i", &hd[0].tracks);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4"));
			sprintf(s, "%i", (int)(((((uint64_t)hd[0].tracks * (uint64_t)hd[0].hpc) * (uint64_t)hd[0].spt) * 512) / 1024) / 1024);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

			hd_type = 0;
			for (c = 1; c <= 46; c++) {
				pclog("Compare %i,%i %i,%i %i,%i\n", hd[0].spt, 17, hd[0].hpc, hd_types[c - 1].heads, hd[0].tracks, hd_types[c - 1].cylinders);
				if (hd[0].spt == 17 && hd[0].hpc == hd_types[c - 1].heads && hd[0].tracks == hd_types[c - 1].cylinders) {
					hd_type = c;
					break;
				}
			}
			h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE"));
			wx_sendmessage(h, WX_CB_SETCURSEL, hd_type, 0);

			return TRUE;
		} else if (ID_IS("IDC_EDIT4")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			pclog("EDIT4: %s\n", s);
			sscanf(s, "%i", &size);

			hd[0].spt = 63;
			hd[0].hpc = 16;
			hd[0].tracks = (int)(((int64_t)size * 1024 * 1024) / (16 * 63 * 512));

			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
			sprintf(s, "%i", 63);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
			sprintf(s, "%i", 16);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
			sprintf(s, "%i", hd[0].tracks);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		} else if (ID_IS("IDC_HDTYPE")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE"));
			hd_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			if (hd_type) {
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
				sprintf(s, "%i", hd_types[hd_type - 1].cylinders);
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
				sprintf(s, "%i", hd_types[hd_type - 1].heads);
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"17");

				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4"));
				sprintf(s, "%i", (int)(((uint64_t)hd_types[hd_type - 1].cylinders * hd_types[hd_type - 1].heads * 17 * 512) / 1024) / 1024);
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
			}
			return TRUE;
		} else if (ID_IS("IDC_HDFORMAT")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT"));
			hd_format = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
			if (hd_format == 3) /* They switched to a dynamic VHD; disable the geometry fields. */
			{
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)");
				wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0);
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)");
				wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0);
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)");
				wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0);
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)");
				wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0);

				h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE"));
				wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
				wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0);
			} else /* Restore geometry fields if necessary. */
			{
				h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
				wx_sendmessage(h, WX_WM_GETTEXT, 0, (LONG_PARAM)s);
				if (!strncmp(s, "(use parent)", 12)) {
					wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"63");
					wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1);
					h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
					wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"16");
					wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1);
					h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
					wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"511");
					wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1);
					h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4"));
					wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"251");
					wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1);

					h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE"));
					wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1);
				}
			}

			if (hd_format == 2 || hd_format == 3) /* For dynamic and diff VHDs, show the block size dropdown. */
			{
				h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZELABEL"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"Block size:");
				h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE"));
				wx_sendmessage(h, WX_WM_SHOW, 0, (LONG_PARAM)1);
			} else /* Hide it otherwise. */
			{
				h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZELABEL"));
				wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)" ");
				h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE"));
				wx_sendmessage(h, WX_WM_SHOW, 0, (LONG_PARAM)0);
			}

			return TRUE;
		}
		break;

	}
	return FALSE;
}

static int hdsize_dlgproc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) {
	char s[260];
	void *h;
	PcemHDC hd[2];
	int c;

	switch (message) {
	case WX_INITDIALOG:h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE"));
		wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Custom type");
		for (c = 1; c <= 46; c++) {
			sprintf(s,
				"Type %02i : cylinders=%i, heads=%i, size=%iMB",
				c,
				hd_types[c - 1].cylinders,
				hd_types[c - 1].heads,
				(hd_types[c - 1].cylinders * hd_types[c - 1].heads * 17 * 512) / (1024 * 1024));
			wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
		}
		wx_sendmessage(h, WX_CB_SETCURSEL, hd_new_type, 0);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
		sprintf(s, "%i", hd_new_spt);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
		sprintf(s, "%i", hd_new_hpc);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
		sprintf(s, "%i", hd_new_cyl);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

		h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT1"));
		sprintf(s, "%imb", (int)((((uint64_t)hd_new_spt * (uint64_t)hd_new_hpc * (uint64_t)hd_new_cyl) * 512) / 1024) / 1024);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

		return TRUE;
	case WX_COMMAND:
		if (wParam == wxID_OK) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd_new_spt);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd_new_hpc);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd_new_cyl);

			if (hd_new_spt > 63) {
				wx_messagebox(hdlg, "Drive has too many sectors (maximum is 63)", "PCem error", WX_MB_OK);
				return TRUE;
			}
			if (hd_new_hpc > 16) {
				wx_messagebox(hdlg, "Drive has too many heads (maximum is 16)", "PCem error", WX_MB_OK);
				return TRUE;
			}
			if (hd_new_cyl > MAX_CYLINDERS) {
				char s[256];
				sprintf(s, "Drive has too many cylinders (maximum is %i)", MAX_CYLINDERS);
				wx_messagebox(hdlg, s, "PCem error", WX_MB_OK);
				return TRUE;
			}

			wx_enddialog(hdlg, 1);
			return TRUE;
		} else if (wParam == wxID_CANCEL) {
			wx_enddialog(hdlg, 0);
			return TRUE;
		} else if (ID_IS("IDC_EDIT1") || ID_IS("IDC_EDIT2") || ID_IS("IDC_EDIT3")) {
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd[0].spt);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd[0].hpc);
			h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3"));
			wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
			sscanf(s, "%i", &hd[0].tracks);

			h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT1"));
			sprintf(s, "%imb", (int)(((((uint64_t)hd[0].tracks * (uint64_t)hd[0].hpc) * (uint64_t)hd[0].spt) * 512) / 1024) / 1024);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
			return TRUE;
		}

	}
	return FALSE;
}

int hdconf_init(void *hdlg) {
	int c;

	for (c = 0; c < 7; c++) {
		char s[260];
		void *h;

		sprintf(s, "IDC_EDIT_SPT[%i]", c);
		h = wx_getdlgitem(hdlg, WX_ID(s));
		sprintf(s, "%i", hdc[c].spt);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		sprintf(s, "IDC_EDIT_HPC[%i]", c);
		h = wx_getdlgitem(hdlg, WX_ID(s));
		sprintf(s, "%i", hdc[c].hpc);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		sprintf(s, "IDC_EDIT_CYL[%i]", c);
		h = wx_getdlgitem(hdlg, WX_ID(s));
		sprintf(s, "%i", hdc[c].tracks);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		sprintf(s, "IDC_EDIT_FN[%i]", c);
		h = wx_getdlgitem(hdlg, WX_ID(s));
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)ide_fn[c]);

		sprintf(s, "IDC_TEXT_SIZE[%i]", c);
		h = wx_getdlgitem(hdlg, WX_ID(s));
		sprintf(s, "%imb", (int)(((((uint64_t)hdc[c].tracks * (uint64_t)hdc[c].hpc) * (uint64_t)hdc[c].spt) * 512) / 1024) / 1024);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

	}

	return hdconf_update(hdlg);
}

int hdconf_update(void *hdlg) {
	char s[260];
	void *h;

	int is_mfm = hdd_controller_selected_is_mfm(hdlg);

	update_hdd_cdrom(hdlg);

	int i;
	for (i = 0; i < 7; ++i) {
		sprintf(s, "IDC_HDD_LABEL[%d]", i * 10);
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !is_mfm);
		sprintf(s, "IDC_COMBODRIVETYPE[%d]", i);
		h = wx_getdlgitem(hdlg, WX_ID(s));
		wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !is_mfm);
	}

	h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREHDD"));
	if (hdd_controller_selected_has_config(hdlg))
		wx_enablewindow(h, TRUE);
	else
		wx_enablewindow(h, FALSE);

	return TRUE;
}

static int hd_eject(void *hdlg, int drive) {
	char s[80];

	ide_fn[drive][0] = 0;
	sprintf(s, "IDC_EDIT_SPT[%i]", drive);
	wx_setdlgitemtext(hdlg, WX_ID(s), "0");
	sprintf(s, "IDC_EDIT_HPC[%i]", drive);
	wx_setdlgitemtext(hdlg, WX_ID(s), "0");
	sprintf(s, "IDC_EDIT_CYL[%i]", drive);
	wx_setdlgitemtext(hdlg, WX_ID(s), "0");
	sprintf(s, "IDC_EDIT_FN[%i]", drive);
	wx_setdlgitemtext(hdlg, WX_ID(s), "");
	hd_changed = 1;

	return TRUE;
}

static int hd_new(void *hdlg, int drive) {
	if (wx_dialogbox(hdlg, "HdNewDlg", hdnew_dlgproc) == 1) {
		char s[80];
		char id[80];
		void *h;

		sprintf(id, "IDC_EDIT_SPT[%i]", drive);
		h = wx_getdlgitem(hdlg, WX_ID(id));
		sprintf(s, "%i", hd_new_spt);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		sprintf(id, "IDC_EDIT_HPC[%i]", drive);
		h = wx_getdlgitem(hdlg, WX_ID(id));
		sprintf(s, "%i", hd_new_hpc);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		sprintf(id, "IDC_EDIT_CYL[%i]", drive);
		h = wx_getdlgitem(hdlg, WX_ID(id));
		sprintf(s, "%i", hd_new_cyl);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
		sprintf(id, "IDC_EDIT_FN[%i]", drive);
		h = wx_getdlgitem(hdlg, WX_ID(id));
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)hd_new_name);

		sprintf(id, "IDC_TEXT_SIZE[%i]", drive);
		h = wx_getdlgitem(hdlg, WX_ID(id));
		sprintf(s, "%imb", (int)(((((uint64_t)hd_new_cyl * (uint64_t)hd_new_hpc) * (uint64_t)hd_new_spt) * 512) / 1024) / 1024);
		wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

		hd_changed = 1;
	}
	return TRUE;
}

static int hd_file(void *hdlg, int drive) {
	if (!getfile(hdlg, "Hard disc image (*.img;*.vhd)|*.img;*.vhd|All files (*.*)|*.*", "")) {
		off64_t sz;
		FILE *f = fopen64(openfilestring, "rb");
		if (!f) {
			wx_messagebox(hdlg, "Can't open file for read", "PCem error", WX_MB_OK);
			return TRUE;
		}

		if (mvhd_file_is_vhd(f)) {
			fclose(f);
			int vhdError = 0;
			MVHDMeta *vhd = mvhd_open(openfilestring, false, &vhdError);
			if (vhd == NULL) {
				wx_messagebox(hdlg, mvhd_strerr(vhdError), "PCem error", WX_MB_OK);
				return TRUE;
			} else if (vhdError == MVHD_ERR_TIMESTAMP) {
				const char ts_warning[] =
					"WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\n"
					"This could indicate that the parent image was modified after this VHD was created.\n\n"
					"This could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\n"
					"Do you wish to fix this error after a file copy or DiskPart creation?";
				int wx_res = wx_messagebox(hdlg, ts_warning, "PCem error", WX_MB_NODEFAULT);
				if (wx_res == WX_MB_YES) {
					int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhdError);
					if (ts_res != 0) {
						wx_messagebox(hdlg, "Can't fix VHD timestamps", "PCem error", WX_MB_OK);
						mvhd_close(vhd);
						return TRUE;
					}
				} else {
					mvhd_close(vhd);
					return TRUE;
				}

			}
			MVHDGeom geom = mvhd_get_geometry(vhd);
			hd_new_cyl = geom.cyl;
			hd_new_hpc = geom.heads;
			hd_new_spt = geom.spt;
			hd_new_type = 0;
			adjust_vhd_geometry_for_pcem();
			mvhd_close(vhd);
		} else {
			fseeko64(f, -1, SEEK_END);
			sz = ftello64(f) + 1;
			fclose(f);
			check_hd_type(hdlg, sz);
		}

		if (wx_dialogbox(hdlg, "HdSizeDlg", hdsize_dlgproc) == 1) {
			char s[80];
			char id[80];
			void *h;

			sprintf(id, "IDC_EDIT_SPT[%i]", drive);
			h = wx_getdlgitem(hdlg, WX_ID(id));
			sprintf(s, "%i", hd_new_spt);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
			sprintf(id, "IDC_EDIT_HPC[%i]", drive);
			h = wx_getdlgitem(hdlg, WX_ID(id));
			sprintf(s, "%i", hd_new_hpc);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
			sprintf(id, "IDC_EDIT_CYL[%i]", drive);
			h = wx_getdlgitem(hdlg, WX_ID(id));
			sprintf(s, "%i", hd_new_cyl);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);
			sprintf(id, "IDC_EDIT_FN[%i]", drive);
			h = wx_getdlgitem(hdlg, WX_ID(id));
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)openfilestring);

			sprintf(id, "IDC_TEXT_SIZE[%i]", drive);
			h = wx_getdlgitem(hdlg, WX_ID(id));
			sprintf(s, "%imb", (int)(((((uint64_t)hd_new_cyl * (uint64_t)hd_new_hpc) * (uint64_t)hd_new_spt) * 512) / 1024) / 1024);
			wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

			hd_changed = 1;
		}
	}
	return TRUE;
}

static int hd_edit(void *hdlg, int drive) {
	char s[80];
	char id[80];
	void *h;
	int spt, hpc, tracks;

	sprintf(id, "IDC_EDIT_SPT[%i]", drive);
	h = wx_getdlgitem(hdlg, WX_ID(id));
	wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
	sscanf(s, "%i", &spt);
	sprintf(id, "IDC_EDIT_HPC[%i]", drive);
	h = wx_getdlgitem(hdlg, WX_ID(id));
	wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
	sscanf(s, "%i", &hpc);
	sprintf(id, "IDC_EDIT_CYL[%i]", drive);
	h = wx_getdlgitem(hdlg, WX_ID(id));
	wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s);
	sscanf(s, "%i", &tracks);

	sprintf(id, "IDC_TEXT_SIZE[%i]", drive);
	h = wx_getdlgitem(hdlg, WX_ID(id));
	sprintf(s, "%imb", ((((tracks * hpc) * spt) * 512) / 1024) / 1024);
	wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s);

	return TRUE;
}

static int hd_combodrivetype(void *hdlg, int drive) {
	int type;
	char id[80];
	void *h;

	sprintf(id, "IDC_COMBODRIVETYPE[%i]", drive);
	h = wx_getdlgitem(hdlg, WX_ID(id));
	type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

	switch (type) {
	case 0: /*Hard drive*/
		if (new_cdrom_channel == drive)
			new_cdrom_channel = -1;
		if (new_zip_channel == drive)
			new_zip_channel = -1;
		break;
	case 1: /*CD-ROM*/
		new_cdrom_channel = drive;
		if (new_zip_channel == drive)
			new_zip_channel = -1;
		break;
	case 2: /*Zip*/
		new_zip_channel = drive;
		if (new_cdrom_channel == drive)
			new_cdrom_channel = -1;
		break;
	}
	update_hdd_cdrom(hdlg);
	return TRUE;
}

int hdconf_dlgproc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) {
	switch (message) {
	case WX_INITDIALOG:pause = 1;
		return hdconf_init(hdlg);

	case WX_COMMAND:
		if (ID_IS("IDC_EJECT[0]"))
			return hd_eject(hdlg, 0);
		else if (ID_IS("IDC_EJECT[1]"))
			return hd_eject(hdlg, 1);
		else if (ID_IS("IDC_EJECT[2]"))
			return hd_eject(hdlg, 2);
		else if (ID_IS("IDC_EJECT[3]"))
			return hd_eject(hdlg, 3);
		else if (ID_IS("IDC_EJECT[4]"))
			return hd_eject(hdlg, 4);
		else if (ID_IS("IDC_EJECT[5]"))
			return hd_eject(hdlg, 5);
		else if (ID_IS("IDC_EJECT[6]"))
			return hd_eject(hdlg, 6);
		else if (ID_IS("IDC_NEW[0]"))
			return hd_new(hdlg, 0);
		else if (ID_IS("IDC_NEW[1]"))
			return hd_new(hdlg, 1);
		else if (ID_IS("IDC_NEW[2]"))
			return hd_new(hdlg, 2);
		else if (ID_IS("IDC_NEW[3]"))
			return hd_new(hdlg, 3);
		else if (ID_IS("IDC_NEW[4]"))
			return hd_new(hdlg, 4);
		else if (ID_IS("IDC_NEW[5]"))
			return hd_new(hdlg, 5);
		else if (ID_IS("IDC_NEW[6]"))
			return hd_new(hdlg, 6);
		else if (ID_IS("IDC_FILE[0]"))
			return hd_file(hdlg, 0);
		else if (ID_IS("IDC_FILE[1]"))
			return hd_file(hdlg, 1);
		else if (ID_IS("IDC_FILE[2]"))
			return hd_file(hdlg, 2);
		else if (ID_IS("IDC_FILE[3]"))
			return hd_file(hdlg, 3);
		else if (ID_IS("IDC_FILE[4]"))
			return hd_file(hdlg, 4);
		else if (ID_IS("IDC_FILE[5]"))
			return hd_file(hdlg, 5);
		else if (ID_IS("IDC_FILE[6]"))
			return hd_file(hdlg, 6);
		else if (ID_IS("IDC_EDIT_SPT[0]") || ID_IS("IDC_EDIT_HPC[0]") || ID_IS("IDC_EDIT_CYL[0]"))
			return hd_edit(hdlg, 0);
		else if (ID_IS("IDC_EDIT_SPT[1]") || ID_IS("IDC_EDIT_HPC[1]") || ID_IS("IDC_EDIT_CYL[1]"))
			return hd_edit(hdlg, 1);
		else if (ID_IS("IDC_EDIT_SPT[2]") || ID_IS("IDC_EDIT_HPC[2]") || ID_IS("IDC_EDIT_CYL[2]"))
			return hd_edit(hdlg, 2);
		else if (ID_IS("IDC_EDIT_SPT[3]") || ID_IS("IDC_EDIT_HPC[3]") || ID_IS("IDC_EDIT_CYL[3]"))
			return hd_edit(hdlg, 3);
		else if (ID_IS("IDC_EDIT_SPT[4]") || ID_IS("IDC_EDIT_HPC[4]") || ID_IS("IDC_EDIT_CYL[4]"))
			return hd_edit(hdlg, 4);
		else if (ID_IS("IDC_EDIT_SPT[5]") || ID_IS("IDC_EDIT_HPC[5]") || ID_IS("IDC_EDIT_CYL[5]"))
			return hd_edit(hdlg, 5);
		else if (ID_IS("IDC_EDIT_SPT[6]") || ID_IS("IDC_EDIT_HPC[6]") || ID_IS("IDC_EDIT_CYL[6]"))
			return hd_edit(hdlg, 6);
		else if (ID_IS("IDC_COMBODRIVETYPE[0]"))
			return hd_combodrivetype(hdlg, 0);
		else if (ID_IS("IDC_COMBODRIVETYPE[1]"))
			return hd_combodrivetype(hdlg, 1);
		else if (ID_IS("IDC_COMBODRIVETYPE[2]"))
			return hd_combodrivetype(hdlg, 2);
		else if (ID_IS("IDC_COMBODRIVETYPE[3]"))
			return hd_combodrivetype(hdlg, 3);
		else if (ID_IS("IDC_COMBODRIVETYPE[4]"))
			return hd_combodrivetype(hdlg, 4);
		else if (ID_IS("IDC_COMBODRIVETYPE[5]"))
			return hd_combodrivetype(hdlg, 5);
		else if (ID_IS("IDC_COMBODRIVETYPE[6]"))
			return hd_combodrivetype(hdlg, 6);
	}
	return FALSE;
}

void config_change_page_index(void *hdlg, int index) {
	void *h;
	h = wx_getdlgitem(hdlg, WX_ID("IDC_NOTEBOOK"));
	wx_sendmessage(h, WX_SB_SETCURSEL, index, 0);

	if (index == 3)
		update_hdd_cdrom(hdlg);
}

int config_dialog_proc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) {
	switch (message) {
	case WX_INITDIALOG:pause = 1;
		eventBinder = wx_config_eventbinder(hdlg, config_change_page_index);
		return config_dlgproc(hdlg, message, wParam, lParam);
	case WX_COMMAND: {
		if (wParam == wxID_OK) {
			wx_config_destroyeventbinder(eventBinder);
			eventBinder = NULL;
			config_dlgsave(hdlg);
			pause = 0;
			wx_enddialog(hdlg, 1);
			return TRUE;
		} else if (wParam == wxID_CANCEL) {
			wx_config_destroyeventbinder(eventBinder);
			eventBinder = NULL;
			pause = 0;
			wx_enddialog(hdlg, 0);
			return TRUE;
		}
		break;
	}
	}
	config_dlgproc(hdlg, message, wParam, lParam);
	hdconf_dlgproc(hdlg, message, wParam, lParam);
	return TRUE;
}

int config_open(void *hwnd) {
	return wx_dialogbox(hwnd, "ConfigureDlg", config_dialog_proc);
}
