#include "pch.h"

#include "MemDumpView.h"
#include "BKMessageBox.h"
#include "Platform.h"
#include "Debugger.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif

/////////////////////////////////////////////////////////////////////////////
// CMemDumpView

DISPLAY_MODE_PARAM CMemDumpView::m_dmArray[DISPLAY_MODES_NUM] =
{
	{ DUMP_DISPLAY_MODE::DD_WORD_VIEW, IDS_MEMDUMP_WORD },
	{ DUMP_DISPLAY_MODE::DD_BYTE_VIEW, IDS_MEMDUMP_BYTE }
};

constexpr auto BK_PAGE_SIZE = 040000;
constexpr auto AZBK_PAGE_SIZE = 010000;
constexpr auto AZBK_MIN_SEGMENT = 0;
constexpr auto AZBK_MAX_SEGMENT = 8191;

IMPLEMENT_DYNAMIC(CMemDumpView, CDocPaneDlgViewBase)

CMemDumpView::CMemDumpView()
	: m_nCurrentDDM(0)
	, m_pV(nullptr)
	, m_strDumpAddr(_T("000000"))
	, m_pDmpEAPtr(nullptr)
	, m_nAZSegment(0)
	, m_bAZShowed(true)
	, m_pAZMemory(nullptr)
{
}

CMemDumpView::~CMemDumpView()
    = default;

void CMemDumpView::DoDataExchange(CDataExchange *pDX)
{
	CDocPaneDlgViewBase::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST_MD_MEMORY, m_ListMemory);
	DDX_Control(pDX, IDC_COMBO_MD_WINDOWS, m_cbWndList);
	DDX_Control(pDX, IDC_COMBO_MD_WINDADDR, m_cbWndAddr);
	DDX_Control(pDX, IDC_EDIT_MD_DUMPADDR, m_EditAddr);
	DDX_Control(pDX, IDC_EDIT_MD_AZSEG, m_EditAZSegment);
	DDX_Text(pDX, IDC_EDIT_MD_DUMPADDR, m_strDumpAddr);
	DDX_OctText(pDX, IDC_EDIT_MD_AZSEG, m_nAZSegment);
	DDV_MyMinMaxInt(pDX, IDC_EDIT_MD_AZSEG, m_nAZSegment, AZBK_MIN_SEGMENT, AZBK_MAX_SEGMENT);
	DDX_Control(pDX, IDC_SPIN_MD_AZSEG, m_spinAZSegment);
}



BEGIN_MESSAGE_MAP(CMemDumpView, CDocPaneDlgViewBase)
	ON_WM_SETFOCUS()
	ON_MESSAGE(WM_INITDIALOG, &CMemDumpView::HandleInitDialog)
	ON_MESSAGE(WM_DBG_CURRENT_ADDRESS_CHANGE, &CMemDumpView::OnDumpAddressChange)
	ON_MESSAGE(WM_DBG_TOP_ADDRESS_UPDATE, &CMemDumpView::OnDumpAddressUpdate)
	ON_COMMAND(IDC_BUTTON_MD_DUMPMODE, &CMemDumpView::OnBnClickedButtonDumpMode)
	ON_COMMAND(IDC_BUTTON_MD_SAVE, &CMemDumpView::OnBnClickedButtonSaveDump)
	ON_COMMAND(IDC_BUTTON_MD_LOAD, &CMemDumpView::OnBnClickedButtonLoadDump)
	ON_CBN_SELCHANGE(IDC_COMBO_MD_WINDOWS, &CMemDumpView::OnCbnSelchangeComboMdWindows)
	ON_CBN_SELCHANGE(IDC_COMBO_MD_WINDADDR, &CMemDumpView::OnCbnSelchangeComboMdWindaddr)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_MD_DUMPMODE, &CMemDumpView::OnUpdateButton)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_MD_SAVE, &CMemDumpView::OnUpdateButton)
	ON_UPDATE_COMMAND_UI(IDC_BUTTON_MD_LOAD, &CMemDumpView::OnUpdateButton)
	ON_EN_CHANGE(IDC_EDIT_MD_AZSEG, &CMemDumpView::OnEnChangeEditMdAzseg)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// обработчики сообщений CMemDumpView

LRESULT CMemDumpView::HandleInitDialog(WPARAM wp, LPARAM lp)
{
	CDocPaneDlgViewBase::HandleInitDialog(wp, lp);
	m_ToolTip.AddTool(GetDlgItem(IDC_EDIT_MD_DUMPADDR), IDS_TOOLTIP_EDIT_MD_DUMPADDR);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_MD_DUMPMODE), IDS_TOOLTIP_BUTTON_MD_DUMPMODE);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_MD_SAVE), IDS_TOOLTIP_BUTTON_MD_SAVE);
	m_ToolTip.AddTool(GetDlgItem(IDC_BUTTON_MD_LOAD), IDS_TOOLTIP_BUTTON_MD_LOAD);
	m_ToolTip.AddTool(GetDlgItem(IDC_COMBO_MD_WINDOWS), IDS_TOOLTIP_COMBO_MD_WINDOWS);
	m_ToolTip.AddTool(GetDlgItem(IDC_COMBO_MD_WINDADDR), IDS_TOOLTIP_COMBO_MD_WINDADDR);
	m_EditAddr.SetLimitText(6);
	m_EditAZSegment.SetLimitText(6);
	SetDlgItemText(IDC_BUTTON_MD_DUMPMODE, CString(MAKEINTRESOURCE(m_dmArray[m_nCurrentDDM].strID))); // на кнопке нарисуем начальное значение
	m_ListMemory.SetFont(&m_hFont, FALSE);
//  m_ListMemory.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER, LVS_EX_DOUBLEBUFFER);
	m_ListMemory.Init(m_dmArray[m_nCurrentDDM].mode); // создадим только колонки
	m_cbWndAddr.AddString(_T("000000"));
	m_cbWndAddr.AddString(_T("040000"));
	m_cbWndAddr.AddString(_T("100000"));
	m_cbWndAddr.AddString(_T("140000"));
	m_cbWndAddr.SetCurSel(0);
	m_ListMemory.SetAddress(m_ListMemory.m_nDmpWndAddr);
	m_spinAZSegment.SetRange32(AZBK_MIN_SEGMENT, AZBK_MAX_SEGMENT);
	m_spinAZSegment.SetPos32(m_nAZSegment);
	m_spinAZSegment.SetOctBuddy(reinterpret_cast<COctalEdit *>(GetDlgItem(IDC_EDIT_MD_AZSEG)));
	return TRUE;  // возврат значения TRUE, если фокус не передан элементу управления
}

void CMemDumpView::OnSetFocus(CWnd *pOldWnd)
{
	m_ListMemory.SetFocus();
}

void CMemDumpView::DisplayMemDump()
{
	if (IsVisible())
	{
		m_ListMemory.RefreshItems();
	}
}

void CMemDumpView::SetAddress(const uint16_t addr)
{
	m_ListMemory.SetAddress(addr);
	m_strDumpAddr = Global::WordToOctString(addr);
	UpdateData(FALSE);
}

void CMemDumpView::SetDumpWindows(VWinParam *pV, const int nPageListPos, const int nAddrListPos)
{
	m_pV = pV;
	const int nCount = m_cbWndList.GetCount();

	if (nCount > 0)
	{
		for (int i = nCount - 1; i >= 0; --i)
		{
			m_cbWndList.DeleteString(i);
		}
	}

	m_cbWndList.AddString(_T("АП БК 64Кб"));

	if (!pV->empty())
	{
		for (auto &n : *pV)
		{
			m_cbWndList.AddString(n.strName);
		}

		m_cbWndList.EnableWindow(TRUE);
	}
	else
	{
		m_cbWndList.EnableWindow(FALSE);
	}

	m_cbWndAddr.SetCurSel(nAddrListPos);
	m_cbWndList.SetCurSel(nPageListPos);
	// обновим данные
	OnCbnSelchangeComboMdWindows();
}


int CMemDumpView::GetDumpPageListPos() const
{
	return m_cbWndList.GetCurSel();
}

int CMemDumpView::GetDumpAddrListPos() const
{
	return m_cbWndAddr.GetCurSel();
}

void CMemDumpView::OnCbnSelchangeComboMdWindows()
{
	int n = m_cbWndList.GetCurSel();

	if (n <= 0)
	{
		m_ListMemory.m_nDmpWndAddr = 0;
		m_ListMemory.m_nDmpWndLen = 65536;
		m_pDmpEAPtr = nullptr;
		m_cbWndAddr.EnableWindow(FALSE);
		ChangeViewDlg(false);
	}
	else
	{
		CString str;
		m_cbWndList.GetLBText(n, str);
		ChangeViewDlg(str == _T("AZBK"));
		--n;

		if (m_pV->at(n).nDmpWndAddr != -1)
		{
			m_cbWndAddr.EnableWindow(FALSE);
			m_ListMemory.m_nDmpWndAddr = m_pV->at(n).nDmpWndAddr;
		}
		else
		{
			m_cbWndAddr.EnableWindow(TRUE);
			m_ListMemory.m_nDmpWndAddr = m_cbWndAddr.GetCurSel() * BK_PAGE_SIZE;
		}

		m_ListMemory.m_nDmpWndLen = m_pV->at(n).nDmpWndLen;

		if (m_bAZShowed)
		{
			m_pAZMemory = m_pV->at(n).pDmpEAPtr;
			m_pDmpEAPtr = const_cast<uint8_t *>(m_pAZMemory) + m_nAZSegment * AZBK_PAGE_SIZE;
		}
		else
		{
			m_pDmpEAPtr = const_cast<uint8_t *>(m_pV->at(n).pDmpEAPtr);
		}
	}

	RefreshDump(m_pDmpEAPtr); //нужно, чтоб передать данные списку
}


void CMemDumpView::ChangeViewDlg(const bool bAZBK)
{
	if (bAZBK) // если выбрана страница памяти AZBK
	{
		if (!m_bAZShowed) // если элементы AZ не показаны
		{
			// надо показать
			m_bAZShowed = true;
			CWnd *pWEd = GetDlgItem(IDC_EDIT_MD_AZSEG);
			CWnd *pWSpn = GetDlgItem(IDC_SPIN_MD_AZSEG);
			pWEd->EnableWindow(TRUE);
			pWSpn->EnableWindow(TRUE);
			CWnd *pWSt = GetDlgItem(IDC_STATIC_MD_AZSEC);
			pWSt->ShowWindow(SW_HIDE);
			pWSt->EnableWindow(TRUE);
			pWSt->ShowWindow(SW_SHOW);
//          GetDlgItem(IDC_STATIC_MD_AZSEC)->ShowWindow(SW_SHOW);
//          pWEd->ShowWindow(SW_SHOW);
//          pWSpn->ShowWindow(SW_SHOW);
//          CRect editRect, listRect;
//          pWEd->GetWindowRect(&editRect);
//          CWnd *pWLst = GetDlgItem(IDC_LIST_MD_MEMORY);
//          pWLst->GetWindowRect(&listRect);
//          ScreenToClient(&editRect);
//          ScreenToClient(&listRect);
//          int nPixelH = ::GetDeviceCaps(GetDC()->GetSafeHdc(), LOGPIXELSY);
//          int padY = ::MulDiv(4, nPixelH, DEFAULT_DPIY); // отступ
//          listRect.top = editRect.bottom + padY;
//          pWLst->SetWindowPos(nullptr, listRect.left, listRect.top, listRect.Width(), listRect.Height(), SWP_SHOWWINDOW); // изменяем размеры списка
		}
	}
	else // если выбрано что-то другое
	{
		if (m_bAZShowed) // если показаны элементы AZ
		{
			// надо скрыть
			m_bAZShowed = false;
			CWnd *pWEd = GetDlgItem(IDC_EDIT_MD_AZSEG);
			CWnd *pWSpn = GetDlgItem(IDC_SPIN_MD_AZSEG);
			pWEd->EnableWindow(FALSE);
			pWSpn->EnableWindow(FALSE);
			CWnd *pWSt = GetDlgItem(IDC_STATIC_MD_AZSEC);
			pWSt->ShowWindow(SW_HIDE);
			pWSt->EnableWindow(FALSE);
			pWSt->ShowWindow(SW_SHOW);
//          GetDlgItem(IDC_STATIC_MD_AZSEC)->ShowWindow(SW_HIDE);
//          pWEd->ShowWindow(SW_HIDE);
//          pWSpn->ShowWindow(SW_HIDE);
//          CRect editRect, listRect;
//          pWEd->GetWindowRect(&editRect);
//          CWnd *pWLst = GetDlgItem(IDC_LIST_MD_MEMORY);
//          pWLst->GetWindowRect(&listRect);
//          ScreenToClient(&editRect);
//          ScreenToClient(&listRect);
//          listRect.top = editRect.top;
//          pWLst->SetWindowPos(nullptr, listRect.left, listRect.top, listRect.Width(), listRect.Height(), SWP_SHOWWINDOW); // изменяем размеры списка
		}
	}

	// !!! Прям вот серьёзнейший косяк MFC - при перерисовке окошка, если оно было скрыто другим окошком,
	// размеры контролов берутся из ресурсов, а не те, какие были
	// Красиво не получилось. Поэтому будем просто дисаблить/енаблить
}


void CMemDumpView::OnEnChangeEditMdAzseg()
{
	UpdateData(TRUE);

	if (AZBK_MIN_SEGMENT <= m_nAZSegment && m_nAZSegment <= AZBK_MAX_SEGMENT)
	{
		m_pDmpEAPtr = const_cast<uint8_t*>(m_pAZMemory) + m_nAZSegment * AZBK_PAGE_SIZE;
		RefreshDump(m_pDmpEAPtr); //нужно, чтоб передать данные списку
	}
}


void CMemDumpView::OnCbnSelchangeComboMdWindaddr()
{
	m_ListMemory.m_nDmpWndAddr = m_cbWndAddr.GetCurSel() * BK_PAGE_SIZE;
	RefreshDump(m_pDmpEAPtr); //нужно, чтоб передать данные списку
}

LRESULT CMemDumpView::OnDumpAddressChange(WPARAM wParam, LPARAM)
{
	// в окошке адреса изменим значение
	const uint16_t addr = static_cast<uint16_t>(wParam);
	m_strDumpAddr = Global::WordToOctString(addr);
	UpdateData(FALSE);
	m_ListMemory.SetAddress(addr);
	m_ListMemory.RefreshItems(addr, true);
	return S_OK;
}

LRESULT CMemDumpView::OnDumpAddressUpdate(WPARAM, LPARAM)
{
	UpdateData(TRUE);
	const uint16_t addr = Global::OctStringToWord(m_strDumpAddr);
	// обновим значение, чтобы оно было всегда 6 значным
	m_strDumpAddr = Global::WordToOctString(addr);
	UpdateData(FALSE);
	m_ListMemory.SetAddress(addr);
	m_ListMemory.RefreshItems(addr, true);
	return S_OK;
}


void CMemDumpView::OnBnClickedButtonDumpMode()
{
	if (++m_nCurrentDDM >= DISPLAY_MODES_NUM)
	{
		m_nCurrentDDM = 0;
	}

	SetDlgItemText(IDC_BUTTON_MD_DUMPMODE, CString(MAKEINTRESOURCE(m_dmArray[m_nCurrentDDM].strID)));
	m_ListMemory.SetDisplayMode(m_dmArray[m_nCurrentDDM].mode);
}

void CMemDumpView::RefreshDump(uint8_t *pDmpEAPtr)
{
	m_pDmpEAPtr = pDmpEAPtr;
	m_ListMemory.m_nDmpWndEndAddr = m_ListMemory.m_nDmpWndAddr + m_ListMemory.m_nDmpWndLen;
	m_ListMemory.SetAddress(m_ListMemory.m_nDmpWndAddr);
	m_ListMemory.SetDisplayMode(m_dmArray[m_nCurrentDDM].mode); // перерисуем всё
}

uint16_t CMemDumpView::GetDebugMemDumpWord(const uint16_t dumpAddress) const
{
	if (m_pDmpEAPtr)
	{
		return *(reinterpret_cast<uint16_t *>(m_pDmpEAPtr + (dumpAddress - m_ListMemory.m_nDmpWndAddr)));
	}

	return g_Platform.GetDebuggerPtr()->GetDebugMemDumpWord(dumpAddress);
}

uint8_t CMemDumpView::GetDebugMemDumpByte(const uint16_t dumpAddress) const
{
	if (m_pDmpEAPtr)
	{
		return *(m_pDmpEAPtr + (dumpAddress - m_ListMemory.m_nDmpWndAddr));
	}

	return g_Platform.GetDebuggerPtr()->GetDebugMemDumpByte(dumpAddress);
}

void CMemDumpView::SetDebugMemDumpWord(const uint16_t dumpAddress, const uint16_t value) const
{
	if (m_pDmpEAPtr)
	{
		*(reinterpret_cast<uint16_t *>(m_pDmpEAPtr + (dumpAddress - m_ListMemory.m_nDmpWndAddr))) = value;
	}
	else
	{
		g_Platform.GetDebuggerPtr()->SetDebugMemDump(dumpAddress, value);
	}
}

void CMemDumpView::SetDebugMemDumpByte(const uint16_t dumpAddress, const uint8_t value) const
{
	if (m_pDmpEAPtr)
	{
		*(m_pDmpEAPtr + (dumpAddress - m_ListMemory.m_nDmpWndAddr)) = value;
	}
	else
	{
		g_Platform.GetDebuggerPtr()->SetDebugMemDump(dumpAddress, value);
	}
}


#pragma warning(disable:4996)

void CMemDumpView::OnBnClickedButtonSaveDump()
{
	SvDmpParam sBinParam;
	sBinParam.bNoHeader = !!(::GetAsyncKeyState(VK_SHIFT) & 0x8000);

	GetDlgItem(IDC_BUTTON_MD_SAVE)->GetWindowRect(&sBinParam.rect);
	const auto SvDmpDlg = std::make_unique<CSvDmpParamDlg>(&sBinParam);

	if (SvDmpDlg)
	{
		if (SvDmpDlg->DoModal() == IDOK)
		{
			const int nAddr = sBinParam.nBgnAddr;
			int nLen = sBinParam.nLength;

			if (nAddr + nLen >= m_ListMemory.m_nDmpWndLen)
			{
				nLen = m_ListMemory.m_nDmpWndLen - nAddr;
			}

			if (nLen > 0)
			{
				CString strDefExt(MAKEINTRESOURCE(IDS_FILEEXT_BINARY));
				CString strFilter(MAKEINTRESOURCE(IDS_FILEFILTER_BIN));
				if (sBinParam.bNoHeader)
				{
					strFilter.Empty();
				}

				CFileDialog dlg(FALSE, strDefExt, nullptr,
				                OFN_HIDEREADONLY | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_EXPLORER,
				                strFilter, this);
				dlg.GetOFN().lpstrInitialDir = g_Config.m_strBinPath.c_str(); // диалог всегда будем начинать с директории для bin файлов

				if (dlg.DoModal() == IDOK)
				{
					auto buf = std::vector<uint8_t>(nLen);

					if (buf.data())
					{
						const fs::path str = dlg.GetPathName().GetString();
						bool bIsBreak = g_Platform.IsCPUBreaked();
						g_Platform.StopCPU(!bIsBreak);
						//g_Platform.SetMemPages(sBinParam.nPage0, sBinParam.nPage1);

						for (int addr = nAddr, i = 0; i < nLen; ++i)
						{
							buf[i] = GetDebugMemDumpByte(addr++);
						}

						if (sBinParam.bNoHeader)
						{
							Global::SaveRawFile(buf.data(), nAddr, nLen, str);
						}
						else
						{
							Global::SaveBinFile(buf.data(), nAddr, nLen, str);
						}

						//g_Platform.RestoreMemPages();
						g_Platform.RunCPU(!bIsBreak);
					}
					else
					{
						g_BKMsgBox.Show(IDS_BK_ERROR_NOTENMEMR, MB_OK);
					}
				}
			}
		}
	}
}


void CMemDumpView::OnBnClickedButtonLoadDump()
{
	if (!!(::GetAsyncKeyState(VK_SHIFT) & 0x8000))
	{
		SvDmpParam sBinParam;
		GetDlgItem(IDC_BUTTON_MD_LOAD)->GetWindowRect(&sBinParam.rect);
		const auto LdDmpDlg = std::make_unique<CLdDmpParamDlg>(&sBinParam);

		if (LdDmpDlg)
		{
			if (LdDmpDlg->DoModal() == IDOK)
			{
				bool bIsBreak = g_Platform.IsCPUBreaked();
				g_Platform.StopCPU(!bIsBreak);
				// если БК11(М) - подключить нужные страницы
				g_Platform.SetMemPages(sBinParam.nPage0, sBinParam.nPage1);
				LoadFunc(sBinParam.nBgnAddr);
				// если БК11(М) - отключить нужные страницы и вернуть как было
				g_Platform.RestoreMemPages();
				g_Platform.RunCPU(!bIsBreak);
			}
		}
	}
	else
	{
		const bool bIsBreak = g_Platform.IsCPUBreaked();
		g_Platform.StopCPU(!bIsBreak);
		LoadFunc();
		g_Platform.RunCPU(!bIsBreak);
	}
}

void CMemDumpView::OnUpdateButton(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(true);
}

void CMemDumpView::LoadFunc(uint16_t nLoadAddr)
{
	const CString strDefExt(MAKEINTRESOURCE(IDS_FILEEXT_BINARY));
	const CString strFilter(MAKEINTRESOURCE(IDS_FILEFILTER_BIN));
	CFileDialog dlg(TRUE, strDefExt, nullptr,
	                OFN_HIDEREADONLY | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR | OFN_EXPLORER,
	                strFilter, this);
	dlg.GetOFN().lpstrInitialDir = g_Config.m_strBinPath.c_str(); // диалог всегда будем начинать с директории для bin файлов

	if (dlg.DoModal() == IDOK)
	{
		const fs::path str = dlg.GetPathName().GetString();
		uint16_t nAddr, nLen;
		std::unique_ptr<uint8_t[]> buf;

		if (Global::LoadBinFile(buf, nAddr, nLen, str, false))
		{
			// !!! Косяк - невозможно загружать принудительно с нулевого адреса.
			// Тут бы очень помогли отрицательные числа, но их ввод в поле адреса не предусмотрен,
			// как быть, пока идей нет.
			if (nLoadAddr)
			{
				nAddr = nLoadAddr;
			}

			if (int(nAddr) + int(nLen) >= m_ListMemory.m_nDmpWndLen)
			{
				nLen = m_ListMemory.m_nDmpWndLen - nAddr;
			}

			for (int i = 0; i < nLen; ++i)
			{
				SetDebugMemDumpByte(nAddr++, buf[i]);
			}
		}
	}
}


IMPLEMENT_DYNAMIC(CSvDmpParamDlg, CBaseDialog)

CSvDmpParamDlg::CSvDmpParamDlg(SvDmpParam *pParam, CWnd *pParent /*= nullptr*/)
	: CBaseDialog(CSvDmpParamDlg::IDD, pParent)
	, m_pParam(pParam)
	, m_nBgnAddr(0)
	, m_nEndAddr(BK_PAGE_SIZE)
	, m_nLength(m_nEndAddr - m_nBgnAddr)
	, m_bNoHeader(FALSE)
{
	m_strBgnAddr = Global::WordToOctString(m_nBgnAddr);
	m_strEndAddr = Global::WordToOctString(m_nEndAddr);
	m_strLength = Global::WordToOctString(m_nLength);
}

CSvDmpParamDlg::~CSvDmpParamDlg()
    = default;

BEGIN_MESSAGE_MAP(CSvDmpParamDlg, CBaseDialog)
	ON_MESSAGE(WM_DBG_TOP_ADDRESS_UPDATE, &CSvDmpParamDlg::OnEditChange)
	ON_EN_KILLFOCUS(IDC_EDIT_SVDMP_BGNADDR, &CSvDmpParamDlg::OnEnKillfocusEditSvdmpBgnaddr)
	ON_EN_KILLFOCUS(IDC_EDIT_SVDMP_ENDADDR, &CSvDmpParamDlg::OnEnKillfocusEditSvdmpEndaddr)
	ON_EN_KILLFOCUS(IDC_EDIT_SVDMP_LENGTH, &CSvDmpParamDlg::OnEnKillfocusEditSvdmpLength)
END_MESSAGE_MAP()

void CSvDmpParamDlg::DoDataExchange(CDataExchange *pDX)
{
	CBaseDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_SVDMP_BGNADDR, m_EditBgnAddr);
	DDX_Control(pDX, IDC_EDIT_SVDMP_ENDADDR, m_EditEndAddr);
	DDX_Control(pDX, IDC_EDIT_SVDMP_LENGTH, m_EditLength);
	DDX_Text(pDX, IDC_EDIT_SVDMP_BGNADDR, m_strBgnAddr);
	DDX_Text(pDX, IDC_EDIT_SVDMP_ENDADDR, m_strEndAddr);
	DDX_Text(pDX, IDC_EDIT_SVDMP_LENGTH, m_strLength);
	DDX_Check(pDX, IDC_CHECK_SVDMP_RAW, m_bNoHeader);
}

BOOL CSvDmpParamDlg::OnInitDialog()
{
	CRect r2;
	GetWindowRect(r2);
	CRect r;
	r.left = m_pParam->rect.left;
	r.top = m_pParam->rect.top + m_pParam->rect.Height();
	r.right = r.left + r2.Width();
	r.bottom = r.top + r2.Height();
//  r2.OffsetRect(m_pParam->rect.left - r2.left, m_pParam->rect.top + m_pParam->rect.Height() - r2.top);
	MoveWindow(r, FALSE);
	CBaseDialog::OnInitDialog();
	m_EditBgnAddr.SetLimitText(6);
	m_EditEndAddr.SetLimitText(6);
	m_EditLength.SetLimitText(6);
	m_bNoHeader = m_pParam->bNoHeader;
	UpdateData(FALSE);
	return TRUE;
}

void CSvDmpParamDlg::OnOK()
{
	if (m_pParam)
	{
		UpdateData(TRUE);
		m_pParam->nBgnAddr = m_nBgnAddr;
		m_pParam->nLength = m_nLength;
		m_pParam->bNoHeader = m_bNoHeader;
	}

	CBaseDialog::OnOK();
}


LRESULT CSvDmpParamDlg::OnEditChange(WPARAM wParam, LPARAM lParam)
{
	UpdateData(TRUE);

	switch (wParam)
	{
		case IDC_EDIT_SVDMP_BGNADDR:
			m_nBgnAddr = Global::OctStringToWord(m_strBgnAddr);

			if (m_nBgnAddr > 65536)
			{
				m_nBgnAddr = 0;
			}
			// если начальный адрес задали больше конечного,
			if (m_nBgnAddr > m_nEndAddr)
			{
				m_nEndAddr = m_nBgnAddr;	// то конечный адрес двинем к начальному
			}

			m_nLength = m_nEndAddr - m_nBgnAddr;
			break;

		case IDC_EDIT_SVDMP_ENDADDR:
			m_nEndAddr = Global::OctStringToWord(m_strEndAddr);

			if (m_nEndAddr > 65534)
			{
				m_nEndAddr = 65534;
			}
			// если конечный адрес задали меньше начального, то обменяем адреса
			if (m_nBgnAddr > m_nEndAddr)
			{
				std::swap(m_nBgnAddr, m_nEndAddr);
			}

			m_nLength = m_nEndAddr - m_nBgnAddr;
			break;

		case IDC_EDIT_SVDMP_LENGTH:
			m_nLength = Global::OctStringToWord(m_strLength);

			if (m_nLength > 65534)
			{
				m_nLength = 65534;
			}
			// вычисляем конечный адрес
			m_nEndAddr = m_nBgnAddr + m_nLength;
			// если он слишком большой
			if (m_nEndAddr > 65534)
			{
				m_nEndAddr = 65534; // огранчим
				m_nLength = m_nEndAddr - m_nBgnAddr; // и корректируем длину
			}

			break;

		default:
			return LRESULT();
	}

	m_strBgnAddr = Global::WordToOctString(m_nBgnAddr);
	m_strEndAddr = Global::WordToOctString(m_nEndAddr);
	m_strLength = Global::WordToOctString(m_nLength);
	UpdateData(FALSE);
	return LRESULT();
}


void CSvDmpParamDlg::OnEnKillfocusEditSvdmpBgnaddr()
{
	OnEditChange(IDC_EDIT_SVDMP_BGNADDR, 0);
}


void CSvDmpParamDlg::OnEnKillfocusEditSvdmpEndaddr()
{
	OnEditChange(IDC_EDIT_SVDMP_ENDADDR, 0);
}


void CSvDmpParamDlg::OnEnKillfocusEditSvdmpLength()
{
	OnEditChange(IDC_EDIT_SVDMP_LENGTH, 0);
}


IMPLEMENT_DYNAMIC(CLdDmpParamDlg, CBaseDialog)

CLdDmpParamDlg::CLdDmpParamDlg(SvDmpParam *pParam /*= nullptr*/, CWnd *pParent /*= nullptr*/)
	: CBaseDialog(CLdDmpParamDlg::IDD, pParent)
	, m_pParam(pParam)
	, m_nBgnAddr(0)
	, m_nPg0(5)
	, m_nPg1(1)
{
	m_strBgnAddr = Global::WordToOctString(m_nBgnAddr);
}

CLdDmpParamDlg::~CLdDmpParamDlg()
    = default;

BEGIN_MESSAGE_MAP(CLdDmpParamDlg, CBaseDialog)
	ON_MESSAGE(WM_DBG_TOP_ADDRESS_UPDATE, &CLdDmpParamDlg::OnEditChange)
	ON_EN_KILLFOCUS(IDC_EDIT_LDDMP_ADDR, &CLdDmpParamDlg::OnEnKillfocusEditLddmpAddr)
END_MESSAGE_MAP()

void CLdDmpParamDlg::DoDataExchange(CDataExchange *pDX)
{
	CBaseDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_LDDMP_ADDR, m_EditBgnAddr);
	DDX_Text(pDX, IDC_EDIT_LDDMP_ADDR, m_strBgnAddr);
	DDX_Control(pDX, IDC_EDIT_LDDMP_PG0, m_EditPG0); // IDC_EDIT_LDDMP_PG0 - номер страницы 1 ( на адрес 040000 )
	DDX_Control(pDX, IDC_EDIT_LDDMP_PG1, m_EditPG1);// IDC_EDIT_LDDMP_PG1 - страница 2 ( на адрес 100000 )
	DDX_Text(pDX, IDC_EDIT_LDDMP_PG0, m_nPg0);
	DDX_Text(pDX, IDC_EDIT_LDDMP_PG1, m_nPg1);
}

BOOL CLdDmpParamDlg::OnInitDialog()
{
	CRect r2;
	GetWindowRect(r2);
	CRect r;
	r.left = m_pParam->rect.left;
	r.top = m_pParam->rect.top + m_pParam->rect.Height();
	r.right = r.left + r2.Width();
	r.bottom = r.top + r2.Height();
	//  r2.OffsetRect(m_pParam->rect.left - r2.left, m_pParam->rect.top + m_pParam->rect.Height() - r2.top);
	MoveWindow(r, FALSE);
	CBaseDialog::OnInitDialog();
	m_EditBgnAddr.SetLimitText(6);
	m_EditPG0.SetLimitText(1);
	m_EditPG1.SetLimitText(1);

	// Если сейчас не БК11М и её конфигурации, засерим контролы выбора страниц.
	// В других местах - не юзаем результаты в контролах и не сохраняем
	if (!(g_Config.isBK11() || g_Config.isBK11M()))
	{
		GetDlgItem(IDC_EDIT_LDDMP_PG0)->EnableWindow(FALSE);
		GetDlgItem(IDC_EDIT_LDDMP_PG1)->EnableWindow(FALSE);
		GetDlgItem(IDC_TEXT_LDDMP_PG0)->EnableWindow(FALSE);
		GetDlgItem(IDC_TEXT_LDDMP_PG1)->EnableWindow(FALSE);
	}

	UpdateData(FALSE);
	return TRUE;
}

void CLdDmpParamDlg::OnOK()
{
	UpdateData(TRUE);

	if (m_pParam)
	{
		m_nBgnAddr = Global::OctStringToWord(m_strBgnAddr);
		m_pParam->nBgnAddr = m_nBgnAddr;
		m_pParam->nPage0 = m_nPg0;
		m_pParam->nPage1 = m_nPg1;
	}

	CBaseDialog::OnOK();
}


LRESULT CLdDmpParamDlg::OnEditChange(WPARAM wParam, LPARAM lParam)
{
	UpdateData(TRUE);

	switch (wParam)
	{
		case IDC_EDIT_LDDMP_ADDR:
			m_nBgnAddr = Global::OctStringToWord(m_strBgnAddr);

			if (m_nBgnAddr > 65536)
			{
				m_nBgnAddr = 0;
			}

			break;

		default:
			return LRESULT();
	}

	m_strBgnAddr = Global::WordToOctString(m_nBgnAddr);
	UpdateData(FALSE);
	return LRESULT();
}

void CLdDmpParamDlg::OnEnKillfocusEditLddmpAddr()
{
	OnEditChange(IDC_EDIT_LDDMP_ADDR, 0);
}

