/*Arculator 2.1 by Sarah Walker
  Hard disc configuration dialogue*/
#include <wx/wxprec.h>

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

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

static int MAX_CYLINDERS = 1024;
static int MAX_HEADS = 16;
static int MIN_SECTORS = 1;
static int MAX_SECTORS = 63;
static int SECTOR_SIZE = 512;
#define MAX_SIZE ((MAX_CYLINDERS * MAX_HEADS * MAX_SECTORS) / (1024 * 1024 / SECTOR_SIZE))

class HDConfDialog: public wxDialog
{
public:
	HDConfDialog(wxWindow *parent, int new_sectors, int new_heads, int new_cylinders);

	int new_sectors;
	int new_heads;
	int new_cylinders;

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

	void OnCHS(wxCommandEvent &event);
	void OnSize(wxCommandEvent &event);
};

HDConfDialog::HDConfDialog(wxWindow *parent, int new_sectors, int new_heads, int new_cylinders) :
		new_sectors(new_sectors),
		new_heads(new_heads),
		new_cylinders(new_cylinders)
{
	char temp_s[80];

	wxXmlResource::Get()->LoadDialog(this, parent, "HdConfDlg");

	Bind(wxEVT_BUTTON, &HDConfDialog::OnOK, this, wxID_OK);
	Bind(wxEVT_BUTTON, &HDConfDialog::OnCancel, this, wxID_CANCEL);
	Bind(wxEVT_TEXT, &HDConfDialog::OnCHS, this, XRCID("IDC_EDIT_SECTORS"));
	Bind(wxEVT_TEXT, &HDConfDialog::OnCHS, this, XRCID("IDC_EDIT_HEADS"));
	Bind(wxEVT_TEXT, &HDConfDialog::OnCHS, this, XRCID("IDC_EDIT_CYLINDERS"));
	Bind(wxEVT_TEXT, &HDConfDialog::OnSize, this, XRCID("IDC_EDIT_SIZE"));

	sprintf(temp_s, "%i", new_sectors);
	((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SECTORS")))->SetValue(temp_s);
	sprintf(temp_s, "%i", new_heads);
	((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_HEADS")))->SetValue(temp_s);
	sprintf(temp_s, "%i", new_cylinders);
	((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_CYLINDERS")))->SetValue(temp_s);
}

void HDConfDialog::OnOK(wxCommandEvent &event)
{
	wxString temp_s;

	temp_s = ((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_CYLINDERS")))->GetValue();
	new_cylinders = atoi(temp_s);
	temp_s = ((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_HEADS")))->GetValue();
	new_heads = atoi(temp_s);
	temp_s = ((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SECTORS")))->GetValue();
	new_sectors = atoi(temp_s);

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

static bool in_callback = false;

void HDConfDialog::OnCHS(wxCommandEvent &event)
{
	wxString temp_s;
	char size_s[80];
	int cylinders, heads, sectors;
	int size;

	if (in_callback)
		return;
	in_callback = true;

	temp_s = ((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_CYLINDERS")))->GetValue();
	cylinders = atoi(temp_s);
	if (cylinders > MAX_CYLINDERS)
	{
		cylinders = MAX_CYLINDERS;
		snprintf(size_s, sizeof(size_s), "%i", cylinders);
		((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_CYLINDERS")))->SetValue(size_s);
	}

	temp_s = ((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_HEADS")))->GetValue();
	heads = atoi(temp_s);
	if (heads > MAX_HEADS)
	{
		heads = MAX_HEADS;
		snprintf(size_s, sizeof(size_s), "%i", heads);
		((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_HEADS")))->SetValue(size_s);
	}

	temp_s = ((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SECTORS")))->GetValue();
	sectors = atoi(temp_s);
	if (sectors > MAX_SECTORS)
	{
		sectors = MAX_SECTORS;
		snprintf(size_s, sizeof(size_s), "%i", sectors);
		((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SECTORS")))->SetValue(size_s);

	}
	else if (sectors < MIN_SECTORS)
	{
		sectors = MIN_SECTORS;
		snprintf(size_s, sizeof(size_s), "%i", sectors);
		((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SECTORS")))->SetValue(size_s);

	}

	size = (cylinders * heads * sectors) / (1024 * 1024 / SECTOR_SIZE);
	snprintf(size_s, sizeof(size_s), "%i", size);
	((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SIZE")))->SetValue(size_s);

	in_callback = false;
}

void HDConfDialog::OnSize(wxCommandEvent &event)
{
	wxString temp_s;
	char size_s[80];
	int cylinders, heads, sectors;
	int size;

	if (in_callback)
		return;
	in_callback = true;

	temp_s = ((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SIZE")))->GetValue();
	size = atoi(temp_s);
	if (size > MAX_SIZE)
	{
		size = MAX_SIZE;
		snprintf(size_s, sizeof(size_s), "%i", size);
		((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SIZE")))->SetValue(size_s);
	}

	heads = MAX_HEADS;
	sectors = MAX_SECTORS;
	cylinders = (size * (1024 * 1024 / SECTOR_SIZE)) / (MAX_HEADS * MAX_SECTORS);

	snprintf(size_s, sizeof(size_s), "%i", cylinders);
	((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_CYLINDERS")))->SetValue(size_s);
	snprintf(size_s, sizeof(size_s), "%i", heads);
	((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_HEADS")))->SetValue(size_s);
	snprintf(size_s, sizeof(size_s), "%i", sectors);
	((wxTextCtrl *)this->FindWindow(XRCID("IDC_EDIT_SECTORS")))->SetValue(size_s);

	in_callback = false;
}

int ShowConfHD(wxWindow *parent, int *new_sectors, int *new_heads, int *new_cylinders, char *new_fn, bool is_st506)
{
	if (is_st506)
	{
		MAX_CYLINDERS = 1024;
		MAX_HEADS = 8;
		MIN_SECTORS = 32;
		MAX_SECTORS = 32;
		SECTOR_SIZE = 256;
	}
	else
	{
		MAX_CYLINDERS = 1024;
		MAX_HEADS = 16;
		MIN_SECTORS = 1;
		MAX_SECTORS = 63;
		SECTOR_SIZE = 512;
	}

	FILE *f = fopen(new_fn, "rb");
	if (!f)
	{
		wxMessageBox("Could not access file", "Arculator", wxOK | wxCENTRE | wxSTAY_ON_TOP | wxICON_ERROR, parent);
		return 0;
	}

	fseek(f, -1, SEEK_END);
	int filesize = ftell(f) + 1;
	fseek(f, 0, SEEK_SET);

	int log2secsize, density;

	/*Try to detect drive size geometry disc record. Valid disc record
	  will have log2secsize of 8 (256 bytes per sector) or 9 (512
	  bytes per sector), density of 0, and sector and head counts
	  within valid range*/
	/*Initially assume stupid 512 byte header created by RPCemu and
	  older Arculator*/
	fseek(f, 0xFC0, SEEK_SET);
	log2secsize = getc(f);
	*new_sectors = getc(f);
	*new_heads = getc(f);
	density = getc(f);

	if ((log2secsize != 8 && log2secsize != 9) || !(*new_sectors) || !(*new_heads) || (*new_sectors) > MAX_SECTORS || (*new_heads) > MAX_HEADS || density != 0)
	{
		/*Invalid geometry, try without header*/
		fseek(f, 0xDC0, SEEK_SET);
		log2secsize = getc(f);
		*new_sectors = getc(f);
		*new_heads = getc(f);
		density = getc(f);

		if ((log2secsize != 8 && log2secsize != 9) || !(*new_sectors) || !(*new_heads) || (*new_sectors) > MAX_SECTORS || (*new_heads) > MAX_HEADS || density != 0)
		{
			/*Invalid geometry, assume max*/
			*new_sectors = MAX_SECTORS;
			*new_heads = MAX_HEADS;
		}
	}
	else
		filesize -= 512; /*Account for header*/

	fclose(f);

//                rpclog("sectors=%i, heads=%i\n", new_sectors, new_heads);
	*new_cylinders = filesize / (SECTOR_SIZE * *new_sectors * *new_heads);

	HDConfDialog dlg(parent, *new_sectors, *new_heads, *new_cylinders);

	dlg.Fit();
	if (dlg.ShowModal())
	{
		*new_sectors = dlg.new_sectors;
		*new_heads = dlg.new_heads;
		*new_cylinders = dlg.new_cylinders;

		return 1;
	}
	else
		return 0;
}
