/*Arculator 2.1 by Sarah Walker
  Joystick configuration dialogue
  This handles configuration of host joystick -> emulated joystick mappings*/
#include <stdint.h>
#include <wx/wxprec.h>

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include <wx/xrc/xmlres.h>
#include "wx-joystick-config.h"

extern "C" {
void rpclog(const char *format, ...);
#include "config.h"
#include "joystick.h"
#include "plat_joystick.h"
}

#define IDC_CONFIG_BASE 1000

class JoystickConfDialog: public wxDialog
{
public:
	JoystickConfDialog(wxWindow *parent, int joy_nr, int type);
	void OnInit();

private:
	void OnOK(wxCommandEvent &event);
	void OnCancel(wxCommandEvent &event);

	void OnDevice(wxCommandEvent &event);

	void rebuild_axis_button_selections();
	int get_axis(int id);
	int get_pov(int id);

	int joy_device;
	int joystick_nr;
	int joystick_config_type;
};

#define AXIS_STRINGS_MAX 3
static const char *axis_strings[AXIS_STRINGS_MAX] = {"X Axis", "Y Axis", "Z Axis"};


void JoystickConfDialog::rebuild_axis_button_selections()
{
	int id = IDC_CONFIG_BASE + 3;
	int c, d;

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

		wxComboBox *cbox = (wxComboBox *)this->FindWindow(id);
		cbox->Clear();

		if (joy_device)
		{
			for (d = 0; d < plat_joystick_state[joy_device-1].nr_axes; d++)
			{
				cbox->Append(plat_joystick_state[joy_device-1].axis[d].name);
				if (c < AXIS_STRINGS_MAX)
				{
					if (!strcasecmp(axis_strings[c], plat_joystick_state[joy_device-1].axis[d].name))
						sel = d;
				}
			}
			for (d = 0; d < plat_joystick_state[joy_device-1].nr_povs; d++)
			{
				char s[80];

				sprintf(s, "%s (X axis)", plat_joystick_state[joy_device-1].pov[d].name);
				cbox->Append(s);
				sprintf(s, "%s (Y axis)", plat_joystick_state[joy_device-1].pov[d].name);
				cbox->Append(s);
			}
			cbox->SetSelection(sel);
			cbox->Enable(true);
		}
		else
			cbox->Enable(false);

		id += 2;
	}

	for (c = 0; c < joystick_get_button_count(joystick_config_type); c++)
	{
		wxComboBox *cbox = (wxComboBox *)this->FindWindow(id);
		cbox->Clear();

		if (joy_device)
		{
			for (d = 0; d < plat_joystick_state[joy_device-1].nr_buttons; d++)
				cbox->Append(plat_joystick_state[joy_device-1].button[d].name);
			cbox->SetSelection(c);
			cbox->Enable(true);
		}
		else
			cbox->Enable(false);

		id += 2;
	}

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

		wxComboBox *cbox = (wxComboBox *)this->FindWindow(id);
		cbox->Clear();

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

				sprintf(s, "%s (X axis)", plat_joystick_state[joy_device-1].pov[d].name);
				cbox->Append(s);
				sprintf(s, "%s (Y axis)", plat_joystick_state[joy_device-1].pov[d].name);
				cbox->Append(s);
			}
			for (d = 0; d < plat_joystick_state[joy_device-1].nr_axes; d++)
				cbox->Append(plat_joystick_state[joy_device-1].axis[d].name);
			cbox->SetSelection(sel);
			cbox->Enable(true);
		}
		else
			cbox->Enable(false);

		id += 2;
	}

}

int JoystickConfDialog::get_axis(int id)
{
	wxComboBox *cbox = (wxComboBox *)this->FindWindow(id);
	int axis_sel = cbox->GetCurrentSelection();
	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);
}

int JoystickConfDialog::get_pov(int id)
{
	wxComboBox *cbox = (wxComboBox *)this->FindWindow(id);
	int axis_sel = cbox->GetCurrentSelection();
	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;
}

void JoystickConfDialog::OnInit()
{
	wxComboBox *cbox = (wxComboBox *)this->FindWindow(IDC_CONFIG_BASE+1);
	int c;
	int id = IDC_CONFIG_BASE + 3;
	int joystick = joystick_state[joystick_nr].plat_joystick_nr;

	cbox->SetSelection(joystick);
	joy_device = joystick;

	rebuild_axis_button_selections();

	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];

			cbox = (wxComboBox *)this->FindWindow(id);
			if (mapping & POV_X)
				cbox->SetSelection(nr_axes + (mapping & 3)*2);
			else if (mapping & POV_Y)
				cbox->SetSelection(nr_axes + (mapping & 3)*2 + 1);
			else
				cbox->SetSelection(mapping);
			id += 2;
		}
		for (c = 0; c < joystick_get_button_count(joystick_config_type); c++)
		{
			cbox = (wxComboBox *)this->FindWindow(id);
			cbox->SetSelection(joystick_state[joystick_nr].button_mapping[c]);
			id += 2;
		}
		for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++)
		{
			int mapping;

			cbox = (wxComboBox *)this->FindWindow(id);
			mapping = joystick_state[joystick_nr].pov_mapping[c][0];
			if (mapping & POV_X)
				cbox->SetSelection((mapping & 3)*2);
			else if (mapping & POV_Y)
				cbox->SetSelection((mapping & 3)*2 + 1);
			else
				cbox->SetSelection(mapping + nr_povs*2);
			id += 2;
			cbox = (wxComboBox *)this->FindWindow(id);
			mapping = joystick_state[joystick_nr].pov_mapping[c][1];
			if (mapping & POV_X)
				cbox->SetSelection((mapping & 3)*2);
			else if (mapping & POV_Y)
				cbox->SetSelection((mapping & 3)*2 + 1);
			else
				cbox->SetSelection(mapping + nr_povs*2);
			id += 2;
		}
	}
}

void JoystickConfDialog::OnOK(wxCommandEvent &event)
{
	int c;
	int id = IDC_CONFIG_BASE + 3;
	wxComboBox *cbox = (wxComboBox *)this->FindWindow(IDC_CONFIG_BASE+1);

	joystick_state[joystick_nr].plat_joystick_nr = cbox->GetCurrentSelection();

	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(id);
			id += 2;
		}
		for (c = 0; c < joystick_get_button_count(joystick_config_type); c++)
		{
			cbox = (wxComboBox *)this->FindWindow(id);
			joystick_state[joystick_nr].button_mapping[c] = cbox->GetCurrentSelection();
			id += 2;
		}
		for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++)
		{
			joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(id);
			id += 2;
			joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(id);
			id += 2;
		}
	}

	EndModal(0);
}
void JoystickConfDialog::OnCancel(wxCommandEvent &event)
{
	EndModal(0);
}

void JoystickConfDialog::OnDevice(wxCommandEvent &event)
{
	wxComboBox *cbox = dynamic_cast<wxComboBox *>(event.GetEventObject());
	joy_device = cbox->GetCurrentSelection();

	rebuild_axis_button_selections();
}


JoystickConfDialog::JoystickConfDialog(wxWindow *parent, int joy_nr, int type) :
	wxDialog(parent, -1, "Configure joystick"),
	joystick_nr(joy_nr),
	joystick_config_type(type)
{
	char s[257];
	int c;

	wxFlexGridSizer* root = new wxFlexGridSizer(0, 1, 0, 0);
	root->SetFlexibleDirection(wxBOTH);
	root->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
	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(this, id++, "Device:"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
	wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(comboSizer, 1, wxEXPAND, 5);
	wxComboBox* cb = new wxComboBox(this, id++);
	cb->SetEditable(false);
	comboSizer->Add(cb, 1, wxALL, 5);
	Bind(wxEVT_COMBOBOX, &JoystickConfDialog::OnDevice, this, id-1);

	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++)
	{
		sizer->Add(new wxStaticText(this, id++, joystick_get_axis_name(type, c)), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
		wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL);
		sizer->Add(comboSizer, 1, wxEXPAND, 5);
		wxComboBox* cb = new wxComboBox(this, 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(this, id++, joystick_get_button_name(type, c)), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
		wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL);
		sizer->Add(comboSizer, 1, wxEXPAND, 5);
		wxComboBox* cb = new wxComboBox(this, 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(this, id++, joystick_get_pov_name(type, c)), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
		wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL);
		sizer->Add(comboSizer, 1, wxEXPAND, 5);
		wxComboBox* cb = new wxComboBox(this, 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(this, wxID_OK), 0, wxALL, 5);
	okCancelSizer->Add(new wxButton(this, wxID_CANCEL), 0, wxALL, 5);

	Bind(wxEVT_BUTTON, &JoystickConfDialog::OnOK, this, wxID_OK);
	Bind(wxEVT_BUTTON, &JoystickConfDialog::OnCancel, this, wxID_CANCEL);
}

void ShowConfJoy(wxWindow *parent, int joy_nr, int type)
{
	rpclog("joysticks_present=%i\n", joysticks_present);
	JoystickConfDialog dlg(parent, joy_nr, type);

	dlg.Fit();
	dlg.OnInit();
	dlg.ShowModal();
}
