#ifdef _WIN32
#define BITMAP WINDOWS_BITMAP
#include <windows.h>
#include <windowsx.h>
#undef BITMAP
#endif

#ifdef USE_PCAP_NETWORKING
#include <pcap.h>
#endif

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

#include "ibm.h"
#include "config.h"
#include "nethandler.h"

#ifdef USE_PCAP_NETWORKING
static pcap_if_t *alldevs;
static char *dev_name[20];
#endif

#define ETH_DEV_NAME_MAX 256 /* maximum device name size */
#define ETH_DEV_DESC_MAX 256 /* maximum device description size */
#define ETH_MAX_DEVICE 30    /* maximum ethernet devices */
#define ETH_PROMISC 1        /* promiscuous mode = true */
#define ETH_MAX_PACKET 1514  /* maximum ethernet packet size */
#define PCAP_READ_TIMEOUT -1

#ifdef USE_PCAP_NETWORKING
static int get_network_name(char *dev_name, char *regval) {
#if _WIN32
        if (dev_name[strlen("\\Device\\NPF_")] == '{') {
                char regkey[2048];
                HKEY reghnd;

                sprintf(regkey,
                        "SYSTEM\\CurrentControlSet\\Control\\Network\\"
                        "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",
                        dev_name + strlen("\\Device\\NPF_"));

                if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, &reghnd) == ERROR_SUCCESS) {
                        DWORD reglen = 2048;
                        DWORD regtype;

                        if (RegQueryValueExA(reghnd, "Name", NULL, &regtype, (LPBYTE)regval, &reglen) == ERROR_SUCCESS) {
                                RegCloseKey(reghnd);

                                if ((regtype != REG_SZ) || (reglen > 2048))
                                        return -1;

                                /*Name now in regval*/
                                return 0;
                        }
                        RegCloseKey(reghnd);
                }
        }
#endif
        return -1;
}
#endif
int hostconfig_dialog_proc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) {
        void *h;
#ifdef USE_PCAP_NETWORKING
        pcap_if_t *dev;
        char errbuf[PCAP_ERRBUF_SIZE];
#endif

        switch (message) {
        case WX_INITDIALOG:
                h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE"));
                wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "SLiRP");
                wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
                h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE"));
                wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0);
                wx_enablewindow(h, FALSE);
#ifdef USE_PCAP_NETWORKING

                int c = 0;
                int match = 0;

                if (pcap_findalldevs(&alldevs, errbuf) != -1) {
                        char *pcap_device = config_get_string(CFG_GLOBAL, NULL, "pcap_device", "nothing");

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

                        for (dev = alldevs; dev; dev = dev->next) {
                                pcap_t *conn = pcap_open_live(dev->name, ETH_MAX_PACKET, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
                                int datalink = 0;

                                if (conn) {
                                        datalink = pcap_datalink(conn);
                                        pcap_close(conn);
                                }

                                if (conn && datalink == DLT_EN10MB) {
                                        char desc[2048];
                                        char s[2048];

                                        if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name)))
                                                continue;

                                        if (pcap_device) {
                                                if (!strcmp(pcap_device, dev->name))
                                                        match = c;
                                        }

                                        dev_name[c++] = dev->name;
                                        if (get_network_name(dev->name, desc))
                                                wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)dev->name);
                                        else {
                                                sprintf(s, "%s - %s", dev->name, desc);
                                                wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
                                        }
                                }
                        }
                }
                if (c) {
                        h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE"));
                        wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "PCAP");

                        if (config_get_int(CFG_GLOBAL, NULL, "net_type", NET_SLIRP) == NET_PCAP) {
                                wx_sendmessage(h, WX_CB_SETCURSEL, 1, 0);
                                h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE"));
                                wx_sendmessage(h, WX_CB_SETCURSEL, match, 0);
                                wx_enablewindow(h, TRUE);
                        }
                }

#endif
                return TRUE;

        case WX_COMMAND:
                if (wParam == wxID_OK) {
                        int type;

                        h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE"));
                        type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
#ifdef USE_PCAP_NETWORKING
                        if (type) /*PCAP*/
                        {
                                int dev;

                                h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE"));
                                dev = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

                                config_set_int(CFG_GLOBAL, NULL, "net_type", NET_PCAP);
                                config_set_string(CFG_GLOBAL, NULL, "pcap_device", dev_name[dev]);
                        } else /*SLiRP*/
                        {
#endif
                                config_set_int(CFG_GLOBAL, NULL, "net_type", NET_SLIRP);
                                config_set_string(CFG_GLOBAL, NULL, "pcap_device", "nothing");
#ifdef USE_PCAP_NETWORKING
                        }
#endif
                        saveconfig_global_only();

                        wx_enddialog(hdlg, 1);

                        return TRUE;
                } else if (wParam == wxID_CANCEL) {
                        wx_enddialog(hdlg, 0);

                        return TRUE;
                } else if (ID_IS("IDC_COMBO_NETWORK_TYPE")) {
                        int type;

                        h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE"));
                        type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
                        h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE"));
                        if (!type)
                                wx_enablewindow(h, FALSE);
                        else
                                wx_enablewindow(h, TRUE);

                        return TRUE;
                }
                break;
        }

        return TRUE;
}

int hostconfig_open(void *hwnd) { return wx_dialogbox(hwnd, "HostConfig", hostconfig_dialog_proc); }
