#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, off_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 = fopen(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 disk image (*.img;*.vhd)|*.img;*.vhd|RAM disk image (*.rdimg;*.rdvhd)|*.rdimg;*.rdvhd|All files (*.*)|*.*", "")) {
                off_t sz;
                FILE *f = fopen(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); }
