
// DisasmDlg.cpp : implementation file
//

#include "stdafx.h"
#include "DisasmDlg.h"
#include "afxdialogex.h"
#include "Debugger.h"
#include "Config.h"

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

/////////////////////////////////////////////////////////////////////////////
// CDisasmDlg dialog

CDisasmDlg::CDisasmDlg(CWnd *pParent /*=nullptr*/)
	: CDialogEx(CDisasmDlg::IDD, pParent)
	, m_hAccelTable(nullptr)
{
}

CDisasmDlg::~CDisasmDlg()
{
	hFont.DeleteObject();
}

CSize CDisasmDlg::GetMinSize()
{
	CSize size;
	MINMAXINFO mmi;
	m_Resizer.GetMinMaxInfo(&mmi);
	size.cx = mmi.ptMinTrackSize.x;
	size.cy = mmi.ptMinTrackSize.y;
	return size;
}

void CDisasmDlg::DoDataExchange(CDataExchange *pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_DISASM_LIST, m_listDisasm);
	DDX_Control(pDX, IDC_DA_DEBUG_ADDRESS, m_AddrDisasm);
}


BEGIN_MESSAGE_MAP(CDisasmDlg, CDialogEx)
	ON_WM_SIZE()
	ON_WM_GETMINMAXINFO()
	ON_WM_SETFOCUS()
	ON_MESSAGE(WM_DBG_TOP_ADDRESS_UPDATE, &CDisasmDlg::OnDisasmTopAddressUpdate)
	ON_MESSAGE(WM_DBG_CURRENT_ADDRESS_CHANGE, &CDisasmDlg::OnDisasmCurrentAddressChange)
	ON_MESSAGE(WM_DBG_DISASM_STEP_UP, &CDisasmDlg::OnDisasmStepUp)
	ON_MESSAGE(WM_DBG_DISASM_STEP_DN, &CDisasmDlg::OnDisasmStepDn)
	ON_MESSAGE(WM_DBG_DISASM_PG_DN, &CDisasmDlg::OnDisasmPgUp)
	ON_MESSAGE(WM_DBG_DISASM_PG_DN, &CDisasmDlg::OnDisasmPgDn)
	ON_MESSAGE(WM_DBG_DISASM_CHECK_BP, &CDisasmDlg::OnDisasmCheckBp)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDisasmDlg message handlers

BOOL CDisasmDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	m_hAccelTable = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
	m_Resizer.Init(this);
	m_Resizer.AddCtrl(IDC_DISASM_LIST, DT_LEFT | DT_TOP | DT_RIGHT | DT_BOTTOM, FALSE, FALSE);
	m_Resizer.AddCtrl(IDC_DA_DEBUG_ADDRESS, DT_LEFT | DT_TOP, TRUE, TRUE);
	m_AddrDisasm.SetLimitText(6);
	LOGFONT lf;
	::GetObject((HGDIOBJ)::SendMessage(GetSafeHwnd(), WM_GETFONT, 0, 0), sizeof(LOGFONT), &lf);
	_tcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Courier New\0"));

	if (!hFont.CreateFontIndirect(&lf))
	{
		_tcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Lucida Console\0"));
		hFont.CreateFontIndirect(&lf);
	}

	m_listDisasm.SetFont(&hFont, FALSE);
	m_listDisasm.Init();
	return TRUE; // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

void CDisasmDlg::AttachDebugger(CDebugger *pDebugger)
{
	m_pDebugger = pDebugger;
	m_listDisasm.AttachDebugger(pDebugger);
	pDebugger->AttachWnd(this);
	SetDlgItemText(IDC_DA_DEBUG_ADDRESS, WordToOctString(m_pDebugger->GetCurrentAddress()));
}

//отменяем действие кнопок enter и esc в диалоге
void CDisasmDlg::OnOK()
{
}

void CDisasmDlg::OnCancel()
{
}


void CDisasmDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialogEx::OnSize(nType, cx, cy);
	m_Resizer.OnSize(cx, cy);
}

void CDisasmDlg::OnGetMinMaxInfo(MINMAXINFO *lpMMI)
{
	m_Resizer.GetMinMaxInfo(lpMMI);
}

void CDisasmDlg::OnSetFocus(CWnd *pOldWnd)
{
	CDialogEx::OnSetFocus(pOldWnd);
	m_listDisasm.SetFocus();
}


LRESULT CDisasmDlg::OnDisasmTopAddressUpdate(WPARAM, LPARAM)
{
	CString strBuf;
	GetDlgItemText(IDC_DA_DEBUG_ADDRESS, strBuf.GetBufferSetLength(10), 10);
	strBuf.ReleaseBuffer();
	uint16_t nAddr = OctStringToWord(strBuf);
	//обновим значение, чтобы оно было всегда 6 значным
	SetDlgItemText(IDC_DA_DEBUG_ADDRESS, WordToOctString(nAddr));
	m_pDebugger->SetCurrentAddress(nAddr);
	return S_OK;
}

LRESULT CDisasmDlg::OnDisasmCurrentAddressChange(WPARAM wp, LPARAM)
{
	SetDlgItemText(IDC_DA_DEBUG_ADDRESS, WordToOctString(uint16_t(wp)));
	return S_OK;
}

LRESULT CDisasmDlg::OnDisasmStepUp(WPARAM, LPARAM)
{
	uint16_t addr = 0;

	if (m_pDebugger) //сдвигаемся вверх
	{
		m_pDebugger->StepBackward();
		addr = m_pDebugger->GetCurrentAddress();
	}

	SetDlgItemText(IDC_DA_DEBUG_ADDRESS, WordToOctString(addr));
	return S_OK;
}

LRESULT CDisasmDlg::OnDisasmStepDn(WPARAM, LPARAM)
{
	uint16_t addr = 0;

	if (m_pDebugger) //сдвигаемся вниз
	{
		m_pDebugger->StepForward();
		addr = m_pDebugger->GetCurrentAddress();
	}

	SetDlgItemText(IDC_DA_DEBUG_ADDRESS, WordToOctString(addr));
	return S_OK;
}

LRESULT CDisasmDlg::OnDisasmPgUp(WPARAM wp, LPARAM)
{
	uint16_t addr = 0;
	int nCount = int(wp);

	if (m_pDebugger) //сдвигаемся вверх
	{
		while (--nCount > 0)
		{
			m_pDebugger->StepBackward();
		}

		addr = m_pDebugger->GetCurrentAddress();
	}

	SetDlgItemText(IDC_DA_DEBUG_ADDRESS, WordToOctString(addr));
	return S_OK;
}

LRESULT CDisasmDlg::OnDisasmPgDn(WPARAM wp, LPARAM)
{
	uint16_t addr = 0;
	int nCount = int(wp);

	if (m_pDebugger) //сдвигаемся вниз
	{
		while (--nCount > 0)
		{
			m_pDebugger->StepForward();
		}

		addr = m_pDebugger->GetCurrentAddress();
	}

	SetDlgItemText(IDC_DA_DEBUG_ADDRESS, WordToOctString(addr));
	return S_OK;
}

LRESULT CDisasmDlg::OnDisasmCheckBp(WPARAM wp, LPARAM)
{
	if (m_pDebugger)
	{
		uint16_t addr = m_pDebugger->GetLineAddress(int(wp));

		if (!m_pDebugger->SetSimpleBreakpoint(addr))
		{
			m_pDebugger->RemoveBreakpoint();
		}
	}

	return S_OK;
}



//для того, чтобы акселераторы работали, их надо загрузить и в этот диалог
//и передавать главному фрейму.
// способа проще найти не получилось.
BOOL CDisasmDlg::PreTranslateMessage(MSG *pMsg)
{
	if (m_hAccelTable)
	{
		if (::TranslateAccelerator(AfxGetMainWnd()->GetSafeHwnd(), m_hAccelTable, pMsg))
		{
			return TRUE;
		}
	}

	return CDialogEx::PreTranslateMessage(pMsg);
}
