/*
 * CiderPress
 * Copyright (C) 2007 by faddenSoft, LLC.  All Rights Reserved.
 * See the file LICENSE for distribution terms.
 */
/*
 * Support for ConvDiskOptionsDialog.
 */
#include "stdafx.h"
#include "CreateImageDialog.h"
#include "NewDiskSize.h"
#include "HelpTopics.h"
#include "../diskimg/DiskImgDetail.h"		// need ProDOS filename validator

BEGIN_MESSAGE_MAP(CreateImageDialog, CDialog)
	ON_WM_HELPINFO()
	ON_COMMAND(IDHELP, OnHelp)
	ON_CONTROL_RANGE(BN_CLICKED, IDC_CREATEFS_DOS32, IDC_CREATEFS_BLANK,
		OnFormatChangeRange)
	ON_CONTROL_RANGE(BN_CLICKED, IDC_CONVDISK_140K, IDC_CONVDISK_SPECIFY,
		OnSizeChangeRange)
END_MESSAGE_MAP()



const int kProDOSVolNameMax = 15;		// longest possible ProDOS volume name
const int kPascalVolNameMax = 7;		// longest possible Pascal volume name
const int kHFSVolNameMax = 27;			// longest possible HFS volume name
const long kMaxBlankBlocks = 16777216;	// 8GB in 512-byte blocks

/*
 * Set up our modified version of the "use selection" dialog.
 */
BOOL
CreateImageDialog::OnInitDialog(void)
{
	// high bit set in signed short means key is down
	if (::GetKeyState(VK_SHIFT) < 0) {
		WMSG0("Shift key is down, enabling extended options\n");
		fExtendedOpts = true;
	}

	CEdit* pEdit = (CEdit*) GetDlgItem(IDC_CREATEFSPRODOS_VOLNAME);
	ASSERT(pEdit != nil);
	pEdit->SetLimitText(kProDOSVolNameMax);

	pEdit = (CEdit*) GetDlgItem(IDC_CREATEFSPASCAL_VOLNAME);
	ASSERT(pEdit != nil);
	pEdit->SetLimitText(kPascalVolNameMax);

	pEdit = (CEdit*) GetDlgItem(IDC_CREATEFSHFS_VOLNAME);
	ASSERT(pEdit != nil);
	pEdit->SetLimitText(kHFSVolNameMax);

	pEdit = (CEdit*) GetDlgItem(IDC_CREATEFSDOS_VOLNUM);
	ASSERT(pEdit != nil);
	pEdit->SetLimitText(3);		// 3 digit volume number

	pEdit = (CEdit*) GetDlgItem(IDC_CONVDISK_SPECIFY_EDIT);
	ASSERT(pEdit != nil);
	pEdit->EnableWindow(FALSE);

	return CDialog::OnInitDialog();
}

/*
 * Convert values.
 */
void
CreateImageDialog::DoDataExchange(CDataExchange* pDX)
{
	UINT specifyBlocks = 280;
	CString errMsg;

	DDX_Radio(pDX, IDC_CONVDISK_140K, fDiskSizeIdx);
	DDX_Radio(pDX, IDC_CREATEFS_DOS32, fDiskFormatIdx);
	DDX_Check(pDX, IDC_CREATEFSDOS_ALLOCDOS, fAllocTracks_DOS);
	DDX_Text(pDX, IDC_CREATEFSDOS_VOLNUM, fDOSVolumeNum);
	DDX_Text(pDX, IDC_CREATEFSPRODOS_VOLNAME, fVolName_ProDOS);
	DDX_Text(pDX, IDC_CREATEFSPASCAL_VOLNAME, fVolName_Pascal);
	DDX_Text(pDX, IDC_CREATEFSHFS_VOLNAME, fVolName_HFS);
	DDX_Text(pDX, IDC_CONVDISK_SPECIFY_EDIT, specifyBlocks);

	ASSERT(fDiskSizeIdx >= 0 && fDiskSizeIdx < (int)NewDiskSize::GetNumSizeEntries());

	if (pDX->m_bSaveAndValidate) {
		fNumBlocks = NewDiskSize::GetDiskSizeByIndex(fDiskSizeIdx);
		if (fNumBlocks == NewDiskSize::kSpecified)
			fNumBlocks = specifyBlocks;

		if (fDiskFormatIdx == kFmtDOS32) {
			CString tmpStr;
			tmpStr.Format("%d", fDOSVolumeNum);
			if (!IsValidVolumeName_DOS(tmpStr))
				errMsg.LoadString(IDS_VALID_VOLNAME_DOS);
		} else if (fDiskFormatIdx == kFmtDOS33) {
			CString tmpStr;
			tmpStr.Format("%d", fDOSVolumeNum);
			if (!IsValidVolumeName_DOS(tmpStr))
				errMsg.LoadString(IDS_VALID_VOLNAME_DOS);

			// only needed in "extended" mode -- this stuff is too painful to
			//  inflict on the average user
			if (fNumBlocks < 18*8 || fNumBlocks > 800 ||
				(fNumBlocks <= 400 && (fNumBlocks % 8) != 0) ||
				(fNumBlocks > 400 && (fNumBlocks % 16) != 0))
			{
				errMsg = "Specify a size between 144 blocks (18 tracks) and"
						 " 800 blocks (50 tracks/32 sectors).  The block count"
						 " must be a multiple of 8 for 16-sector disks, or a"
						 " multiple of 16 for 32-sector disks.  32 sector"
						 " formatting starts at 400 blocks.  Disks larger than"
						 " 400 blocks but less than 800 aren't recognized by"
						 " CiderPress.";
			}
		} else if (fDiskFormatIdx == kFmtProDOS) {
			// Max is really 65535, but we allow 65536 for creation of volumes
			// that can be copied to CFFA cards.
			if (fNumBlocks < 16 || fNumBlocks > 65536) {
				errMsg = "Specify a size of at least 16 blocks and no more"
						  " than 65536 blocks.";
			} else if (fVolName_ProDOS.IsEmpty() ||
				fVolName_ProDOS.GetLength() > kProDOSVolNameMax)
			{
				errMsg = "You must specify a volume name 1-15 characters long.";
			} else {
				if (!IsValidVolumeName_ProDOS(fVolName_ProDOS))
					errMsg.LoadString(IDS_VALID_VOLNAME_PRODOS);
			}
		} else if (fDiskFormatIdx == kFmtPascal) {
			if (fVolName_Pascal.IsEmpty() ||
				fVolName_Pascal.GetLength() > kPascalVolNameMax)
			{
				errMsg = "You must specify a volume name 1-7 characters long.";
			} else {
				if (!IsValidVolumeName_Pascal(fVolName_Pascal))
					errMsg.LoadString(IDS_VALID_VOLNAME_PASCAL);
			}
		} else if (fDiskFormatIdx == kFmtHFS) {
			if (fNumBlocks < 1600 || fNumBlocks > 4194303) {
				errMsg = "Specify a size of at least 1600 blocks and no more"
						  " than 4194303 blocks.";
			} else if (fVolName_HFS.IsEmpty() ||
				fVolName_HFS.GetLength() > kHFSVolNameMax)
			{
				errMsg = "You must specify a volume name 1-27 characters long.";
			} else {
				if (!IsValidVolumeName_HFS(fVolName_HFS))
					errMsg.LoadString(IDS_VALID_VOLNAME_HFS);
			}
		} else if (fDiskFormatIdx == kFmtBlank) {
			if (fNumBlocks < 1 || fNumBlocks > kMaxBlankBlocks)
				errMsg = "Specify a size of at least 1 block and no more"
						  " than 16777216 blocks.";
		} else {
			ASSERT(false);
		}
	} else {
		OnFormatChangeRange(IDC_CREATEFS_DOS32 + fDiskFormatIdx);
	}

	if (!errMsg.IsEmpty()) {
		CString appName;
		appName.LoadString(IDS_MB_APP_NAME);
		MessageBox(errMsg, appName, MB_OK);
		pDX->Fail();
	}

	CDialog::DoDataExchange(pDX);
}

/*
 * When the user chooses a format, enable and disable controls as
 * appropriate.
 */
void
CreateImageDialog::OnFormatChangeRange(UINT nID)
{
	static const struct {
		UINT	buttonID;
		UINT	ctrlID;
	} kFormatTab[] = {
		{ IDC_CREATEFS_DOS32, IDC_CREATEFSDOS_ALLOCDOS },
		{ IDC_CREATEFS_DOS32, IDC_CREATEFSDOS_VOLNUM },
		{ IDC_CREATEFS_DOS32, IDC_CONVDISK_140K },
		{ IDC_CREATEFS_DOS33, IDC_CREATEFSDOS_ALLOCDOS },
		{ IDC_CREATEFS_DOS33, IDC_CREATEFSDOS_VOLNUM },
		{ IDC_CREATEFS_DOS33, IDC_CONVDISK_140K },
		{ IDC_CREATEFS_PRODOS, IDC_CREATEFSPRODOS_VOLNAME },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_140K },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_800K },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_1440K },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_5MB },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_16MB },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_20MB },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_32MB },
		{ IDC_CREATEFS_PRODOS, IDC_CONVDISK_SPECIFY },
		{ IDC_CREATEFS_PASCAL, IDC_CREATEFSPASCAL_VOLNAME },
		{ IDC_CREATEFS_PASCAL, IDC_CONVDISK_140K },
		{ IDC_CREATEFS_PASCAL, IDC_CONVDISK_800K },
		{ IDC_CREATEFS_HFS, IDC_CREATEFSHFS_VOLNAME },
		{ IDC_CREATEFS_HFS, IDC_CONVDISK_800K },
		{ IDC_CREATEFS_HFS, IDC_CONVDISK_1440K },
		{ IDC_CREATEFS_HFS, IDC_CONVDISK_5MB },
		{ IDC_CREATEFS_HFS, IDC_CONVDISK_16MB },
		{ IDC_CREATEFS_HFS, IDC_CONVDISK_20MB },
		{ IDC_CREATEFS_HFS, IDC_CONVDISK_32MB },
		{ IDC_CREATEFS_HFS, IDC_CONVDISK_SPECIFY },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_140K },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_800K },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_1440K },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_5MB },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_16MB },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_20MB },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_32MB },
		{ IDC_CREATEFS_BLANK, IDC_CONVDISK_SPECIFY },
	};
	static const UINT kDetailControls[] = {
		IDC_CREATEFSDOS_ALLOCDOS,
		IDC_CREATEFSDOS_VOLNUM,
		IDC_CREATEFSPRODOS_VOLNAME,
		IDC_CREATEFSPASCAL_VOLNAME,
		IDC_CREATEFSHFS_VOLNAME
	};
	int i;
	
	WMSG1("OnFormatChangeRange id=%d\n", nID);

	/* reset so 140K is highlighted */
	NewDiskSize::EnableButtons_ProDOS(this, 32, 16);

	/* disable all buttons */
	NewDiskSize::EnableButtons(this, FALSE);

	for (i = 0; i < NELEM(kDetailControls); i++) {
		CWnd* pWnd = GetDlgItem(kDetailControls[i]);
		if (pWnd != nil)
			pWnd->EnableWindow(FALSE);
	}

	/* re-enable just the ones we like */
	for (i = 0; i < NELEM(kFormatTab); i++) {
		if (kFormatTab[i].buttonID == nID) {
			CWnd* pWnd = GetDlgItem(kFormatTab[i].ctrlID);
			ASSERT(pWnd != nil);
			if (pWnd != nil)
				pWnd->EnableWindow(TRUE);
		}
	}
	if (fExtendedOpts && nID != IDC_CREATEFS_DOS32) {
		CWnd* pWnd = GetDlgItem(IDC_CONVDISK_SPECIFY);
		pWnd->EnableWindow(TRUE);
	}

	/* make sure 140K is viable; doesn't work for HFS */
	CButton* pButton;
	pButton = (CButton*) GetDlgItem(IDC_CONVDISK_140K);
	if (!pButton->IsWindowEnabled()) {
		pButton->SetCheck(BST_UNCHECKED);
		pButton = (CButton*) GetDlgItem(IDC_CONVDISK_800K);
		pButton->SetCheck(BST_CHECKED);
	}
}

/*
 * When one of the radio buttons is clicked on, update the active status
 * and contents of the "specify size" edit box.
 */
void
CreateImageDialog::OnSizeChangeRange(UINT nID)
{
	WMSG1("OnSizeChangeRange id=%d\n", nID);

	CButton* pButton = (CButton*) GetDlgItem(IDC_CONVDISK_SPECIFY);
	CEdit* pEdit = (CEdit*) GetDlgItem(IDC_CONVDISK_SPECIFY_EDIT);
	pEdit->EnableWindow(pButton->GetCheck() == BST_CHECKED);

	CButton* pBlank;
	CButton* pHFS;
	pBlank = (CButton*) GetDlgItem(IDC_CREATEFS_BLANK);
	pHFS = (CButton*) GetDlgItem(IDC_CREATEFS_HFS);
	if (pHFS->GetCheck() == BST_CHECKED)
		pEdit->SetLimitText(10);	// enough for "2147483647"
	else if (pBlank->GetCheck() == BST_CHECKED)
		pEdit->SetLimitText(8);		// enough for "16777216"
	else
		pEdit->SetLimitText(5);		// enough for "65535"

	NewDiskSize::UpdateSpecifyEdit(this);
}


/*
 * Test a DOS filename for validity.
 */
bool
CreateImageDialog::IsValidVolumeName_DOS(const char* name)
{
	return DiskImgLib::DiskFSDOS33::IsValidVolumeName(name);
}

/*
 * Test a ProDOS filename for validity.
 */
bool
CreateImageDialog::IsValidVolumeName_ProDOS(const char* name)
{
	return DiskImgLib::DiskFSProDOS::IsValidVolumeName(name);
}

/*
 * Test a Pascal filename for validity.
 */
bool
CreateImageDialog::IsValidVolumeName_Pascal(const char* name)
{
	return DiskImgLib::DiskFSPascal::IsValidVolumeName(name);
}

/*
 * Test an HFS filename for validity.
 */
bool
CreateImageDialog::IsValidVolumeName_HFS(const char* name)
{
	return DiskImgLib::DiskFSHFS::IsValidVolumeName(name);
}


/*
 * Context help request (question mark button).
 */
BOOL
CreateImageDialog::OnHelpInfo(HELPINFO* lpHelpInfo)
{
	WinHelp((DWORD) lpHelpInfo->iCtrlId, HELP_CONTEXTPOPUP);
	return TRUE;	// yes, we handled it
}

/*
 * User pressed the "Help" button.
 */
void
CreateImageDialog::OnHelp(void)
{
	WinHelp(HELP_TOPIC_IMAGE_CREATOR, HELP_CONTEXT);
}
