// ---------------------------------------------------------------------------
//  M88 - PC-8801 emulator
//	Copyright (C) cisc 2000.
// ---------------------------------------------------------------------------
//	$Id: mvmon.cpp,v 1.3 2001/02/21 11:58:55 cisc Exp $

#include "headers.h"
#include "resource.h"
#include "pc88/pc88.h"
#include "memmon.h"
#include "misc.h"
#include "device_i.h"

using namespace PC8801;

// ---------------------------------------------------------------------------
//	構築/消滅
//
MemViewMonitor::MemViewMonitor()
{
}

MemViewMonitor::~MemViewMonitor()
{
}

// ---------------------------------------------------------------------------
//	初期化
//
bool MemViewMonitor::Init(LPCTSTR tmpl, PC88* pc88, const char* inisection,
						  int defcols, int defrows)
{
	if (!WinMonitor::Init(tmpl, inisection, defcols, defrows))
		return false;
	mv.Init(pc88);
	bus = mv.GetBus();
	
	a0 = MemoryViewer::mainram;
	a6 = MemoryViewer::n88rom;
	ac = MemoryViewer::mainram;
	af = MemoryViewer::tvram;
	
	return true;
}

// ---------------------------------------------------------------------------
//	ダイアログ処理
//
BOOL MemViewMonitor::DlgProc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg)
	{
	case WM_INITDIALOG:
		SetBank();
		break;
		
	case WM_COMMAND:
		switch (LOWORD(wp))
		{
		case IDM_MEM_0_RAM:	a0 = MemoryViewer::mainram;	SetBank(); break;
		case IDM_MEM_0_N88:	a0 = MemoryViewer::n88rom;	SetBank(); break;
		case IDM_MEM_0_N:	a0 = MemoryViewer::nrom;	SetBank(); break;
		case IDM_MEM_0_SUB: a0 = MemoryViewer::sub;     SetBank(); break;
		case IDM_MEM_0_ERAM0: a0 = MemoryViewer::eram0;     SetBank(); break;
		case IDM_MEM_0_ERAM1: a0 = MemoryViewer::eram1;     SetBank(); break;
		case IDM_MEM_0_ERAM2: a0 = MemoryViewer::eram2;     SetBank(); break;
		case IDM_MEM_0_ERAM3: a0 = MemoryViewer::eram3;     SetBank(); break;
		case IDM_MEM_6_N88:	a6 = MemoryViewer::n88rom;	SetBank(); break;
		case IDM_MEM_6_E0:	a6 = MemoryViewer::n88e0;	SetBank(); break;
		case IDM_MEM_6_E1:	a6 = MemoryViewer::n88e1;	SetBank(); break;
		case IDM_MEM_6_E2:	a6 = MemoryViewer::n88e2;	SetBank(); break;
		case IDM_MEM_6_E3:	a6 = MemoryViewer::n88e3;	SetBank(); break;
		case IDM_MEM_F_RAM:	af = MemoryViewer::mainram;	SetBank(); break;
		case IDM_MEM_F_TVRAM:af= MemoryViewer::tvram;	SetBank(); break;
		case IDM_MEM_C_RAM:	ac = MemoryViewer::mainram;	SetBank(); break;
		case IDM_MEM_C_GV0:	ac = MemoryViewer::gvram0;	SetBank(); break;
		case IDM_MEM_C_GV1:	ac = MemoryViewer::gvram1;	SetBank(); break;
		case IDM_MEM_C_GV2:	ac = MemoryViewer::gvram2;	SetBank(); break;

		case IDM_MEM_STATCLEAR: mv.StatClear(); break;

		case IDM_MEM_GOTO:
			GotoAddress();
			break;
	
		case IDM_CLOSE:
			PostMessage(hdlg, WM_CLOSE, 0, 0);
			break;
		}
		break;

	case WM_KEYDOWN:
		if (wp == 'G' && (GetKeyState(VK_CONTROL) & 0x8000))
		{
			GotoAddress();
			return 0;
		}
		break;

	case WM_INITMENU:
		{
			HMENU hmenu = (HMENU) wp;
			CheckMenuItem(hmenu, IDM_MEM_0_RAM, (a0 == MemoryViewer::mainram) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_0_N88, (a0 == MemoryViewer::n88rom ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_0_N,   (a0 == MemoryViewer::nrom   ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_0_ERAM0, (a0 == MemoryViewer::eram0 ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_0_ERAM1, (a0 == MemoryViewer::eram1 ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_0_ERAM2, (a0 == MemoryViewer::eram2 ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_0_ERAM3, (a0 == MemoryViewer::eram3 ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_0_SUB, (a0 == MemoryViewer::sub    ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_6_N88, (a6 == MemoryViewer::n88rom ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_6_E0,  (a6 == MemoryViewer::n88e0  ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_6_E1,  (a6 == MemoryViewer::n88e1  ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_6_E2,  (a6 == MemoryViewer::n88e2  ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_6_E3,  (a6 == MemoryViewer::n88e3  ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_F_RAM, (af == MemoryViewer::mainram) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_F_TVRAM,(af== MemoryViewer::tvram  ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_C_RAM, (ac == MemoryViewer::mainram) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_C_GV0, (ac == MemoryViewer::gvram0 ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_C_GV1, (ac == MemoryViewer::gvram1 ) ? MF_CHECKED : MF_UNCHECKED);
			CheckMenuItem(hmenu, IDM_MEM_C_GV2, (ac == MemoryViewer::gvram2 ) ? MF_CHECKED : MF_UNCHECKED);
			int x = a0 != MemoryViewer::n88rom ? MF_GRAYED : MF_ENABLED;
			EnableMenuItem(hmenu, IDM_MEM_6_N88, x);
			EnableMenuItem(hmenu, IDM_MEM_6_E0,  x);
			EnableMenuItem(hmenu, IDM_MEM_6_E1,  x);
			EnableMenuItem(hmenu, IDM_MEM_6_E2,  x);
			EnableMenuItem(hmenu, IDM_MEM_6_E3,  x);
			// GVRAM 選択中は $c000-$ffff 全部を占有するので &f000 は無効化する
			int fx = ac != MemoryViewer::mainram ? MF_GRAYED : MF_ENABLED;
			EnableMenuItem(hmenu, IDM_MEM_F_RAM,   fx);
			EnableMenuItem(hmenu, IDM_MEM_F_TVRAM, fx);
			break;
		}
	}
	return WinMonitor::DlgProc(hdlg, msg, wp, lp);
}

// ---------------------------------------------------------------------------
//	バンク変更
//
void MemViewMonitor::SetBank()
{
	MemoryViewer::Type t6;
	if (a0 == MemoryViewer::n88rom)
		t6 = a6;
	else
		t6 = a0;
	mv.SelectBank(a0, t6, MemoryViewer::mainram, ac, af);
	Update();
}


uint MemViewMonitor::StatExec(uint a)
{
	int ex = mv.StatExec(a);
	if (!ex)
		return 0;
	return ex < 0x4 ? (ex + 4) * 0x10 : Min(ex+0x80-0x04, 0xc0);
}

void MemViewMonitor::StatClear()
{
//	mv.StatClear();
	uint* st = mv.StatExecBuf();
	if (st)
	{
		for (int i=0; i<0x10000; i++)
		{
			*st = (*st+1) / 2;
			st++;
		}
	}
}

// ---------------------------------------------------------------------------
//	任意アドレスへ飛ぶ
//
void MemViewMonitor::GotoAddress()
{
	DialogBoxParam(GetHInst(), MAKEINTRESOURCE(IDD_ADDR_GOTO),
				   GetHWnd(), DLGPROC((void*)GotoDlgProcGate), (LPARAM)this);
}

BOOL MemViewMonitor::GotoDlgProc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp)
{
	char buf[16];
	switch (msg)
	{
	case WM_INITDIALOG:
		SetFocus(GetDlgItem(hdlg, IDC_ADDR_GOTO_EDIT));
		return 0;

	case WM_COMMAND:
		if (HIWORD(wp) == BN_CLICKED)
		{
			switch (LOWORD(wp))
			{
				char* dum;
			case IDOK:
				GetDlgItemText(hdlg, IDC_ADDR_GOTO_EDIT, buf, sizeof(buf));
				if (isxdigit((unsigned char) buf[0]))
				{
					uint addr = strtoul(buf, &dum, 16) & 0xffff;
					JumpTo(addr);
					Update();
				}
			case IDCANCEL:
				EndDialog(hdlg, false);
				break;
			}
		}
		return 0;

	case WM_CLOSE:
		EndDialog(hdlg, false);
		return true;

	default:
		return false;
	}
}

BOOL CALLBACK MemViewMonitor::GotoDlgProcGate
(HWND hwnd, UINT m, WPARAM w, LPARAM l)
{
	MemViewMonitor* mon = 0;

	if ( m == WM_INITDIALOG ) {
		mon = reinterpret_cast<MemViewMonitor*>(l);
		if (mon) {
			::SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)mon );
		}
	} else {
		mon = (MemViewMonitor*)::GetWindowLongPtr( hwnd, GWLP_USERDATA );
	}

	if (mon) {
		return mon->GotoDlgProc(hwnd, m, w, l);
	} else {
		return FALSE;
	}
}
