
// BKMEM_testDlg.cpp : файл реализации
//

#include "stdafx.h"
#include "Globals.h"
#include "BKMEM_Dlg.h"
#include "BKMessageBox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

IMPLEMENT_DYNAMIC(CBKMEM_Dlg, CDialogEx)

// диалоговое окно CBKMEM_Dlg
CBKMEM_Dlg::CBKMEM_Dlg(BOARD_MODEL nBKModel, BKFDD_MODEL nBKFDDModel, BYTE *MainMem, BYTE *AddMem, CWnd *pParent /*=nullptr*/)
	: CDialogEx(CBKMEM_Dlg::IDD, pParent)
	, m_Memory(MainMem)
	, m_MemoryADD(AddMem)
	, m_BKModel(nBKModel)
	, m_BKFDDmodel(nBKFDDModel)
	, m_nTabsCount(0)
	, m_nSelectedTab(0)
{
	ZeroMemory(m_pContainers, sizeof(m_pContainers));
}

CBKMEM_Dlg::~CBKMEM_Dlg()
{
	//всё и без этого вроде бы удаляется, но если ещё раз вручную не удалять - получаются утечки памяти
	for (unsigned int i = 0; i < m_nTabsCount; ++i)
	{
		C16KPageContainer *pc = m_pContainers[i];

		if (pc)
		{
			pc->DestroyWindow();
			SAFE_DELETE(pc);
			m_pContainers[i] = pc;
		}
	}
}

void CBKMEM_Dlg::DoDataExchange(CDataExchange *pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TAB_MEMMAP, m_tab);
}

BEGIN_MESSAGE_MAP(CBKMEM_Dlg, CDialogEx)
	ON_WM_QUERYDRAGICON()
	ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_MEMMAP, &OnTcnSelchangeTab1)
END_MESSAGE_MAP()

BOOL CBKMEM_Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	//создаём вкладки
	switch (m_BKModel)
	{
		case BK_0010:
			CreateTabs_10();
			break;

		case BK_0011:
		case BK_0011M:
			CreateTabs_11M();
			break;

		default:
			ASSERT(FALSE); //неопределённых значений не должно быть в принципе
	}

	switch (m_BKFDDmodel)
	{
		default:
		case DEV_FDD_STD:
			break;

		case DEV_FDD_A16M:
			AddTabsA16M();
			break;

		case DEV_FDD_SMK512:
			AddTabsSMK512();
			break;
	}

	AdjustTab();
	m_pContainers[m_nSelectedTab]->ShowWindow(SW_SHOW);
	return TRUE; // возврат значения TRUE, если фокус не передан элементу управления
}

void CBKMEM_Dlg::OnTcnSelchangeTab1(NMHDR *pNMHDR, LRESULT *pResult)
{
	m_pContainers[m_nSelectedTab]->ShowWindow(SW_HIDE);
	m_nSelectedTab = m_tab.GetCurSel();

	if (m_nSelectedTab < 0)
	{
		m_nSelectedTab = 0;
	}

	m_pContainers[m_nSelectedTab]->ShowWindow(SW_SHOW);
	*pResult = S_OK;
}

void CBKMEM_Dlg::AdjustTab()
{
	CRect rectCont;
	m_pContainers[0]->GetWindowRect(rectCont);
	auto pCtrl = dynamic_cast<CTabCtrl *>(GetDlgItem(IDC_TAB_MEMMAP));
	pCtrl->AdjustRect(TRUE, rectCont);
	//как то задалбывает каждый раз SM_CYSMCAPTION вычитать.
	//неужели нету нормального способа скорректировать размер окна в зависимости от контента,
	//с учётом заголовка и рамок окна?
	rectCont.right -= GetSystemMetrics(SM_CXFRAME) * 2;
	rectCont.bottom -= (GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CYFRAME) * 2);
	pCtrl->MoveWindow(rectCont, FALSE);
	//волшебные числа 5 и 10 - это расстояние от рамки диалога до границы таба.
	//эти расстояния в общем то в мастере диалога заданы были, и как их автоматом применять
	//непонятно.
	CRect rectClient(0, 0,
	                 rectCont.Width() + 5 + GetSystemMetrics(SM_CXDLGFRAME) * 2,
	                 rectCont.Height() + 10 + GetSystemMetrics(SM_CYDLGFRAME) * 2);
	MoveWindow(rectClient, FALSE);
}

void CBKMEM_Dlg::CreateTabs_10()
{
	m_nTabsCount = 1;
	CString str, strwnd, strtab;
	unsigned int nUnique_num = 0, t1, t2;

	for (unsigned int i = 0; i < m_nTabsCount; ++i)
	{
		m_pContainers[i] = new C16KPageContainer(C16KP_NUM_PAGES);
		str.Format(_T("pgBK10_n%d"), nUnique_num);
		m_pContainers[i]->SetBuffer_Param(C16KP_FIRST_PAGE, m_Memory + i * 0100000,
		                                  040000, t1 = nUnique_num++, str);
		str.Format(_T("pgBK10_n%d"), nUnique_num);
		m_pContainers[i]->SetBuffer_Param(C16KP_SECOND_PAGE, m_Memory + i * 0100000 + 040000,
		                                  040000, t2 = nUnique_num++, str);
		strwnd.Format(_T("tabBK10_n%d"), i);

		if (!m_pContainers[i]->Create(nullptr, strwnd, WS_CHILD, CRect(0, 0, 200, 200), this, 0))
		{
#ifdef _DEBUG
			GetLastErrorOut(_T("TabBK10"));
#endif
			CBKMessageBox(_T("Неудача создания TabBK10"), MB_OK);
		}

		strtab.Format(_T("BK10_pg%d%d"), t1, t2);
		m_tab.InsertItem(i, strtab);
	}
}

void CBKMEM_Dlg::CreateTabs_11M()
{
	m_nTabsCount = 4;
	static unsigned int Pages[8] = { 0, 1, 2, 3, 5, 6, 4, 7 };
	CString str, strwnd, strtab;

	for (unsigned int i = 0; i < m_nTabsCount; ++i)
	{
		unsigned int n0 = Pages[i * 2];
		unsigned int n1 = Pages[i * 2 + 1];
		BYTE *buf0 = m_Memory + (n0 << 14);
		BYTE *buf1 = m_Memory + (n1 << 14);
		m_pContainers[i] = new C16KPageContainer(C16KP_NUM_PAGES);
		str.Format(_T("pgBK11M_n%d"), n0);
		m_pContainers[i]->SetBuffer_Param(C16KP_FIRST_PAGE, buf0, 040000, n0, str);
		str.Format(_T("pgBK11M_n%d"), n1);
		m_pContainers[i]->SetBuffer_Param(C16KP_SECOND_PAGE, buf1, 040000, n1, str);
		strwnd.Format(_T("tabBK11M_n%d"), i);

		if (!m_pContainers[i]->Create(nullptr, strwnd, WS_CHILD, CRect(0, 0, 200, 200), this, 0))
		{
#ifdef _DEBUG
			GetLastErrorOut(_T("TabBK11M"));
#endif
			CBKMessageBox(_T("Неудача создания TabBK11M"), MB_OK);
		}

		strtab.Format(_T("BK11M_pg%d%d"), n0, n1);
		m_tab.InsertItem(i, strtab);
	}
}

void CBKMEM_Dlg::AddTabsA16M()
{
	unsigned int i = m_nTabsCount++;
	CString str, strwnd, strtab;
	unsigned int nUnique_num = 0, t1;
	m_pContainers[i] = new C16KPageContainer(C16KP_NUM_PAGES - 1);
	str.Format(_T("pgA16M_n%d"), nUnique_num);
	m_pContainers[i]->SetBuffer_Param(C16KP_FIRST_PAGE, m_MemoryADD,
	                                  040000, t1 = nUnique_num++, str);
	strwnd.Format(_T("tabA16M_n%d"), i);

	if (!m_pContainers[i]->Create(nullptr, strwnd, WS_CHILD, CRect(0, 0, 200, 200), this, 0))
	{
#ifdef _DEBUG
		GetLastErrorOut(_T("TabA16M"));
#endif
		CBKMessageBox(_T("Неудача создания TabA16M"), MB_OK);
	}

	strtab.Format(_T("A16M_pg%d"), t1);
	m_tab.InsertItem(i, strtab);
}

void CBKMEM_Dlg::AddTabsSMK512()
{
	unsigned int n = m_nTabsCount;
	m_nTabsCount += 16;
	CString str, strwnd, strtab;
	unsigned int nUnique_num = 0, t1, t2;

	for (unsigned int i = n; i < m_nTabsCount; ++i)
	{
		m_pContainers[i] = new C16KPageContainer(C16KP_NUM_PAGES);
		str.Format(_T("pgSMK_n%d"), nUnique_num);
		m_pContainers[i]->SetBuffer_Param(C16KP_FIRST_PAGE, m_MemoryADD + (i - n) * 0100000,
		                                  040000, t1 = nUnique_num++, str);
		str.Format(_T("pgSMK_n%d"), nUnique_num);
		m_pContainers[i]->SetBuffer_Param(C16KP_SECOND_PAGE, m_MemoryADD + (i - n) * 0100000 + 040000,
		                                  040000, t2 = nUnique_num++, str);
		strwnd.Format(_T("tabSMK_n%d"), i);

		if (!m_pContainers[i]->Create(nullptr, strwnd, WS_CHILD, CRect(0, 0, 200, 200), this, 0))
		{
#ifdef _DEBUG
			GetLastErrorOut(_T("TabSMK512"));
#endif
			CBKMessageBox(_T("Неудача создания TabSMK512"), MB_OK);
		}

		strtab.Format(_T("SMK_pg%d%d"), t1, t2);
		m_tab.InsertItem(i, strtab);
	}
}

void CBKMEM_Dlg::DrawTab()
{
	m_pContainers[m_nSelectedTab]->Draw16KPages();
}


void CBKMEM_Dlg::OnCancel()
{
	CDialogEx::OnCancel();
	GetSafeOwner(this)->DestroyWindow();
}

// CBKMEMView

IMPLEMENT_DYNAMIC(CBKMEMView, CFrameWnd)

CBKMEMView::CBKMEMView(BOARD_MODEL nBKModel, BKFDD_MODEL BKFDDmodel, BYTE *MainMem, BYTE *AddMem)
{
	m_pdlgBKMem = new CBKMEM_Dlg(nBKModel, BKFDDmodel, MainMem, AddMem);
}

CBKMEMView::~CBKMEMView()
{
}

BEGIN_MESSAGE_MAP(CBKMEMView, CFrameWnd)
	ON_WM_DESTROY()
	ON_WM_CREATE()
END_MESSAGE_MAP()


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


int CBKMEMView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CFrameWnd::OnCreate(lpCreateStruct) == - 1)
	{
		return -1;
	}

	if (m_pdlgBKMem == nullptr)
	{
		return -1;
	}

	if (!m_pdlgBKMem->Create(IDD_BKMEM_MAP_DIALOG, this))
	{
		TRACE0("Не удалось создать диалог Memory Map\n");
		return -1; // не удалось создать
	}

	CRect rectClient;
	m_pdlgBKMem->GetClientRect(rectClient);
//так и не удаётся избавиться от волшебства
// как надо делать правильно - х.з. никто не знает, а микрософт не рассказывает.
#ifdef TARGET_WINXP
#define MAGIC_NUMBER 0
#else
#define MAGIC_NUMBER 5
#endif
	rectClient.right += GetSystemMetrics(SM_CXFRAME) * MAGIC_NUMBER;
	rectClient.bottom += GetSystemMetrics(SM_CYFRAME) * MAGIC_NUMBER + GetSystemMetrics(SM_CYSMCAPTION);
	ClientToScreen(rectClient);
	MoveWindow(rectClient, FALSE);
	return 0;
}

void CBKMEMView::DrawCurrentTab()
{
	if (m_lockStop.IsLocked())
	{
		return;
	}

	m_lockDraw.Lock();
	m_pdlgBKMem->DrawTab();
	m_lockDraw.UnLock();
}

void CBKMEMView::OnDestroy()
{
	m_lockStop.Lock();

	while (m_lockDraw.IsLocked())
	{
		Sleep(1); //тут может быть дедлок. если UI в m_pdlgBKMem->DrawTab() захочет сообщений;
	}

	//посылаем в MainFrame сообщение о закрытии всего этого тут
	::SendMessage(GetParentFrame()->GetSafeHwnd(), WM_MEMMAP_CLOSE, 0, 0);

	if (m_pdlgBKMem)
	{
		m_pdlgBKMem->DestroyWindow();
		delete m_pdlgBKMem;
	}

	CFrameWnd::OnDestroy();
}

/*
вот так эта вся херня выглядит.

CBKMEMView ------------------------------------------------------+
| CBKMEM_Dlg---------------------------------------------------+ |
| |  C16KPageContainer---------------------------------------+ | |
| |  | C16KPageView----------------------------------------+ | | |
| |  | | CScreen-------------------------------------+ +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | +-------------------------------------------+     | | | |
| |  | +---------------------------------------------------+ | | |
| |  | C16KPageView----------------------------------------+ | | |
| |  | | CScreen-------------------------------------+ +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | |                                           | +-+ | | | |
| |  | | +-------------------------------------------+     | | | |
| |  | +---------------------------------------------------+ | | |
| |  +-------------------------------------------------------+ | |
| +------------------------------------------------------------+ |
+----------------------------------------------------------------+
Справа от CScreen - кнопки
*/

