/***************************************************************************
**
**    $Header:   D:/EPSLDV1/SRC/LOG/SPAENTRY.CPP   1.8   20 Jun 1996 09:24:48   ZJRD  $
**
**    $Log:   D:/EPSLDV1/SRC/LOG/SPAENTRY.CPP  $
** 
**    Rev 1.8   20 Jun 1996 09:24:48   ZJRD
** EasyPack/SLD Version 1.20a
** 
**    Rev 1.6   10 Jun 1996 10:19:26   ZJRD
** EasyPack/SLD Version 1.20
** 
**    Rev 1.4   29 May 1996 09:28:30   ZJRD
** EasyPack/SLD Version 1.95
** 
**    Rev 1.3   16 May 1996 09:08:52   ZJRD
** EasyPack/SLD Version 1.94
** 
**    Rev 1.2   10 May 1996 09:08:20   ZJRD
** EasyPack/SLD Version 1.93
** 
**    Rev 1.1   02 May 1996 10:26:18   ZJRD
** EasyPack/SLD Version 1.92
** 
**    Rev 1.1   18 Apr 1996 12:54:10   Shirley
** EasyPack/SLD Version 1.91
** 
**    Rev 1.0   12 Apr 1996 10:36:16   Shirley
** Initial revision.
** 
****************************************************************************/

/////////////////////////////////////////////////////////////////////////////
//
//  File name: SPAENTRY.CPP
//
//  Description: The implementation file fore class: CSpaModuleEntryPage.
//
//  Author: Chen Jun
//
//  Date: 03/21/96
//
//  Modification:
//      1. 03/21/96, Initial version of the class: CSpaModuleEntryDlg.
//      2. 03/29/96, CSpaModuleEntryPage with CPropertyPage.
//		3. 05/08/96, According to Fax: 960502-M1, I changed all the related
//					 codes. We would refer to V1.92 from PVCS if we should
//				     recover to the old version. It would include *.RES, 
//					 resource.h & spaentry.*.
//
//  Copyright (C) 1996 Microtek International. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"

#include "spagrp.h"
#include "spauser.h"
#include "spabp.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// External variables.
extern char szAppPath[_MAX_PATH+1];

STATUS AbiSpaBpSet(SPABPSETINFO spaBpSetInfor);
STATUS AbiGetOneReg(int iRegId, UINT* uRegValue);
STATUS AbiGo(FLAG runFlag, ADDR fromAddr, ADDR tillAddr);
STATUS AbiGetTimerCount(TIMER_COUNT *pTimerCount);
STATUS AbiAbort();
void RestoreAllConfig(void);

/////////////////////////////////////////////////////////////////////////////
// CSpaModuleEntryPage dialog

CSpaModuleEntryPage::CSpaModuleEntryPage()
	: CPropertyPage(CSpaModuleEntryPage::IDD),
    m_uTimerID(0), m_cdwMaxTime(1000000000), m_cnMaxCount(10000),
    m_bStop(TRUE), m_nWhichModule(module0),	m_nWhichBtn(btnStart)
{
	//{{AFX_DATA_INIT(CSpaModuleEntryPage)
	m_nSelect = -1;
	m_strRange1 = _T("");
	m_strRange2 = _T("");
	m_strRange3 = _T("");
	m_strRange4 = _T("");
	m_nCount0 = 0;
	m_dwTime0 = 0;
	m_nCount1 = 0;
	m_nCount2 = 0;
	m_nCount3 = 0;
	m_nCount4 = 0;
	m_dwTime1 = 0;
	m_dwTime2 = 0;
	m_dwTime3 = 0;
	m_dwTime4 = 0;
	m_strRange0 = _T("");
	//}}AFX_DATA_INIT

	// Initial.
	m_nCountPer1 = 0;
	m_nCountPer2 = 0;
	m_nCountPer3 = 0;
	m_nCountPer4 = 0;
	m_nTimePer1 = 0;
	m_nTimePer2 = 0;
	m_nTimePer3 = 0;
	m_nTimePer4 = 0;
}

void CSpaModuleEntryPage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSpaModuleEntryPage)
	DDX_Control(pDX, IDC_BUTTON_SPA_BP, m_btnBp);
	DDX_Control(pDX, IDC_BUTTON_SPA_RESTART, m_btnRestart);
	DDX_Control(pDX, IDC_STATIC_SPA_TIMEBAR1, m_staticTimeBar1);
	DDX_Control(pDX, IDC_STATIC_SPA_TIMEBAR2, m_staticTimeBar2);
	DDX_Control(pDX, IDC_STATIC_SPA_TIMEBAR3, m_staticTimeBar3);
	DDX_Control(pDX, IDC_STATIC_SPA_TIMEBAR4, m_staticTimeBar4);
	DDX_Control(pDX, IDC_STATIC_SPA_COUNTBAR1, m_staticCountBar1);
	DDX_Control(pDX, IDC_STATIC_SPA_COUNTBAR2, m_staticCountBar2);
	DDX_Control(pDX, IDC_STATIC_SPA_COUNTBAR3, m_staticCountBar3);
	DDX_Control(pDX, IDC_STATIC_SPA_COUNTBAR4, m_staticCountBar4);
	DDX_Control(pDX, IDC_BUTTON_SPA_EDIT, m_btnEdit);
	DDX_Control(pDX, IDC_BUTTON_SPA_STOP, m_btnStop);
	DDX_Control(pDX, IDC_BUTTON_SPA_START, m_btnStart);
	DDX_Control(pDX, IDC_LIST_SPA_ENTRY, m_listEntry);
	DDX_Control(pDX, IDC_COMBO_SPA_RANGE4, m_comboRange4);
	DDX_Control(pDX, IDC_COMBO_SPA_RANGE3, m_comboRange3);
	DDX_Control(pDX, IDC_COMBO_SPA_RANGE2, m_comboRange2);
	DDX_Control(pDX, IDC_COMBO_SPA_RANGE1, m_comboRange1);
	DDX_LBIndex(pDX, IDC_LIST_SPA_ENTRY, m_nSelect);
	DDX_CBString(pDX, IDC_COMBO_SPA_RANGE1, m_strRange1);
	DDV_MaxChars(pDX, m_strRange1, 80);
	DDX_CBString(pDX, IDC_COMBO_SPA_RANGE2, m_strRange2);
	DDV_MaxChars(pDX, m_strRange2, 80);
	DDX_CBString(pDX, IDC_COMBO_SPA_RANGE3, m_strRange3);
	DDV_MaxChars(pDX, m_strRange3, 80);
	DDX_CBString(pDX, IDC_COMBO_SPA_RANGE4, m_strRange4);
	DDV_MaxChars(pDX, m_strRange4, 80);
	DDX_Text(pDX, IDC_EDIT_SPA_COUNT0, m_nCount0);
	DDV_MinMaxInt(pDX, m_nCount0, 0, 30000);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME0, m_dwTime0);
	DDV_MinMaxDWord(pDX, m_dwTime0, 0, 30000000);
	DDX_Text(pDX, IDC_EDIT_SPA_COUNT1, m_nCount1);
	DDV_MinMaxInt(pDX, m_nCount1, 0, 10000);
	DDX_Text(pDX, IDC_EDIT_SPA_COUNT2, m_nCount2);
	DDV_MinMaxInt(pDX, m_nCount2, 0, 10000);
	DDX_Text(pDX, IDC_EDIT_SPA_COUNT3, m_nCount3);
	DDV_MinMaxInt(pDX, m_nCount3, 0, 10000);
	DDX_Text(pDX, IDC_EDIT_SPA_COUNT4, m_nCount4);
	DDV_MinMaxInt(pDX, m_nCount4, 0, 10000);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME1, m_dwTime1);
	DDV_MinMaxDWord(pDX, m_dwTime1, 0, 10000000);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME2, m_dwTime2);
	DDV_MinMaxDWord(pDX, m_dwTime2, 0, 10000000);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME3, m_dwTime3);
	DDV_MinMaxDWord(pDX, m_dwTime3, 0, 10000000);
	DDX_Text(pDX, IDC_EDIT_SPA_TIME4, m_dwTime4);
	DDV_MinMaxDWord(pDX, m_dwTime4, 0, 10000000);
	DDX_Control(pDX, IDC_EDIT_SPA_DEFINE_BP, m_editBp);
	DDX_Text(pDX, IDC_EDIT_SPA_DEFINE_BP, m_strRange0);
	DDV_MaxChars(pDX, m_strRange0, 80);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CSpaModuleEntryPage, CPropertyPage)
	//{{AFX_MSG_MAP(CSpaModuleEntryPage)
	ON_BN_CLICKED(ID_HELP, OnHelp)
	ON_BN_CLICKED(IDC_BUTTON_SPA_EDIT, OnButtonSpaEdit)
	ON_BN_CLICKED(IDC_BUTTON_SPA_START, OnButtonSpaStart)
	ON_BN_CLICKED(IDC_BUTTON_SPA_STOP, OnButtonSpaStop)
	ON_WM_SHOWWINDOW()
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BUTTON_SPA_RESTART, OnButtonSpaRestart)
	ON_BN_CLICKED(IDC_BUTTON_SPA_BP, OnButtonSpaBp)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSpaModuleEntryPage common routines

void CSpaModuleEntryPage::CheckInputSyntax(void)
{
	// Check empty.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	if ( m_strRange0.IsEmpty() ) {
		pSheet->m_nErrorID = pSheet->errInput;
		return;
	}
		
	if ( m_strRange1.IsEmpty() && 
		 m_strRange2.IsEmpty() && 
		 m_strRange3.IsEmpty() && 
		 m_strRange4.IsEmpty() ) {
		pSheet->m_nErrorID = pSheet->errInput;
		return;
	}
}

void CSpaModuleEntryPage::UpdateBar(void)
{
	// Get entry data.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	int nRet = GetEntryData();
	
	// Ignore when running.
	if ( running == nRet ) {
		return;
	}

	// When failuer has been detected.
	if ( failure == nRet ) {
		// Stop timer action.
		StopTimerAction();

		// Prompt.
		pSheet->m_nErrorID = pSheet->errRange;
		pSheet->DisplayErrorMessage();
		return;
	}

	// Update count bar.
	UpdateData(FALSE);
	for ( int i(1); i <= 4; i++ ) {
		UpdateCountBar(i);
	}
	
	// Update timer bar.
	for ( i = 1; i <= 4; i++ ) {
		UpdateTimerBar(i);
	}
	
	// Kill timer if Stop.
	if ( stop == nRet ) {
		StopTimerAction();
		return;
	}
	
	// Continue to go when pause.
	if ( pause == nRet ) {
		// Go Till End.
		::ADDR FromAddr, TillAddr;
		memset(&FromAddr, 0, sizeof(FromAddr));

		TillAddr.addrType = MEM_CODE;
		TillAddr.addr = m_EntryInfo.goArgument.addrTo.addr;

		if ( ::ICE_OK != ::AbiGo(0, FromAddr, TillAddr) ) {
			StopTimerAction();
			pSheet->m_nErrorID = pSheet->errAbi;
			pSheet->DisplayErrorMessage();
			return;
		}
	}
}

void CSpaModuleEntryPage::StopTimerAction(void)
{
	// Kill timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
		m_uTimerID = 0;
	}

	// Grayed some controls.
	m_bStop = TRUE;
	DisableControl();
}

void CSpaModuleEntryPage::UpdateCountBar(int nWhich, BOOL bRedraw)
{
	// Assign a static control.
	CWnd* pWnd;
	int nPercent;
	switch ( nWhich ) {
		case 1:
			pWnd = &m_staticCountBar1;
			nPercent = m_nCountPer1;
			break;
		case 2:
			pWnd = &m_staticCountBar2;
			nPercent = m_nCountPer2;
			break;
		case 3:
			pWnd = &m_staticCountBar3;
			nPercent = m_nCountPer3;
			break;
		case 4:
			pWnd = &m_staticCountBar4;
			nPercent = m_nCountPer4;
			break;
		default:
			ASSERT(FALSE);
			return;
	}
	
	// No change.
	if ( 0 == nPercent && bRedraw ) {
		return;
	}

	// Update timer bar.
	CDC* pDC = pWnd->GetDC();

	CBrush brushGray(RGB(192,192,192));
	CBrush* pBrushOld = pDC->SelectObject(&brushGray);
	CRect rect;
	pWnd->GetClientRect(rect);
	rect.left += 1;
	rect.top += 1;
	rect.right -= 1;
	rect.bottom -= 1;
	pDC->FillRect(rect, &brushGray);
	pDC->SelectObject(pBrushOld);

	if ( bRedraw ) {
		CBrush brushRed(RGB(255,0,0));
		pBrushOld = pDC->SelectObject(&brushRed);
		rect.right = rect.right * nPercent / 100;
		rect.right =  rect.right <= rect.left ? rect.left + 1 : rect.right;
		pDC->FillRect(rect, &brushRed);
		pDC->SelectObject(pBrushOld);
		
		// Set percentage.
		CString strPer;
		strPer.Format("%d %%", nPercent);
		pDC->SetTextColor(RGB(0,0,0));
		pDC->SetBkMode(TRANSPARENT);
		pWnd->GetClientRect(rect);
		pDC->TextOut(rect.Width()/2-12, 2, strPer);
	}

	pWnd->ReleaseDC(pDC);
}

void CSpaModuleEntryPage::UpdateTimerBar(int nWhich, BOOL bRedraw)
{
	// Assign a static control.
	CWnd* pWnd;
	int nPercent;
	switch ( nWhich ) {
		case 1:
			pWnd = &m_staticTimeBar1;
			nPercent = m_nTimePer1;
			break;
		case 2:
			pWnd = &m_staticTimeBar2;
			nPercent = m_nTimePer2;
			break;
		case 3:
			pWnd = &m_staticTimeBar3;
			nPercent = m_nTimePer3;
			break;
		case 4:
			pWnd = &m_staticTimeBar4;
			nPercent = m_nTimePer4;
			break;
		default:
			ASSERT(FALSE);
			return;
	}

	// No change.
	if ( 0 == nPercent && bRedraw ) {
		return;
	}

	// Update timer bar.
	CDC* pDC = pWnd->GetDC();

	CBrush brushGray(RGB(192,192,192));
	CBrush* pBrushOld = pDC->SelectObject(&brushGray);
	CRect rect;
	pWnd->GetClientRect(rect);
	rect.left += 1;
	rect.top += 1;
	rect.right -= 1;
	rect.bottom -= 1;
	pDC->FillRect(rect, &brushGray);
	pDC->SelectObject(pBrushOld);

	if ( bRedraw ) {
		CBrush brushRed(RGB(255,0,0));
		pBrushOld = pDC->SelectObject(&brushRed);
		rect.right = rect.right * nPercent / 100;
		rect.right =  rect.right <= rect.left ? rect.left + 1 : rect.right;
		pDC->FillRect(rect, &brushRed);
		pDC->SelectObject(pBrushOld);

		// Set percentage.
		CString strPer;
		strPer.Format("%d %%", nPercent);
		pDC->SetTextColor(RGB(0,0,0));
		pDC->SetBkMode(TRANSPARENT);
		pWnd->GetClientRect(rect);
		pDC->TextOut(rect.Width()/2-12, 2, strPer);
	}

	pWnd->ReleaseDC(pDC);
}

void CSpaModuleEntryPage::DisableControl(void)
{
	// Enable / disable buttons.
	m_btnStart.EnableWindow(m_bStop);
	m_btnRestart.EnableWindow(m_bStop);
	m_btnEdit.EnableWindow(m_bStop);
	m_btnBp.EnableWindow(m_bStop);
	m_editBp.EnableWindow(m_bStop);
	m_btnStop.EnableWindow(!m_bStop);
	
	// Enable combo boxes.
	m_comboRange1.EnableWindow(m_bStop);
	m_comboRange2.EnableWindow(m_bStop);
	m_comboRange3.EnableWindow(m_bStop);
	m_comboRange4.EnableWindow(m_bStop);

	// Enable ESC to cancel this page.
	SetFocus();
}

void CSpaModuleEntryPage::GetExecuteRange()
{
	// Get start address.
	char szPC[33+1];
	UINT uPC;
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();

	switch ( m_nWhichBtn ) {
		case btnStart:
			// Get the current PC.
			if ( ::ICE_OK != ::AbiGetOneReg(0, &uPC) ) {
				ultoa(pSheet->m_uPC, szPC, 16);
			}
			else {
				ultoa(uPC, szPC, 16);
			}
			break;
		case btnRestart:
			// Get the old PC.
			ultoa(pSheet->m_uPC, szPC, 16);
			break;
		default:
			ASSERT(FALSE);
			return;
	}
	
	// Get the end BP.
	pSheet->m_strStart = szPC;
	pSheet->m_strEnd = m_strRange0;
}

BOOL CSpaModuleEntryPage::SetEntryData(void)
{
	// Initial when restart.
	memset(&m_EntryInfo, 0, sizeof(m_EntryInfo));
	memset(&m_Addr, 0, sizeof(m_Addr));

	m_nCount1 = 0;
	m_nCount2 = 0;
	m_nCount3 = 0;
	m_nCount4 = 0;
	
	m_dwTime1 = 0;
	m_dwTime2 = 0;
	m_dwTime3 = 0;
	m_dwTime4 = 0;

	// Convert input data.
	::ADDRESS Addr;
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	pSheet->EmptyBuffer();

	// Convert execution range.
	GetExecuteRange();
	if ( pSheet->m_strStart.IsEmpty() ) {
		pSheet->m_nErrorID = pSheet->errInput;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}
	else {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ||
			 !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strStart, Addr);
			m_EntryInfo.goArgument.addrFrom.addr = (WORD&)(Addr.adrAddress);
			m_EntryInfo.goArgument.addrFrom.addrType = (FLAG&)(Addr.adrSpace);
			::AdrTextToAddr(pSheet->m_strEnd, Addr);
			m_EntryInfo.goArgument.addrTo.addr = (WORD&)(Addr.adrAddress);
			m_EntryInfo.goArgument.addrTo.addrType = (FLAG&)(Addr.adrSpace);
		}
	}
	
	// Convert Module 1 range.
	ReadRecord(entryRange, m_strRange1);
	if ( !pSheet->m_strStart.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strStart, Addr);
			m_Addr[0].addrType = MEM_CODE;
			m_Addr[0].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[0].addr;
		}
	}
	if ( !pSheet->m_strEnd.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strEnd, Addr);
			m_Addr[1].addrType = MEM_CODE;
			m_Addr[1].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[1].addr;
		}
	}

	// Convert Module 2 range.
	ReadRecord(entryRange, m_strRange2);
	if ( !pSheet->m_strStart.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strStart, Addr);
			m_Addr[2].addrType = MEM_CODE;
			m_Addr[2].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[2].addr;
		}
	}
	if ( !pSheet->m_strEnd.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strEnd, Addr);
			m_Addr[3].addrType = MEM_CODE;
			m_Addr[3].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[3].addr;
		}
	}

	// Convert Module 3 range.
	ReadRecord(entryRange, m_strRange3);
	if ( !pSheet->m_strStart.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strStart, Addr);
			m_Addr[4].addrType = MEM_CODE;
			m_Addr[4].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[4].addr;
		}
	}
	if ( !pSheet->m_strEnd.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strEnd, Addr);
			m_Addr[5].addrType = MEM_CODE;
			m_Addr[5].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[5].addr;
		}
	}
	
	// Convert Module 4 range.
	ReadRecord(entryRange, m_strRange4);
	if ( !pSheet->m_strStart.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strStart) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strStart, Addr);
			m_Addr[6].addrType = MEM_CODE;
			m_Addr[6].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[6].addr;
		}
	}
	if ( !pSheet->m_strEnd.IsEmpty() ) {
		if ( !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		else {
			::AdrTextToAddr(pSheet->m_strEnd, Addr);
			m_Addr[7].addrType = MEM_CODE;
			m_Addr[7].addr = (unsigned short&)(Addr.adrAddress);
			m_EntryInfo.usAddr[m_EntryInfo.uchNumber++] = m_Addr[7].addr;
		}
	}
	
	// Call ABI routine.
	if ( ::ICE_OK != ::AbiSpaBpSet(m_EntryInfo) ) {
		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}

	return TRUE;
}

BOOL CSpaModuleEntryPage::GetEntryData(void)
{
	// Call ABI routine.
	UINT uPC;
	int nStatus = ::AbiGetOneReg(0, &uPC);

	// EP Running.
	if ( ::ICE_EP_RUNNING == nStatus ) {
		return running;
	}

	// Till end.
	if ( uPC == m_EntryInfo.goArgument.addrTo.addr ) {
		if ( !CalcResult() ) {
			return failure;
		}
		else {
			return stop;
		}
	}

	// Pause.
	if ( uPC == m_Addr[0].addr && MEM_CODE == m_Addr[0].addrType ) {
		m_nWhichModule = module1;
		m_nCount1++;
	}
	else if ( uPC == m_Addr[2].addr && MEM_CODE == m_Addr[2].addrType ) {
		m_nWhichModule = module2;
		m_nCount2++;
	}
	else if ( uPC == m_Addr[4].addr && MEM_CODE == m_Addr[4].addrType ) {
		m_nWhichModule = module3;
		m_nCount3++;
	}
	else if ( uPC == m_Addr[6].addr && MEM_CODE == m_Addr[6].addrType ) {
		m_nWhichModule = module4;
		m_nCount4++;
	}
	else if ( uPC == m_Addr[1].addr && MEM_CODE == m_Addr[1].addrType ) {
		if ( module1 == m_nWhichModule ) {
			::TIMER_COUNT Timer;
			if ( ::ICE_OK == ::AbiGetTimerCount(&Timer) ) {
				unsigned long ul = Timer.ulLowCount;
				m_dwTime1 += ( 0 == ul ) ? m_cdwMaxTime : ul;
			}
			else {
				return failure;
			}
		}
		m_nWhichModule = module0;
	}
	else if ( uPC == m_Addr[3].addr && MEM_CODE == m_Addr[3].addrType ) {
		if ( module2 == m_nWhichModule ) {
			::TIMER_COUNT Timer;
			if ( ::ICE_OK == ::AbiGetTimerCount(&Timer) ) {
				unsigned long ul = Timer.ulLowCount;
				m_dwTime2 += ( 0 == ul ) ? m_cdwMaxTime : ul;
			}
			else {
				return failure;
			}
		}
		m_nWhichModule = module0;
	}
	else if ( uPC == m_Addr[5].addr && MEM_CODE == m_Addr[5].addrType ) {
		if ( module3 == m_nWhichModule ) {
			::TIMER_COUNT Timer;
			if ( ::ICE_OK == ::AbiGetTimerCount(&Timer) ) {
				unsigned long ul = Timer.ulLowCount;
				m_dwTime3 += ( 0 == ul ) ? m_cdwMaxTime : ul;
			}
			else {
				return failure;
			}
		}
		m_nWhichModule = module0;
	}
	else if ( uPC == m_Addr[7].addr && MEM_CODE == m_Addr[7].addrType ) {
		if ( module4 == m_nWhichModule ) {
			::TIMER_COUNT Timer;
			if ( ::ICE_OK == ::AbiGetTimerCount(&Timer) ) {
				unsigned long ul = Timer.ulLowCount;
				m_dwTime4 += ( 0 == ul ) ? m_cdwMaxTime : ul;
			}
			else {
				return failure;
			}
		}
		m_nWhichModule = module0;
	}
	else {
//	    ASSERT(FALSE);	// Assertion will be caused by HALT.
//		return failure;
		return stop;
	}

	// Calculate result.
	if ( !CalcResult() ) {
		return failure;
	}

	return pause;
}

BOOL CSpaModuleEntryPage::CalcResult(void)
{
	// Calculate the count.
	if ( !CalcCount() ) {
		return FALSE;
	}
	
	// Calculate the time.
	if ( !CalcTimer() ) {
		return FALSE;
	}

	return TRUE;
}

BOOL CSpaModuleEntryPage::CalcCount(void)
{
	// Adjust count range.
	if ( m_nCount1 < 0 || 
		 m_nCount2 < 0 || 
		 m_nCount3 < 0 || 
		 m_nCount4 < 0 ) {
		return FALSE;
	}

	if ( m_nCount1 > m_cnMaxCount || 
		 m_nCount2 > m_cnMaxCount || 
		 m_nCount3 > m_cnMaxCount || 
		 m_nCount4 > m_cnMaxCount ) {
		return FALSE;
	}

	m_nCount0 = m_nCount1 + m_nCount2 + m_nCount3 + m_nCount4;
	if ( m_nCount0 < 0 || m_nCount0 > m_cnMaxCount * 3 ) {
		return FALSE;
	}

	// Calculate the count percentage.
	if ( 0 == m_nCount0 ) {
		m_nCountPer1 = 0;
		m_nCountPer2 = 0;
		m_nCountPer3 = 0;
		m_nCountPer4 = 0;
	}
	else {
		m_nCountPer1 = int(long(m_nCount1 * 100) / long(m_nCount0));
		m_nCountPer2 = int(long(m_nCount2 * 100) / long(m_nCount0));
		m_nCountPer3 = int(long(m_nCount3 * 100) / long(m_nCount0));
		m_nCountPer4 = int(long(m_nCount4 * 100) / long(m_nCount0));
	}
	if ( m_nCountPer1 < 0 || 
		 m_nCountPer2 < 0 || 
		 m_nCountPer3 < 0 || 
		 m_nCountPer4 < 0 ) {
		return FALSE;
	}
	if ( m_nCountPer1 > 100 || 
		 m_nCountPer2 > 100 || 
		 m_nCountPer3 > 100 || 
		 m_nCountPer4 > 100 ) {
		return FALSE;
	}
	if ( 0 == m_nCountPer1 && 0 != m_nCount1 ) {
		m_nCountPer1 = 1;
	}
	if ( 0 == m_nCountPer2 && 0 != m_nCount2 ) {
		m_nCountPer2 = 1;
	}
	if ( 0 == m_nCountPer3 && 0 != m_nCount3 ) {
		m_nCountPer3 = 1;
	}
	if ( 0 == m_nCountPer4 && 0 != m_nCount4 ) {
		m_nCountPer4 = 1;
	}
		
	return TRUE;
}

BOOL CSpaModuleEntryPage::CalcTimer(void)
{
	// Adjust count range.
	if ( m_dwTime1 < 0 || 
		 m_dwTime2 < 0 || 
		 m_dwTime3 < 0 || 
		 m_dwTime4 < 0 ) {
		return FALSE;
	}

	if ( m_dwTime1 > m_cdwMaxTime || 
		 m_dwTime2 > m_cdwMaxTime || 
		 m_dwTime3 > m_cdwMaxTime || 
		 m_dwTime4 > m_cdwMaxTime ) {
		return FALSE;
	}

	m_dwTime0 = m_dwTime1 + m_dwTime2 + m_dwTime3 + m_dwTime4;
	if ( m_dwTime0 < 0 || m_dwTime0 > m_cdwMaxTime * 3 ) {
		return FALSE;
	}

	// Calculate the count percentage.
	if ( 0 == m_dwTime0 ) {
		m_nTimePer1 = 0;
		m_nTimePer2 = 0;
		m_nTimePer3 = 0;
		m_nTimePer4 = 0;
	}
	else {
		m_nTimePer1 = int(m_dwTime1 * 100 / m_dwTime0);
		m_nTimePer2 = int(m_dwTime2 * 100 / m_dwTime0);
		m_nTimePer3 = int(m_dwTime3 * 100 / m_dwTime0);
		m_nTimePer4 = int(m_dwTime4 * 100 / m_dwTime0);
	}

	if ( 0 == m_nTimePer1 && 0 != m_dwTime1 ) {
		m_nTimePer1 = 1;
	}
	if ( 0 == m_nTimePer2 && 0 != m_dwTime2 ) {
		m_nTimePer2 = 1;
	}
	if ( 0 == m_nTimePer3 && 0 != m_dwTime3 ) {
		m_nTimePer3 = 1;
	}
	if ( 0 == m_nTimePer4 && 0 != m_dwTime4 ) {
		m_nTimePer4 = 1;
	}

	return TRUE;
}

void CSpaModuleEntryPage::UpdateCombo(void)
{
	// Remove all from the combo boxes.
	m_comboRange1.ResetContent();
	m_comboRange2.ResetContent();
	m_comboRange3.ResetContent();
	m_comboRange4.ResetContent();
	
	// Read user defined name.
	ReadRecord(entryRange, combo1);
	ReadRecord(entryRange, combo2);
	ReadRecord(entryRange, combo3);
	ReadRecord(entryRange, combo4);

/*
	// Add an empty string to the combo boxes.
	m_comboRange1.AddString("");
	m_comboRange2.AddString("");
	m_comboRange3.AddString("");
	m_comboRange4.AddString("");
*/

	// Select the default setting.
	int nCount = m_comboRange1.GetCount();
	if ( CB_ERR != nCount && nCount > 0 ) {
		m_comboRange1.GetLBText(0, m_strRange1);
	}

	nCount = m_comboRange2.GetCount();
	if ( CB_ERR != nCount && nCount > 1 ) {
		m_comboRange2.GetLBText(1, m_strRange2);
	}
			
	nCount = m_comboRange3.GetCount();
	if ( CB_ERR != nCount && nCount > 2 ) {
		m_comboRange3.GetLBText(2, m_strRange3);
	}
			
	nCount = m_comboRange4.GetCount();
	if ( CB_ERR != nCount && nCount > 3 ) {
		m_comboRange4.GetLBText(3, m_strRange4);
	}
}

void CSpaModuleEntryPage::UpdateList(void)
{
	// Remove all from the list boxes.
	m_listEntry.ResetContent();

	// Read from the record file.
	ReadRecord(entryRange);
}

void CSpaModuleEntryPage::ReadRecord(int nWhichFile)
{
	// Read from the record file.
	CString strFile(::szAppPath), strHead;
	switch ( nWhichFile ) {
//		case executionRange:
//			strFile += "SPA\\execute.dbf";
//			strHead = "Execution Range:";
//			break;
		case entryRange:
			strFile += "SPA\\entry.dbf";
			strHead = "Module Range:";
			break;
		default:
			ASSERT(FALSE);
			return;
	}

	// Assign the open flag.
    CFileStatus status;
	if ( !CFile::GetStatus(strFile, status) ) {
		strHead += " None";
		m_listEntry.AddString(strHead);
		return;
	}
	m_listEntry.AddString(strHead);
		
	// Open the record file.
	UINT nOpenFlag = CFile::modeRead | CFile::typeText;
	CStdioFile* fp = new CStdioFile(strFile, nOpenFlag);
	
	// Read from the record file.
	int nMax = defineLen+startLen+endLen;
	char* pszLine = new char[nMax+4];
	while ( fp->ReadString(pszLine, nMax) ) {
		// Split string.
		char* p = pszLine;
		while ( *p ) {
			if ( '\n' == *p ) {
				*p = NULL;
				break;
			}
			p++;
		}
		CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
		pSheet->EmptyBuffer();
		pSheet->SplitRecord(CString(pszLine));
		CString strList(pSheet->m_strDefine + " " + 
				  		pSheet->m_strStart + " " + pSheet->m_strEnd);
		m_listEntry.AddString(strList);
	}
	delete []pszLine;
	m_listEntry.AddString("");
		
	// Close the record file.
	fp->Close();
	delete fp;
}

void CSpaModuleEntryPage::ReadRecord(int nWhichFile, int nWhichCombo)
{
	// Read from the record file.
	CString strFile(::szAppPath);
	switch ( nWhichFile ) {
//		case executionRange:
//			strFile += "SPA\\execute.dbf";
//			break;
		case entryRange:
			strFile += "SPA\\entry.dbf";
			break;
		default:
			ASSERT(FALSE);
			return;
	}

	// Assign the open flag.
    CFileStatus status;
	if ( !CFile::GetStatus(strFile, status) ) {
		return;
	}

	// Open the record file.
	UINT nOpenFlag = CFile::modeRead | CFile::typeText;
	CStdioFile* fp = new CStdioFile(strFile, nOpenFlag);
	
	// Read from the record file.
	int nMax = defineLen+startLen+endLen;
	char* pszLine = new char[nMax+4];
	while ( fp->ReadString(pszLine, nMax) ) {
		// Split string.
		char* p = pszLine;
		while ( *p ) {
			if ( '\n' == *p ) {
				*p = NULL;
				break;
			}
			p++;
		}
		CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
		pSheet->EmptyBuffer();
		pSheet->SplitRecord(CString(pszLine));
		CString strDefine(pSheet->m_strDefine);
		switch ( nWhichCombo ) {
			case combo1:
				m_comboRange1.AddString(strDefine);
				break;
			case combo2:
				m_comboRange2.AddString(strDefine);
				break;
			case combo3:
				m_comboRange3.AddString(strDefine);
				break;
			case combo4:
				m_comboRange4.AddString(strDefine);
				break;
			default:
				ASSERT(FALSE);
				break;
		}
	}
	delete []pszLine;
	
	// Close the record file.
	fp->Close();
	delete fp;
}

void CSpaModuleEntryPage::ReadRecord(int nWhichFile, const CString& strDefine)
{
	// Read from the record file.
	CString strFile(::szAppPath);
	switch ( nWhichFile ) {
//		case executionRange:
//			strFile += "SPA\\execute.dbf";
//			break;
		case entryRange:
			strFile += "SPA\\entry.dbf";
			break;
		default:
			ASSERT(FALSE);
			return;
	}

	// Assign the open flag.
    CFileStatus status;
	if ( !CFile::GetStatus(strFile, status) ) {
		return;
	}

	// Open the record file.
	UINT nOpenFlag = CFile::modeRead | CFile::typeText;
	CStdioFile* fp = new CStdioFile(strFile, nOpenFlag);
	
	// Read from the record file.
	int nMax = defineLen+startLen+endLen;
	char* pszLine = new char[nMax+4];
	while ( fp->ReadString(pszLine, nMax) ) {
		// Split string.
		char* p = pszLine;
		while ( *p ) {
			if ( '\n' == *p ) {
				*p = NULL;
				break;
			}
			p++;
		}
		CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
		pSheet->SplitRecord(CString(pszLine));
		if ( strDefine == pSheet->m_strDefine ) {
			break;
		}
		pSheet->EmptyBuffer();
	}
	delete []pszLine;
		
	// Close the record file.
	fp->Close();
	delete fp;
}

void CSpaModuleEntryPage::ClearResult(void)
{
	// Initial the result variables.
	m_nCount0 = 0;
	m_nCount1 = 0;
	m_nCount2 = 0;
	m_nCount3 = 0;
	m_nCount4 = 0;
	m_dwTime0 = 0;
	m_dwTime1 = 0;
	m_dwTime2 = 0;
	m_dwTime3 = 0;
	m_dwTime4 = 0;
	m_nCountPer1 = 0;
	m_nCountPer2 = 0;
	m_nCountPer3 = 0;
	m_nCountPer4 = 0;
	m_nTimePer1 = 0;
	m_nTimePer2 = 0;
	m_nTimePer3 = 0;
	m_nTimePer4 = 0;

	// Update count bar.
	for ( int i(1); i <= 4; i++ ) {
		UpdateCountBar(i, FALSE);
	}
	
	// Update timer bar.
	for ( i = 1; i <= 4; i++ ) {
		UpdateTimerBar(i, FALSE);
	}
}


/////////////////////////////////////////////////////////////////////////////
// CSpaModuleEntryPage message handlers

BOOL CSpaModuleEntryPage::OnKillActive()
{
	// TODO: Add your message handler code here

	// Disabled when running.
	if ( !m_bStop ) {
		return FALSE;
	}

	return CPropertyPage::OnKillActive();
}

BOOL CSpaModuleEntryPage::OnSetActive()
{
	// TODO: Add your message handler code here

	// Set timer to update the graph bar.
 	m_uTimerID = SetTimer(tmEvent, tmElapse, NULL);

	return CPropertyPage::OnSetActive();
}

void CSpaModuleEntryPage::OnCancel()
{
	// TODO: Add extra cleanup here

	// Kill one-shot timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
	}

	// Abort EP.
	AbiAbort();

	// Restore HW configuration.
	BeginWaitCursor();
	RestoreAllConfig();
	EndWaitCursor();

	// Close the whole group.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	if ( pSheet->IsKindOf(RUNTIME_CLASS(CSpaGroupSheet)) ) {
		pSheet->EndDialog(IDCANCEL);
	}
	else {
		CPropertyPage::OnCancel();
	}
}

void CSpaModuleEntryPage::OnHelp()
{
	// TODO: Add your control notification handler code here

	// Active Windows Help system
	AfxGetApp()->WinHelp(IDD_SPA_ENTRY);
}

void CSpaModuleEntryPage::OnButtonSpaEdit()
{
	// TODO: Add your control notification handler code here

	// Open the user defined dialog.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	CSpaUserDefineDlg* pDlg = new CSpaUserDefineDlg(pSheet);
	if ( IDOK == pDlg->DoModal() ) {
		// Update current selection.
		BeginWaitCursor();
		UpdateData();

		UpdateCombo();
		UpdateList();
	
		UpdateData(FALSE);
		EndWaitCursor();
	}
		
	delete pDlg;
}

void CSpaModuleEntryPage::OnButtonSpaStart()
{
	// TODO: Add your control notification handler code here

	// Clear current result.
	UpdateData();
	ClearResult();

    // Check the control syntax.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
    CheckInputSyntax();
    if ( pSheet->errOK != pSheet->m_nErrorID ) {
		pSheet->DisplayErrorMessage();
    	return;
    }

	// Set entry data.
    if ( !SetEntryData() ) {
    	return;
    }

	// Grayed the some controls.
	m_bStop = FALSE;
	DisableControl();
	
	// Set timer.
	if ( 0 != m_uTimerID ) {
		// If outstanding timer, kill it.
		KillTimer(m_uTimerID);
	}

 	// Set a timer for 200 milliseconds.
 	m_uTimerID = SetTimer(tmEvent, tmElapse, NULL);
	if ( 0 == m_uTimerID ) {
		pSheet->m_nErrorID = pSheet->errTimer;
		pSheet->DisplayErrorMessage();
		return;
	}

    UpdateData(FALSE);
}

void CSpaModuleEntryPage::OnButtonSpaStop()
{
	// TODO: Add your control notification handler code here
	
	// Kill one-shot timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
		m_uTimerID = 0;
		
		// Abort EP.
		AbiAbort();
	
		// Update graph bar.
		UpdateBar();
	}
    
	// Grayed some controls.
	m_bStop = TRUE;
	DisableControl();
}

void CSpaModuleEntryPage::OnShowWindow(BOOL bShow, UINT nStatus)
{
	CPropertyPage::OnShowWindow(bShow, nStatus);
	
	// TODO: Add your message handler code here
	
	// The window is being shown.
	if ( TRUE == bShow ) {
		// Grayed some controls.
		m_bStop = TRUE;
		DisableControl();
		
		// Update current selection.
		BeginWaitCursor();
	
		UpdateData();

	    HFONT hFont = (HFONT)::GetStockObject(ANSI_FIXED_FONT);
	    CFont font;
		m_listEntry.SetFont(font.FromHandle(hFont));
	
		UpdateCombo();
		UpdateList();

		UpdateData(FALSE);
	
		EndWaitCursor();
	}
}

void CSpaModuleEntryPage::OnTimer(UINT nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	
	// Not our timer.
	if ( m_uTimerID != nIDEvent ) {
		CPropertyPage::OnTimer(nIDEvent);
		return;
	}
    
	// Update graph bar.
	if ( !m_bStop ) {
		UpdateBar();
	}
	else {
		// Kill the timer.
		KillTimer(m_uTimerID);
		m_uTimerID = 0;

		// Update count bar.
		for ( int i(1); i <= 4; i++ ) {
			UpdateCountBar(i);
		}
		
		// Update timer bar.
		for ( i = 1; i <= 4; i++ ) {
			UpdateTimerBar(i);
		}
	}
}

void CSpaModuleEntryPage::OnButtonSpaRestart() 
{
	// TODO: Add your control notification handler code here
    
    // As same as OnStart.
    m_nWhichBtn = btnRestart;
	OnButtonSpaStart();
	m_nWhichBtn = btnStart;
}

void CSpaModuleEntryPage::OnButtonSpaBp() 
{
	// TODO: Add your control notification handler code here

	// Open the BP set dialog.
	UpdateData();

	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	CSpaBpSetDlg* pDlg = new CSpaBpSetDlg(pSheet);
	if ( IDOK == pDlg->DoModal() ) {
		m_strRange0 = pDlg->m_strBp;
	}
	delete pDlg;

	UpdateData(FALSE);
}
