#include "wx-joystickconfig.h"

#include "wx-utils.h"
#include "wx/wxprec.h"

#include "wx-dialogbox.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "wx/xrc/xmlres.h"

extern "C" {
void pclog(const char *format, ...);
#include "config.h"
#include "device.h"
#include "gameport.h"
#include "plat-joystick.h"
}

#define IDC_CONFIG_BASE 1000

static int joystick_nr;
static int joystick_config_type;
#define AXIS_STRINGS_MAX 3
static char axis_strings[AXIS_STRINGS_MAX][10] = {"X Axis", "Y Axis", "Z Axis"};

static void rebuild_axis_button_selections(void *hdlg) {
	int id = IDC_CONFIG_BASE + 3;
	void *h;
	int joystick;
	int c, d;

	h = wx_getdlgitem(hdlg, IDC_CONFIG_BASE + 1);
	joystick = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

	for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) {
		int sel = c;

		h = wx_getdlgitem(hdlg, id);
		wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);

		if (joystick) {
			for (d = 0; d < plat_joystick_state[joystick - 1].nr_axes; d++) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)plat_joystick_state[joystick - 1].axis[d].name);
				if (c < AXIS_STRINGS_MAX) {
					if (!strcasecmp(axis_strings[c], plat_joystick_state[joystick - 1].axis[d].name))
						sel = d;
				}
			}
			for (d = 0; d < plat_joystick_state[joystick - 1].nr_povs; d++) {
				char s[80];

				sprintf(s, "%s (X axis)", plat_joystick_state[joystick - 1].pov[d].name);
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
				sprintf(s, "%s (Y axis)", plat_joystick_state[joystick - 1].pov[d].name);
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
			}
			wx_sendmessage(h, WX_CB_SETCURSEL, sel, 0);
			wx_enablewindow(h, TRUE);
		} else
			wx_enablewindow(h, FALSE);

		id += 2;
	}

	for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) {
		h = wx_getdlgitem(hdlg, id);
		wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);

		if (joystick) {
			for (d = 0; d < plat_joystick_state[joystick - 1].nr_buttons; d++)
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)plat_joystick_state[joystick - 1].button[d].name);
			wx_sendmessage(h, WX_CB_SETCURSEL, c, 0);
			wx_enablewindow(h, TRUE);
		} else
			wx_enablewindow(h, FALSE);

		id += 2;
	}

	for (c = 0; c < joystick_get_pov_count(joystick_config_type) * 2; c++) {
		int sel = c;

		h = wx_getdlgitem(hdlg, id);
		wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0);

		if (joystick) {
			for (d = 0; d < plat_joystick_state[joystick - 1].nr_povs; d++) {
				char s[80];

				sprintf(s, "%s (X axis)", plat_joystick_state[joystick - 1].pov[d].name);
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
				sprintf(s, "%s (Y axis)", plat_joystick_state[joystick - 1].pov[d].name);
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s);
			}
			for (d = 0; d < plat_joystick_state[joystick - 1].nr_axes; d++) {
				wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)plat_joystick_state[joystick - 1].axis[d].name);
			}
			wx_sendmessage(h, WX_CB_SETCURSEL, sel, 0);
			wx_enablewindow(h, TRUE);
		} else
			wx_enablewindow(h, FALSE);

		id += 2;
	}

}

static int get_axis(void *hdlg, int id) {
	void *h = wx_getdlgitem(hdlg, id);
	int axis_sel = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_axes;

	if (axis_sel < nr_axes)
		return axis_sel;

	axis_sel -= nr_axes;
	if (axis_sel & 1)
		return POV_Y | (axis_sel >> 1);
	else
		return POV_X | (axis_sel >> 1);
}

static int get_pov(void *hdlg, int id) {
	void *h = wx_getdlgitem(hdlg, id);
	int axis_sel = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
	int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_povs * 2;

	if (axis_sel < nr_povs) {
		if (axis_sel & 1)
			return POV_Y | (axis_sel >> 1);
		else
			return POV_X | (axis_sel >> 1);
	}

	return axis_sel - nr_povs;
}

static int joystickconfig_dlgproc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) {
	switch (message) {
	case WX_INITDIALOG: {
//                        rebuild_axis_button_selections(hdlg);

		void *h = wx_getdlgitem(hdlg, IDC_CONFIG_BASE + 1);
		int c;
		int id = IDC_CONFIG_BASE + 3;
		int joystick = joystick_state[joystick_nr].plat_joystick_nr;

		wx_sendmessage(h, WX_CB_SETCURSEL, joystick, 0);

		rebuild_axis_button_selections(hdlg);

		if (joystick_state[joystick_nr].plat_joystick_nr) {
			int nr_axes = plat_joystick_state[joystick - 1].nr_axes;
			int nr_povs = plat_joystick_state[joystick - 1].nr_povs;
			for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) {
				int mapping = joystick_state[joystick_nr].axis_mapping[c];

				h = wx_getdlgitem(hdlg, id);
				if (mapping & POV_X)
					wx_sendmessage(h, WX_CB_SETCURSEL, nr_axes + (mapping & 3) * 2, 0);
				else if (mapping & POV_Y)
					wx_sendmessage(h, WX_CB_SETCURSEL, nr_axes + (mapping & 3) * 2 + 1, 0);
				else
					wx_sendmessage(h, WX_CB_SETCURSEL, mapping, 0);
				id += 2;
			}
			for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) {
				h = wx_getdlgitem(hdlg, id);
				wx_sendmessage(h, WX_CB_SETCURSEL, joystick_state[joystick_nr].button_mapping[c], 0);
				id += 2;
			}
			for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) {
				int mapping;

				h = wx_getdlgitem(hdlg, id);
				mapping = joystick_state[joystick_nr].pov_mapping[c][0];
				if (mapping & POV_X)
					wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3) * 2, 0);
				else if (mapping & POV_Y)
					wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3) * 2 + 1, 0);
				else
					wx_sendmessage(h, WX_CB_SETCURSEL, mapping + nr_povs * 2, 0);
				id += 2;
				h = wx_getdlgitem(hdlg, id);
				mapping = joystick_state[joystick_nr].pov_mapping[c][1];
				if (mapping & POV_X)
					wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3) * 2, 0);
				else if (mapping & POV_Y)
					wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3) * 2 + 1, 0);
				else
					wx_sendmessage(h, WX_CB_SETCURSEL, mapping + nr_povs * 2, 0);
				id += 2;
			}
		}
	}
		return TRUE;

	case WX_COMMAND:
		switch (wParam) {
		case IDC_CONFIG_BASE + 1:
//                        if (HIWORD(wParam) == CBN_SELCHANGE)
			rebuild_axis_button_selections(hdlg);
			break;

		case wxID_OK: {
			void *h;
			int c;
			int id = IDC_CONFIG_BASE + 3;

			h = wx_getdlgitem(hdlg, IDC_CONFIG_BASE + 1);
			joystick_state[joystick_nr].plat_joystick_nr = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);

			if (joystick_state[joystick_nr].plat_joystick_nr) {
				for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) {
					joystick_state[joystick_nr].axis_mapping[c] = get_axis(hdlg, id);
					id += 2;
				}
				for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) {
					h = wx_getdlgitem(hdlg, id);
					joystick_state[joystick_nr].button_mapping[c] = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0);
					id += 2;
				}
				for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) {
					h = wx_getdlgitem(hdlg, id);
					joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(hdlg, id);
					id += 2;
					h = wx_getdlgitem(hdlg, id);
					joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(hdlg, id);
					id += 2;
				}
			}
		}
		case wxID_CANCEL:wx_enddialog(hdlg, 0);
			return TRUE;
		}
		break;
	}
	return FALSE;
}

void joystickconfig_open(void *hwnd, int joy_nr, int type) {
	char s[257];
	int c;

	PCemDialogBox dialog((wxWindow *)hwnd, joystickconfig_dlgproc);
//	dialog.SetWindowStyle(wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);

	joystick_nr = joy_nr;
	joystick_config_type = type;

	dialog.SetTitle("Joystick Configuration");

	wxFlexGridSizer *root = new wxFlexGridSizer(0, 1, 0, 0);
	root->SetFlexibleDirection(wxBOTH);
	root->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
	dialog.SetSizer(root);

	wxFlexGridSizer *sizer = new wxFlexGridSizer(0, 2, 0, 0);
	sizer->SetFlexibleDirection(wxBOTH);
	sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
	sizer->AddGrowableCol(1);
	root->Add(sizer, 1, wxEXPAND, 5);

	int id = IDC_CONFIG_BASE;

	sizer->Add(new wxStaticText(&dialog, id++, "Device:"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
	wxBoxSizer *comboSizer = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(comboSizer, 1, wxEXPAND, 5);
	wxComboBox *cb = new wxComboBox(&dialog, id++);
	cb->SetEditable(false);
	comboSizer->Add(cb, 1, wxALL, 5);

	cb->Append("None");
	for (c = 0; c < joysticks_present; c++)
		cb->Append(plat_joystick_state[c].name);

	for (c = 0; c < joystick_get_axis_count(type); c++) {
		sprintf(s, "Axis %i:", c);
		sizer->Add(new wxStaticText(&dialog, id++, s), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
		wxBoxSizer *comboSizer = new wxBoxSizer(wxHORIZONTAL);
		sizer->Add(comboSizer, 1, wxEXPAND, 5);
		wxComboBox *cb = new wxComboBox(&dialog, id++);
		cb->SetEditable(false);
		comboSizer->Add(cb, 1, wxALL, 5);
	}

	for (c = 0; c < joystick_get_button_count(type); c++) {
		sprintf(s, "Button %i:", c);
		sizer->Add(new wxStaticText(&dialog, id++, s), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
		wxBoxSizer *comboSizer = new wxBoxSizer(wxHORIZONTAL);
		sizer->Add(comboSizer, 1, wxEXPAND, 5);
		wxComboBox *cb = new wxComboBox(&dialog, id++);
		cb->SetEditable(false);
		comboSizer->Add(cb, 1, wxALL, 5);
	}

	for (c = 0; c < joystick_get_pov_count(type) * 2; c++) {
		sprintf(s, "POV %i:", c);
		sizer->Add(new wxStaticText(&dialog, id++, s), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
		wxBoxSizer *comboSizer = new wxBoxSizer(wxHORIZONTAL);
		sizer->Add(comboSizer, 1, wxEXPAND, 5);
		wxComboBox *cb = new wxComboBox(&dialog, id++);
		cb->SetEditable(false);
		comboSizer->Add(cb, 1, wxALL, 5);
	}

	wxBoxSizer *okCancelSizer = new wxBoxSizer(wxHORIZONTAL);
	root->Add(okCancelSizer, 1, wxEXPAND, 5);

	okCancelSizer->Add(0, 0, 1, wxEXPAND, 5);
	okCancelSizer->Add(new wxButton(&dialog, wxID_OK), 0, wxALL, 5);
	okCancelSizer->Add(new wxButton(&dialog, wxID_CANCEL), 0, wxALL, 5);

	dialog.Fit();
	dialog.OnInit();
	dialog.ShowModal();
	dialog.Destroy();
}
