/***************************************************************************
**
**    $Header:   D:/ECB2S/SRC/LOG/SPACODE.CPP   1.2.1.4   17 Apr 1997 15:59:38   ZJRD  $
**
**    $Log:   D:/ECB2S/SRC/LOG/SPACODE.CPP  $
** 
**    Rev 1.2.1.4   17 Apr 1997 15:59:38   ZJRD
** No change.
** 
**    Rev 1.2.1.3   16 Apr 1997 10:32:06   ZJRD
** 2.09F
** 
**    Rev 1.2.1.2   10 Apr 1997 15:41:48   ZJRD
** 2.09F
** 
**    Rev 1.2.1.1   03 Apr 1997 15:20:40   ZJRD
** No change.
** 
**    Rev 1.2.1.0   28 Mar 1997 10:25:00   ZJRD
** easy pack sld 2.09d
** 
**    Rev 1.1   19 Mar 1997 11:34:56   ZJRD
** No change.
** 
**    Rev 1.0   12 Mar 1997 14:49:36   ZJRD
** Initial revision.
** 
**    Rev 1.7.1.0.1.0   11 Nov 1996 12:59:40   ZJRD
** EasyPack/SLD Version 2.01
** 
**    Rev 1.7.1.4   09 Sep 1996 13:18:52   ZJRD
** No change.
** 
**    Rev 1.7.1.3   05 Sep 1996 11:30:24   ZJRD
** EasyPack/SLD Version 1.9e
** 
**    Rev 1.7.1.2   02 Sep 1996 09:57:28   ZJRD
** EasyPack/SLD Version 1.9d
** 
**    Rev 1.7.1.1   28 Aug 1996 15:52:44   ZJRD
** EasyPack/SLD Version 1.9b
** 
****************************************************************************/

/////////////////////////////////////////////////////////////////////////////
//
//  File name: SPACODE.CPP
//
//  Description: The implementation file fore class: CSpaCodeCoveragePage.
//
//  Author: Chen Jun
//
//  Date: 03/21/96
//
//  Modification:
//      1. 03/21/96, Initial version of the class: CSpaCodeCoverageDlg.
//      2. 03/29/96, CSpaCodeCoveragePage with CPropertyPage.
//
//  Copyright (C) 1996 Microtek International. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////

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

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

#include "cpust.h"
#include "symblsvr.h"


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


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

extern int g_nBankNum;

STATUS AbiAbort();
STATUS AbiClrAllBp();

STATUS AbiGetOneReg(int iRegId, UINT* uRegValue);
STATUS AbiSetQualify(QUALIFY qualifyData);
int GetCurrentBank(void);
int GetPCBank(void);

STATUS AbiCoverageGo(COVERAGEGOINFO coverageGoInfo);
STATUS AbiCoverageGet(COVERAGEGETINFO* coverageGetInfo);
STATUS AbiGetCpuStatus(UINT *uCpuStatus);
int SpaDisAsm(
	int nBankArg,					// 6, 7, 8, 9
    unsigned short DAsmStartAddr,	// the start address to be disassembly
    unsigned short DAsmInCodeBlkLen,// the code block length
    unsigned short &usNextAddr,
    CStringList* &pList
);
int SpaListSource(int nBank, unsigned short uStartAddr, unsigned short uLen, CStringList* &pList);

int SrcIsLoaded(void);
int SpaGetModule(CStringList* &pList);
CString SrcGetModuleFullName(const char * pszModuleName);
int SymToAddr(char* lpStr , U8* lpType , U32* lpAddr);

void RestoreAllConfig(void);

BOOL CSpaCodeCoveragePage::SetEvent()
{
	UINT uPC;
	CString strPC;
	int nBank;
	
	// Get the current PC bank
	nBank = ::GetPCBank();
	// Get the current PC
	::AbiGetOneReg(0, &uPC);
    
    m_CodeSetData.goArgument.addrFrom.addr = uPC;
    for( int i=0;i<12;i++){
         m_QualifyData.qlfyType[i] = 0;
    }
         
    m_QualifyData.setMode = 0;
    m_QualifyData.qlfyType[0] = 1;
    m_QualifyData.qlfyType[4] = 1;
	m_QualifyData.qlfyType[8] = 0;
	m_QualifyData.status = 0;

	m_QualifyData.addr[0][0] = (WORD)uPC;
    m_QualifyData.addr[0][1] = (WORD)nBank;
	if ( ::ICE_OK != ::AbiSetQualify(m_QualifyData) ) {
    	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();

		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}
	
	TRIGGER_LEVEL trigLevelData;
	
	trigLevelData.traceFlag = 1; 
	trigLevelData.traceFlag = 1;
	trigLevelData.dwCond = 0xAAAAAAAA;
	if ( ::ICE_OK != ::AbiSetTrigLevel(1, trigLevelData)) {
    	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();

		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}

	TRIGGER_LOGIC trigLogicData;
	
	trigLogicData.trigFlag = 0;
	trigLogicData.runFlag = 0;
	trigLogicData.delayCount = 1024;
	trigLogicData.levelCount = 1;
	trigLogicData.levelID[0] = 1;
	  
	if ( ::ICE_OK != ::AbiSetTrigLogic(trigLogicData)) {
    	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();

		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}
    return TRUE;            
}    

BOOL CSpaCodeCoveragePage::IsLastBP()
{
	UINT uPC;
	int nBank;
	
	// Get the current PC bank
	nBank = ::GetPCBank();
	// Get the current PC
	::AbiGetOneReg(0, &uPC);
	
	if(uPC ==  m_CodeSetData.goArgument.addrTo.addr&&
	   nBank == m_CodeSetData.goArgument.addrTo.addrType )
       return TRUE;
    
    return FALSE;
}

void CSpaCodeCoveragePage::DeleteMerge()
{
	CoverageData* data;
	
    m_CodeOldData.uchNumber = 0;
	while(m_CodeOldData.DataSegment){
	      data = m_CodeOldData.DataSegment->next;
	      delete m_CodeOldData.DataSegment;
	      m_CodeOldData.DataSegment = data;
	}
}

void CSpaCodeCoveragePage::MergeResult()
{
	CoverageData* data=0, *temp=0;
	int num = 0, rtn;
	
	if(m_CodeGetData.uchNumber==0) return;
    
    if(m_CodeOldData.uchNumber > 0){
	    data = m_CodeOldData.DataSegment;
	    ASSERT( data != NULL );
	    while(data){
	          temp = data;
	          data = data->next;
	    }
    }
    
	for(int i=0;i<m_CodeGetData.uchNumber;i++){
	    if( (rtn=MergeData(i))==0 ){
		    data = new CoverageData();
		    ASSERT( data != NULL ); 
		    if(m_CodeOldData.uchNumber > 0){
		       temp->next = data;
		       temp = temp->next;
		    }
		    else {
		       m_CodeOldData.DataSegment = data;
		       temp = data;
		    }
		    data->usAddr[0] = m_CodeGetData.usAddr[2*i];
		    data->usAddr[1] = m_CodeGetData.usAddr[2*i+1];
	        data->bType[0] = m_CodeGetData.bType[2*i];
	        data->bType[1] = m_CodeGetData.bType[2*i+1];
		    m_CodeOldData.uchNumber ++;
	   }
    }
}

int CSpaCodeCoveragePage::MergeData(int i)
{
	CoverageData* data=0, *temp=0;
    
    if(m_CodeOldData.DataSegment==0) return 0;
    data = m_CodeOldData.DataSegment;
	while(data){
		if(data->usAddr[0]>m_CodeGetData.usAddr[2*i+1]||
		    data->usAddr[1]<m_CodeGetData.usAddr[2*i]){
		   data = data->next;
		   continue;
		}

		data->usAddr[0] = min(data->usAddr[0],m_CodeGetData.usAddr[2*i]);    
		data->usAddr[1] = max(data->usAddr[1],m_CodeGetData.usAddr[2*i+1]);   
		return 1;
   }
   ASSERT( data == NULL );
   return 0;
}
 
/////////////////////////////////////////////////////////////////////////////
// CSpaCodeCoveragePage dialog

CSpaCodeCoveragePage::CSpaCodeCoveragePage()
	: CPropertyPage(CSpaCodeCoveragePage::IDD),
    m_uTimerID(0), m_bStop(TRUE), m_nMode(modeAsm), m_nProgress(0), m_nWhichBtn(btnStart)
{
	//{{AFX_DATA_INIT(CSpaCodeCoveragePage)
	m_strRange1 = "";
	m_strRange2 = "";
	m_strRange3 = "";
	m_strRange4 = "";
	m_nBlock = -1;
	m_nInst = -1;
	m_bRange1 = FALSE;
	m_bRange2 = FALSE;
	m_bRange3 = FALSE;
	m_bRange4 = FALSE;
	m_strRange0 = _T("");
	//}}AFX_DATA_INIT

	// Allocate space.
	m_pLineList = new CObList;
	m_pLineList->RemoveAll(); 
    memset(&m_CodeOldData, 0, sizeof(m_CodeOldData));
    memset(&m_CodeMergeData, 0, sizeof(m_CodeMergeData));	
}

CSpaCodeCoveragePage::~CSpaCodeCoveragePage()
{
	// Release space.
	POSITION pos = m_pLineList->GetHeadPosition();
	while ( pos ) {
		CSpaTextLine* pObj = (CSpaTextLine*)m_pLineList->GetNext(pos);
		delete pObj;
	}
	m_pLineList->RemoveAll();
	delete m_pLineList;
	DeleteMerge();  //
}

void CSpaCodeCoveragePage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSpaCodeCoveragePage)
	DDX_Control(pDX, IDC_COMBO_SPA_MESSAGEBAR_MODULE, m_comboModule);
	DDX_Control(pDX, IDC_STATIC_MODULE, m_staticModule);
	DDX_Control(pDX, IDC_BUTTON_SPA_CODE_DETAIL, m_btnDetail);
	DDX_Control(pDX, IDC_EDIT_SPA_DEFINE_BP, m_editBp);
	DDX_Control(pDX, IDC_BUTTON_SPA_BP, m_btnBp);
	DDX_Control(pDX, IDC_STATIC_SPA_CODE_PROGRESS, m_staticProgressBar);
	DDX_Control(pDX, IDC_BUTTON_SPA_CODE_MODE, m_btnMode);
	DDX_Control(pDX, IDC_CHECK_SPA_CODE_RANGE1, m_btnRange1);
	DDX_Control(pDX, IDC_CHECK_SPA_CODE_RANGE2, m_btnRange2);
	DDX_Control(pDX, IDC_CHECK_SPA_CODE_RANGE3, m_btnRange3);
	DDX_Control(pDX, IDC_CHECK_SPA_CODE_RANGE4, m_btnRange4);
	DDX_Control(pDX, IDC_BUTTON_SPA_RESTART, m_btnRestart);
	DDX_Control(pDX, IDC_LIST_SPA_CODE_INSTRUCTION, m_listInst);
	DDX_Control(pDX, IDC_LIST_SPA_CODE_BLOCK, m_listBlock);
	DDX_Control(pDX, IDC_COMBO_SPA_CODE_RANGE1, m_comboRange1);
	DDX_Control(pDX, IDC_COMBO_SPA_CODE_RANGE2, m_comboRange2);
	DDX_Control(pDX, IDC_COMBO_SPA_CODE_RANGE3, m_comboRange3);
	DDX_Control(pDX, IDC_COMBO_SPA_CODE_RANGE4, m_comboRange4);
	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_CBString(pDX, IDC_COMBO_SPA_CODE_RANGE1, m_strRange1);
	DDV_MaxChars(pDX, m_strRange1, 80);
	DDX_CBString(pDX, IDC_COMBO_SPA_CODE_RANGE2, m_strRange2);
	DDV_MaxChars(pDX, m_strRange2, 80);
	DDX_CBString(pDX, IDC_COMBO_SPA_CODE_RANGE3, m_strRange3);
	DDV_MaxChars(pDX, m_strRange3, 80);
	DDX_CBString(pDX, IDC_COMBO_SPA_CODE_RANGE4, m_strRange4);
	DDV_MaxChars(pDX, m_strRange4, 80);
	DDX_LBIndex(pDX, IDC_LIST_SPA_CODE_BLOCK, m_nBlock);
	DDX_LBIndex(pDX, IDC_LIST_SPA_CODE_INSTRUCTION, m_nInst);
	DDX_Check(pDX, IDC_CHECK_SPA_CODE_RANGE1, m_bRange1);
	DDX_Check(pDX, IDC_CHECK_SPA_CODE_RANGE2, m_bRange2);
	DDX_Check(pDX, IDC_CHECK_SPA_CODE_RANGE3, m_bRange3);
	DDX_Check(pDX, IDC_CHECK_SPA_CODE_RANGE4, m_bRange4);
	DDX_Text(pDX, IDC_EDIT_SPA_DEFINE_BP, m_strRange0);
	DDV_MaxChars(pDX, m_strRange0, 80);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CSpaCodeCoveragePage, CPropertyPage)
	//{{AFX_MSG_MAP(CSpaCodeCoveragePage)
	ON_BN_CLICKED(IDC_BUTTON_SPA_EDIT, OnButtonSpaEdit)
	ON_BN_CLICKED(ID_HELP, OnHelp)
	ON_BN_CLICKED(IDC_BUTTON_SPA_START, OnButtonSpaStart)
	ON_BN_CLICKED(IDC_BUTTON_SPA_STOP, OnButtonSpaStop)
	ON_WM_SHOWWINDOW()
	ON_WM_TIMER()
	ON_LBN_SELCHANGE(IDC_LIST_SPA_CODE_BLOCK, OnSelchangeListSpaCodeBlock)
	ON_BN_CLICKED(IDC_BUTTON_SPA_RESTART, OnButtonSpaRestart)
	ON_BN_CLICKED(IDC_CHECK_SPA_CODE_RANGE1, OnCheckSpaCodeRange1)
	ON_BN_CLICKED(IDC_CHECK_SPA_CODE_RANGE2, OnCheckSpaCodeRange2)
	ON_BN_CLICKED(IDC_CHECK_SPA_CODE_RANGE3, OnCheckSpaCodeRange3)
	ON_BN_CLICKED(IDC_CHECK_SPA_CODE_RANGE4, OnCheckSpaCodeRange4)
	ON_BN_CLICKED(IDC_BUTTON_SPA_CODE_MODE, OnButtonSpaCodeMode)
	ON_BN_CLICKED(IDC_BUTTON_SPA_BP, OnButtonSpaBp)
	ON_CBN_EDITCHANGE(IDC_COMBO_SPA_CODE_RANGE1, OnEditchangeComboSpaCodeRange1)
	ON_CBN_EDITCHANGE(IDC_COMBO_SPA_CODE_RANGE2, OnEditchangeComboSpaCodeRange2)
	ON_CBN_EDITCHANGE(IDC_COMBO_SPA_CODE_RANGE3, OnEditchangeComboSpaCodeRange3)
	ON_CBN_EDITCHANGE(IDC_COMBO_SPA_CODE_RANGE4, OnEditchangeComboSpaCodeRange4)
	ON_CBN_SELCHANGE(IDC_COMBO_SPA_CODE_RANGE1, OnSelchangeComboSpaCodeRange1)
	ON_CBN_SELCHANGE(IDC_COMBO_SPA_CODE_RANGE2, OnSelchangeComboSpaCodeRange2)
	ON_CBN_SELCHANGE(IDC_COMBO_SPA_CODE_RANGE3, OnSelchangeComboSpaCodeRange3)
	ON_CBN_SELCHANGE(IDC_COMBO_SPA_CODE_RANGE4, OnSelchangeComboSpaCodeRange4)
	ON_BN_CLICKED(IDC_BUTTON_SPA_CODE_DETAIL, OnButtonSpaCodeDetail)
	ON_CBN_SELCHANGE(IDC_COMBO_SPA_MESSAGEBAR_MODULE, OnSelchangeComboSpaMessagebarModule)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSpaCodeCoveragePage common routines

void CSpaCodeCoveragePage::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 CSpaCodeCoveragePage::StopTimerAction(void)
{
	// Kill timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
		m_uTimerID = 0;
	}

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

void CSpaCodeCoveragePage::DisableControl(void)
{
	// Enable / disable buttons.
	m_btnRestart.EnableWindow(m_bStop);
	m_btnStart.EnableWindow(m_bStop);
	m_btnEdit.EnableWindow(m_bStop);
	m_btnMode.EnableWindow(m_bStop);
	m_btnBp.EnableWindow(m_bStop);
	m_editBp.EnableWindow(m_bStop);
	m_btnDetail.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 / disable status check boxes.
	m_btnCheckAK.EnableWindow(m_bStop);
	m_btnCheckF.EnableWindow(m_bStop);
	m_btnCheckR.EnableWindow(m_bStop);
	m_btnCheckS.EnableWindow(m_bStop);
	m_btnCheckW.EnableWindow(m_bStop);
*/

	// Enable / disable range check boxes.
	m_btnRange1.EnableWindow(m_bStop);
	m_btnRange2.EnableWindow(m_bStop);
	m_btnRange3.EnableWindow(m_bStop);
	m_btnRange4.EnableWindow(m_bStop);
	
	// Source/Assembly toggle button.
	m_btnMode.EnableWindow(FALSE);
	m_btnDetail.EnableWindow(FALSE);
}

void CSpaCodeCoveragePage::DetectDisplayMode(void)
{
	// Not loading any source codes.
	if ( 0 != ::SrcIsLoaded() ) {
		m_btnMode.EnableWindow(FALSE);
		m_btnDetail.EnableWindow(FALSE);
		return;
	}

	// Get coverage info.
	if ( 0 == m_CodeGetData.uchNumber ) {
		m_btnMode.EnableWindow(FALSE);
		m_btnDetail.EnableWindow(FALSE);
		return;
	}

	m_btnMode.EnableWindow(TRUE);
	m_btnDetail.EnableWindow(TRUE);

/*
	// Detect if there is source codes.
	unsigned short uStart = m_CodeGetData.usAddr[m_nBlock*2];
	unsigned short uEnd = m_CodeGetData.usAddr[m_nBlock*2+1];
	if ( uEnd < uStart ) {
		m_btnMode.EnableWindow(FALSE);
		return;
	}
	unsigned short uLen = uEnd-uStart+1;

	// New a list.
	CStringList* pList = new CStringList;

	// Get C-trace info from Trace server.
	if ( 0 == ::SpaListSource(uStart, uLen, pList) ) {
		// 0 line C-trace contents.
		m_btnMode.EnableWindow(FALSE);
	}
	else {
		m_btnMode.EnableWindow(TRUE);
	}

	delete pList;
*/
}

void CSpaCodeCoveragePage::UpdateCombo(void)
{
	// Remove all from the combo boxes.
	m_comboRange1.ResetContent();
	m_comboRange2.ResetContent();
	m_comboRange3.ResetContent();
	m_comboRange4.ResetContent();
	
	// Clear all of the edit control.
	m_strRange1 = _T("");
	m_strRange2 = _T("");
	m_strRange3 = _T("");
	m_strRange4 = _T("");

	m_bRange1 = FALSE;
	m_bRange2 = FALSE;
	m_bRange3 = FALSE;
	m_bRange4 = FALSE;
	
	// 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);
		m_bRange1 = TRUE;
	}

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

void CSpaCodeCoveragePage::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);
		if ( pSheet->m_strEnd.IsEmpty() ) {
			continue;
		}
		switch ( nWhichCombo ) {
//			case combo0:
//				m_comboRange0.AddString(strDefine);
//				break;
			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 CSpaCodeCoveragePage::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 ( !pSheet->m_strEnd.IsEmpty() && 
			 strDefine == pSheet->m_strDefine ) {
			break;
		}
		pSheet->EmptyBuffer();
	}
	delete []pszLine;
		
	// Close the record file.
	fp->Close();
	delete fp;
}

void CSpaCodeCoveragePage::ClearResult(void)
{
	// Initial result variables.
	m_nMemory = 0;
	
	// Reset list box.
	m_listBlock.ResetContent();
	m_listInst.ResetContent();
}

void CSpaCodeCoveragePage::GetExecuteRange()
{
	// Get start address.
	char szPC[33+1];
	UINT uPC;
	CString strPC;
	int nBank;

	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();

	switch ( m_nWhichBtn ) {
		case btnStart:
			// Get the current PC bank
			nBank = ::GetPCBank();
			if ( ::SPACE_PROGRAME == nBank ) {
				strPC = "P:";
			}
			else {
				itoa(nBank-::SPACE_BANK1, szPC, 10);
				strPC = 'P';
				strPC += szPC;
				strPC += ':';
			}
			// Get the current PC
			::AbiGetOneReg(0, &uPC);
			ultoa(uPC, szPC, 16);
			strPC += szPC;
			break;
		case btnRestart:
			// Get the old PC bank
			if ( ::SPACE_PROGRAME == pSheet->m_nBank ) {
				strPC = "P:";
			}
			else {
				itoa(pSheet->m_nBank-::SPACE_BANK1, szPC, 10);
				strPC = 'P';
				strPC += szPC;
				strPC += ':';
			}
			// Get the old PC
			ultoa(pSheet->m_uPC, szPC, 16);
			strPC += szPC;
			break;
		default:
			ASSERT(FALSE);
			return;
	}
	
	// Get the end BP.
	pSheet->m_strStart = strPC;
	pSheet->m_strEnd = m_strRange0;
}

BOOL CSpaCodeCoveragePage::SetCoverageData(void)
{
	// Initial when restart.
    DeleteMerge();
    
	memset(&m_QualifyData, 0, sizeof(m_QualifyData));
	memset(&m_CodeSetData, 0, sizeof(m_CodeSetData));
    memset(&m_CodeOldData, 0, sizeof(m_CodeOldData));
    memset(&m_CodeMergeData, 0, sizeof(m_CodeMergeData));	
	// Reset progress bar.
	m_nProgress = 0;
	UpdateBar(FALSE);
	
	// Convert input data.
	::ADDRESS Addr;
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	pSheet->EmptyBuffer();

	// Select no modules.
	if ( !m_bRange1 && !m_bRange2 && !m_bRange3 && !m_bRange4 ) {
		pSheet->m_nErrorID = pSheet->errInput;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}
	
	// Set qualify.
	GetExecuteRange();
	if ( pSheet->m_strStart.IsEmpty() /*||
		 pSheet->m_strEnd.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 {
			m_QualifyData.qlfyType[4] = 0x10;
			if ( !m_bS && !m_bF && !m_bR && !m_bW && !m_bAK ) {
				m_QualifyData.qlfyType[8] = 0;
			}
			else {
				m_QualifyData.qlfyType[8] = 1;
			}
            
			m_QualifyData.status = 0;
            if ( m_bS ) {
				m_QualifyData.status |= 0x1;
			}
            if ( m_bF ) {
				m_QualifyData.status |= 0x2;
			}
            if ( m_bR ) {
				m_QualifyData.status |= 0x4;
			}
            if ( m_bW ) {
				m_QualifyData.status |= 0x8;
			}
            if ( m_bAK ) {
				m_QualifyData.status |= 0x10;
			}

			m_QualifyData.addrCount = 2;

			::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
			m_QualifyData.addr[0][0] = (WORD&)(Addr.adrAddress);

			::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
			m_QualifyData.addr[1][0] = (WORD&)(Addr.adrAddress);
		}
*/
	}
	
/*
	if ( ::ICE_OK != ::AbiSetQualify(m_QualifyData) ) {
		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}
*/
		
	// Convert execution range.
	::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
	m_CodeSetData.goArgument.addrFrom.addr = (WORD&)(Addr.adrAddress);
	m_CodeSetData.goArgument.addrFrom.addrType = (FLAG&)Addr.adrSpace;
	//for no breakpoint
	if(pSheet->m_strEnd.IsEmpty()){
		m_CodeSetData.goArgument.addrTo.addr = 0xffff;
		m_CodeSetData.goArgument.addrTo.addrType = 0;
	}
	else{
		::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
		m_CodeSetData.goArgument.addrTo.addr = (WORD&)(Addr.adrAddress);
		m_CodeSetData.goArgument.addrTo.addrType = (FLAG&)Addr.adrSpace;
    }
	// Flag.	
	BOOL bHasValue(FALSE);

	// Convert Module 1 range.
	if ( m_bRange1 ) {
		pSheet->EmptyBuffer();
		ReadRecord(entryRange, m_strRange1);
		if ( !m_strRange1.IsEmpty() && pSheet->m_strStart.IsEmpty() ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		if ( !pSheet->m_strStart.IsEmpty() ) {
			if ( !pSheet->IsValidAddr(pSheet->m_strStart) ||
				 !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
				pSheet->m_nErrorID = pSheet->errInput;
				pSheet->DisplayErrorMessage();
				return FALSE;
			}
			else {
				::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
				
				::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
			}
			bHasValue = TRUE;
		}
	}

	// Convert Module 2 range.
	if ( m_bRange2 ) {
		pSheet->EmptyBuffer();
		ReadRecord(entryRange, m_strRange2);
		if ( !m_strRange2.IsEmpty() && pSheet->m_strStart.IsEmpty() ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		if ( !pSheet->m_strStart.IsEmpty() ) {
			if ( !pSheet->IsValidAddr(pSheet->m_strStart) ||
				 !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
				pSheet->m_nErrorID = pSheet->errInput;
				pSheet->DisplayErrorMessage();
				return FALSE;
			}
			else {
				::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
				
				::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
			}
			bHasValue = TRUE;
		}
	}

	// Convert Module 3 range.
	if ( m_bRange3 ) {
		pSheet->EmptyBuffer();
		ReadRecord(entryRange, m_strRange3);
		if ( !m_strRange3.IsEmpty() && pSheet->m_strStart.IsEmpty() ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		if ( !pSheet->m_strStart.IsEmpty() ) {
			if ( !pSheet->IsValidAddr(pSheet->m_strStart) ||
				 !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
				pSheet->m_nErrorID = pSheet->errInput;
				pSheet->DisplayErrorMessage();
				return FALSE;
			}
			else {
				::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
				
				::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
			}
			bHasValue = TRUE;
		}
	}

	// Convert Module 4 range.
	if ( m_bRange4 ) {
		pSheet->EmptyBuffer();
		ReadRecord(entryRange, m_strRange4);
		if ( !m_strRange4.IsEmpty() && pSheet->m_strStart.IsEmpty() ) {
			pSheet->m_nErrorID = pSheet->errInput;
			pSheet->DisplayErrorMessage();
			return FALSE;
		}
		if ( !pSheet->m_strStart.IsEmpty() ) {
			if ( !pSheet->IsValidAddr(pSheet->m_strStart) ||
				 !pSheet->IsValidAddr(pSheet->m_strEnd) ) {
				pSheet->m_nErrorID = pSheet->errInput;
				pSheet->DisplayErrorMessage();
				return FALSE;
			}
			else {
				::AdrShellToAddr(pSheet->m_strStart, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
				
				::AdrShellToAddr(pSheet->m_strEnd, Addr, ::SPACE_PROGRAME);
				m_CodeSetData.usAddr[m_CodeSetData.uchNumber] = (unsigned short&)(Addr.adrAddress);
				m_CodeSetData.bType[m_CodeSetData.uchNumber++] = (FLAG&)Addr.adrSpace;
			}
			bHasValue = TRUE;
		}
	}

	// Detect flag.
	if ( !bHasValue ) {
		pSheet->m_nErrorID = pSheet->errInput;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}
	
	// Set Event1 for getting more trace information 
	
	if(!SetEvent()) return FALSE;
	
	// Set coverage data.
	m_CodeSetData.uchNumber /= 2;
	if ( ::ICE_OK != ::AbiCoverageGo(m_CodeSetData) ) {
		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return FALSE;
	}

	return TRUE;
}


void CSpaCodeCoveragePage::UpdateCoverage(int flag)
{
	// Detect EP status.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	UINT uStatus;
	if ( ::ICE_OK != ::AbiGetCpuStatus(&uStatus) ) {
		StopTimerAction();
		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return;
	}

	// EP running.
	if ( 0x40 == (uStatus & 0x70) ) {
		// Idle action.
		IdleAction();
		return;
	}
		
	// Get coverage data.
	memset(&m_CodeGetData, 0, sizeof(m_CodeGetData));
	::STATUS nStatus = ::AbiCoverageGet(&m_CodeGetData);

	if(!IsLastBP()){
	    SetEvent();
	    MergeResult();
	    if(flag) goto End;
	    
		if ( ::ICE_OK != ::AbiCoverageGo(m_CodeSetData) ) {
			pSheet->m_nErrorID = pSheet->errAbi;
			pSheet->DisplayErrorMessage();
			return ;
		}
		
		IdleAction();
	    return;
	}          
	
  	MergeResult();
End:
	StopTimerAction();
	if ( ::ICE_OK != nStatus ) {
		pSheet->m_nErrorID = pSheet->errAbi;
		pSheet->DisplayErrorMessage();
		return;
	}
/*	if ( !g_nBankNum ) {
		for ( int j(0); j < 32; j++ ) {
			m_CodeGetData.bType[j] = ::SPACE_PROGRAME;
		}
	}
*/
    if( !g_nBankNum ){
        m_CodeMergeData = m_CodeOldData.DataSegment;
        while(m_CodeMergeData){
              m_CodeMergeData->bType[0] = ::SPACE_PROGRAME;
              m_CodeMergeData->bType[1] = ::SPACE_PROGRAME;              
              m_CodeMergeData =  m_CodeMergeData->next;
        }
     } 
        
	// Update the progress bar.
	m_nProgress = 100;
	UpdateBar();

	// Not any data coveraged.
	//ASSERT(m_CodeGetData.uchNumber >= 0 && m_CodeGetData.uchNumber <= 16);
	ClearResult();
	if ( 0 == m_CodeOldData.uchNumber ) {
		pSheet->m_nErrorID = pSheet->errNoCoverage;
		pSheet->DisplayErrorMessage();
		UpdateData(FALSE);
		return;
	}
	
	// Add to Block list box.
/*	for ( int i(0); i < m_CodeGetData.uchNumber; i++ ) {
		CString strPercent, strLeft, strRight;
		CalcMemoryPercent(i);
		int nBank = m_CodeGetData.bType[i*2];
		CString strBank;

		if ( ::SPACE_PROGRAME == nBank ) {
			strBank = "P:";
		}
		else if ( nBank >= ::SPACE_BANK1 && nBank <= ::SPACE_BANK4 ) {
			strBank.Format("P%d:", nBank-::SPACE_BANK1);
		}
		else {
			ASSERT(FALSE);
			return;
		}

		strPercent.Format("%2d%% ", m_nMemory);
		strLeft.Format("%04X", m_CodeGetData.usAddr[i*2]);
		strRight.Format("%04X", m_CodeGetData.usAddr[i*2+1]);
		m_listBlock.AddString(strPercent + strBank + strLeft + " ~ " + strBank + strRight);
	}
*/	
    int nBank;
    
    m_CodeMergeData = m_CodeOldData.DataSegment;
    
	for ( int i(0); i < m_CodeOldData.uchNumber; i++ ) {
		CString strPercent, strLeft, strRight;
		
		ASSERT( m_CodeMergeData != NULL );
		CalcMemoryPercent(i);
		nBank = m_CodeMergeData->bType[0];
		CString strBank;

		if ( ::SPACE_PROGRAME == nBank ) {
			strBank = "P:";
		}
		else if ( nBank >= ::SPACE_BANK1 && nBank <= ::SPACE_BANK4 ) {
			strBank.Format("P%d:", nBank-::SPACE_BANK1);
		}
		else {
			ASSERT(FALSE);
			return;
		}

		strPercent.Format("%2d%% ", m_nMemory);
		strLeft.Format("%04X", m_CodeMergeData->usAddr[0]);
		strRight.Format("%04X", m_CodeMergeData->usAddr[1]);
		m_listBlock.AddString(strPercent + strBank + strLeft + " ~ " + strBank + strRight);
		
		m_CodeMergeData = m_CodeMergeData->next;
	}
	

	// Select the first item.
	if ( m_listBlock.GetCount() > 0 ) {
		m_nBlock = 0;
		m_listBlock.SetCurSel(m_nBlock);
		DetectDisplayMode();
	}

	// Update Instruction list.
	UpdateInst();
    
    UpdateData(FALSE);
}

void CSpaCodeCoveragePage::UpdateInst(void)
{
	// If running, return.
	if ( !m_bStop ) {
		return;
	}
	
	// Update right list box.
	switch ( m_nMode ) {
		case modeAsm:
			UpdateInstAsm();
			break;
		case modeSrc:
			UpdateInstSrc();
			break;
		default:
			ASSERT(FALSE);
			return;
	}
}

/*void CSpaCodeCoveragePage::UpdateInstAsm(void)
{
	// Get coverage info.
	unsigned short uStart = m_CodeGetData.usAddr[m_nBlock*2];
	unsigned short uEnd = m_CodeGetData.usAddr[m_nBlock*2+1];
	if ( uEnd < uStart ) {
		return;
	}
	unsigned short uLen = min(uEnd-uStart+1, maxMemBlock);
	unsigned short uNext;

	// New a list.
	CStringList* pList = new CStringList;
	pList->AddTail("Address  Object  Instruction");

	// Get info from DAD server.
	BOOL bEnd(FALSE);
	while ( uStart + uLen <= uEnd + 1 ) {
		int nBank = ::GetPCBank();
		int nRet = ::SpaDisAsm(nBank, uStart, uLen, uNext, pList);
		if ( 0 == nRet ) {
			uStart += uLen;
			uLen = min(uEnd-uStart+1, maxMemBlock);
			if ( 0 == uLen ) {
				break;
			}
			else {
				continue;
			}
		}
		else if ( -4 == nRet ) {
			if ( uStart + uLen < uEnd + 1 ) {
				uStart = uNext;
				uLen = min(uEnd-uStart+1, maxMemBlock);
				if ( 0 == uLen ) {
					break;
				}
				else {
					continue;
				}
			}
			else {
				if ( bEnd ) {
					break;
				}
				else {
					bEnd = TRUE;
					uStart = uNext;
					uLen = 3;
					uEnd = uStart + uLen - 1;
					continue;
				}
			}
		}
		else {
			CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
			pSheet->m_nErrorID = pSheet->errAbi;
			pSheet->DisplayErrorMessage();
			pList->RemoveAll();
			delete pList;
			return;
		}
	}
	
	// Add to Instruction list box.
    m_listInst.ResetContent();
    if ( !pList->IsEmpty() ) {
        POSITION posHead = pList->GetHeadPosition();
        while ( posHead ) {
            m_listInst.AddString(pList->GetNext(posHead));
        }
    }
	
	if ( m_listInst.GetCount() > 0 ) {
		m_nInst = 0;
		m_listInst.SetCurSel(m_nInst);
	}
	
	pList->RemoveAll();
	delete pList;
}

void CSpaCodeCoveragePage::UpdateInstSrc(void)
{
	// Get coverage info.
	unsigned short uStart = m_CodeGetData.usAddr[m_nBlock*2];
	unsigned short uEnd = m_CodeGetData.usAddr[m_nBlock*2+1];
	int nBank = m_CodeGetData.bType[m_nBlock*2];
	if ( uEnd < uStart ) {
		return;
	}
	unsigned short uLen = uEnd-uStart+1;

	// New a list.
	CStringList* pList = new CStringList;
	pList->AddTail("Module   Line   Source");

	// Get C-trace info from Trace server.
	if ( 0 == ::SpaListSource(nBank, uStart, uLen, pList) ) {
		pList->AddTail("............................");
	}

	// Add to Instruction list box.
    m_listInst.ResetContent();
    if ( !pList->IsEmpty() ) {
        POSITION posHead = pList->GetHeadPosition();
        while ( posHead ) {
            m_listInst.AddString(pList->GetNext(posHead));
        }
    }
	
	if ( m_listInst.GetCount() > 0 ) {
		m_nInst = 0;
		m_listInst.SetCurSel(m_nInst);
	}
	
	pList->RemoveAll();
	delete pList;
}

void CSpaCodeCoveragePage::CalcMemoryPercent(int nWhichRange)
{
	// Calclate the memory coverage percent.
	m_nMemory = 1;


//	long lWhole = m_CodeSetData.goArgument.addrTo.addr - 
//				 			m_CodeSetData.goArgument.addrFrom.addr + 1;
//	for ( int i(0); i < m_CodeGetData.uchNumber; i++ ) {
//		lWhole += m_CodeGetData.usAddr[i*2+1] - m_CodeGetData.usAddr[i*2] + 1;
//	}


	// Dome defined as follows, 11/14/96
	
	// Calculate the total range length
    long lWhole(0);
    for ( int i(0); i < m_CodeSetData.uchNumber; i++ ) {
    	lWhole += m_CodeSetData.usAddr[i*2+1] - m_CodeSetData.usAddr[i*2] + 1;
    }
    
    for ( int j(0); j < m_CodeSetData.uchNumber-1; j++ ) {
    	for ( int k(j+1); k < m_CodeSetData.uchNumber; k++ ) {
    		lWhole -= CalcRange(j, k);
    	}
    }

	long lSelect = m_CodeGetData.usAddr[nWhichRange*2+1] - 
				  			 m_CodeGetData.usAddr[nWhichRange*2] + 1;
	
	if ( lWhole <= 0 || lSelect <= 0 || lWhole < lSelect ) {
		return;
	}

	m_nMemory = int(lSelect * 100 / lWhole);
	m_nMemory = min(max(1, m_nMemory), 99);
}
*/

void CSpaCodeCoveragePage::UpdateInstAsm(void)
{
	// Get coverage info.
	int number=0;
	
	m_CodeMergeData = m_CodeOldData.DataSegment;
	while(!(number == m_nBlock)){
	      m_CodeMergeData = m_CodeMergeData->next;
	      number ++;
	}
	
	unsigned short uStart = m_CodeMergeData->usAddr[0];
	unsigned short uEnd = m_CodeMergeData->usAddr[1];
	if ( uEnd < uStart ) {
		return;
	}
	unsigned short uLen = min(uEnd-uStart+1, maxMemBlock);
	unsigned short uNext;

	// New a list.
	CStringList* pList = new CStringList;
	pList->AddTail("Address  Object  Instruction");

	// Get info from DAD server.
	BOOL bEnd(FALSE);
	while ( uStart + uLen <= uEnd + 1 ) {
		int nBank = ::GetPCBank();
		int nRet = ::SpaDisAsm(nBank, uStart, uLen, uNext, pList);
		if ( 0 == nRet ) {
			uStart += uLen;
			uLen = min(uEnd-uStart+1, maxMemBlock);
			if ( 0 == uLen ) {
				break;
			}
			else {
				continue;
			}
		}
		else if ( -4 == nRet ) {
			if ( uStart + uLen < uEnd + 1 ) {
				uStart = uNext;
				uLen = min(uEnd-uStart+1, maxMemBlock);
				if ( 0 == uLen ) {
					break;
				}
				else {
					continue;
				}
			}
			else {
				if ( bEnd ) {
					break;
				}
				else {
					bEnd = TRUE;
					uStart = uNext;
					uLen = 3;
					uEnd = uStart + uLen - 1;
					continue;
				}
			}
		}
		else {
			CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
			pSheet->m_nErrorID = pSheet->errAbi;
			pSheet->DisplayErrorMessage();
			pList->RemoveAll();
			delete pList;
			return;
		}
	}
	
	// Add to Instruction list box.
    m_listInst.ResetContent();
    if ( !pList->IsEmpty() ) {
        POSITION posHead = pList->GetHeadPosition();
        while ( posHead ) {
            m_listInst.AddString(pList->GetNext(posHead));
        }
    }
	
	if ( m_listInst.GetCount() > 0 ) {
		m_nInst = 0;
		m_listInst.SetCurSel(m_nInst);
	}
	
	pList->RemoveAll();
	delete pList;
}

void CSpaCodeCoveragePage::UpdateInstSrc(void)
{
	// Get coverage info.
	int number=0;
	
	m_CodeMergeData = m_CodeOldData.DataSegment;
	while(!(number == m_nBlock)){
	      m_CodeMergeData = m_CodeMergeData->next;
	      number ++;
	}
	
	unsigned short uStart = m_CodeMergeData->usAddr[0];
	unsigned short uEnd = m_CodeMergeData->usAddr[1];

	int nBank = m_CodeMergeData->bType[0];
	if ( uEnd < uStart ) {
		return;
	}
	unsigned short uLen = uEnd-uStart+1;

	// New a list.
	CStringList* pList = new CStringList;
	pList->AddTail("Module   Line   Source");

	// Get C-trace info from Trace server.
	if ( 0 == ::SpaListSource(nBank, uStart, uLen, pList) ) {
		pList->AddTail("............................");
	}

	// Add to Instruction list box.
    m_listInst.ResetContent();
    if ( !pList->IsEmpty() ) {
        POSITION posHead = pList->GetHeadPosition();
        while ( posHead ) {
            m_listInst.AddString(pList->GetNext(posHead));
        }
    }
	
	if ( m_listInst.GetCount() > 0 ) {
		m_nInst = 0;
		m_listInst.SetCurSel(m_nInst);
	}
	
	pList->RemoveAll();
	delete pList;
}

void CSpaCodeCoveragePage::CalcMemoryPercent(int nWhichRange)
{
	// Calclate the memory coverage percent.
	m_nMemory = 1;


//	long lWhole = m_CodeSetData.goArgument.addrTo.addr - 
//				 			m_CodeSetData.goArgument.addrFrom.addr + 1;
//	for ( int i(0); i < m_CodeGetData.uchNumber; i++ ) {
//		lWhole += m_CodeGetData.usAddr[i*2+1] - m_CodeGetData.usAddr[i*2] + 1;
//	}


	// Dome defined as follows, 11/14/96
	
	// Calculate the total range length
    long lWhole(0);
    for ( int i(0); i < m_CodeSetData.uchNumber; i++ ) {
    	lWhole += m_CodeSetData.usAddr[i*2+1] - m_CodeSetData.usAddr[i*2] + 1;
    }
    
    for ( int j(0); j < m_CodeSetData.uchNumber-1; j++ ) {
    	for ( int k(j+1); k < m_CodeSetData.uchNumber; k++ ) {
    		lWhole -= CalcRange(j, k);
    	}
    }

	if(m_CodeMergeData==NULL){
	   return;
	}
	
	long lSelect = m_CodeMergeData->usAddr[1] - 
				  			 m_CodeMergeData->usAddr[0] + 1;
	
	if ( lWhole <= 0 || lSelect <= 0 || lWhole < lSelect ) {
		return;
	}

	m_nMemory = int(lSelect * 100 / lWhole);
	m_nMemory = min(max(1, m_nMemory), 99);
}


long CSpaCodeCoveragePage::CalcRange(const int nFirst, const int nSecond)
{
	if ( m_CodeSetData.usAddr[nFirst*2] > m_CodeSetData.usAddr[nSecond*2+1] ||
		 m_CodeSetData.usAddr[nFirst*2+1] < m_CodeSetData.usAddr[nSecond*2] ) {
		return 0;
	}
	else {
		long l1(0), l2(0);
    	l1 += m_CodeSetData.usAddr[nFirst*2+1] - m_CodeSetData.usAddr[nFirst*2] + 1;
    	l1 += m_CodeSetData.usAddr[nSecond*2+1] - m_CodeSetData.usAddr[nSecond*2] + 1;
    	
    	l2 = max(m_CodeSetData.usAddr[nFirst*2+1], m_CodeSetData.usAddr[nSecond*2+1]) -
    		 min(m_CodeSetData.usAddr[nFirst*2], m_CodeSetData.usAddr[nSecond*2]) + 1;

    	return l1-l2;
	}
}

void CSpaCodeCoveragePage::UpdateBar(BOOL bRedraw)
{
	// Assign a static control.
	CWnd* pWnd = &m_staticProgressBar;
	int nPercent = m_nProgress;
	
	// 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);
*/
		
		// Indicate running status
		CString strStatus = 100 == nPercent ? "Halt" : "Running";
		pDC->SetTextColor(RGB(0,0,0));
		pDC->SetBkMode(TRANSPARENT);
		pWnd->GetClientRect(rect);
		pDC->TextOut(rect.Width()/2-12, 2, strStatus);
	}
	else {
		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);

		// Indicate running status
		CString strStatus = "Running";
		pDC->SetTextColor(RGB(0,0,0));
		pDC->SetBkMode(TRANSPARENT);
		pWnd->GetClientRect(rect);
		pDC->TextOut(rect.Width()/2-12, 2, strStatus);
	}

	pWnd->ReleaseDC(pDC);
}

void CSpaCodeCoveragePage::IdleAction(void)
{
	// Increase the progress percentage.
	m_nProgress = m_nProgress >= 99 ? 5 : ++m_nProgress;

	// Update the progress bar.
	UpdateBar();
}

void CSpaCodeCoveragePage::WindowToDetail()
{
	// Open a child window to show the detail coverage information.

	// Restore HW configuration.
	BeginWaitCursor();

	::AbiAbort();
	::AbiClrAllBp();
	::RestoreAllConfig();

	EndWaitCursor();

	// Close the whole group.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	if ( pSheet->IsKindOf(RUNTIME_CLASS(CSpaGroupSheet)) ) {
		memcpy(&(pSheet->m_CodeGetData), &m_CodeGetData, sizeof(m_CodeGetData));
		pSheet->EndDialog(IDOK);
	}
	else {
		CPropertyPage::OnOK();
	}
}
                          
void CSpaCodeCoveragePage::DialogToDetail()
{
  	// Open a dialog to show the detail coverage information.
  	CCoverageDetailDlg dlg;
  	dlg.DoModal();
}

void CSpaCodeCoveragePage::ControlToDetail()
{
	// "Detail" or "Normal" ?
	char szButton[8];
	memset(&szButton, 0, sizeof(szButton));
	GetDlgItemText(IDC_BUTTON_SPA_CODE_DETAIL, szButton, 7);
	if ( stricmp(szButton, "Detail") == 0 ) {
		// Show the detail information.
		ToggleToDetailStatus();
	}
	else {
		// Show the normal status.
		ToggleToNormalStatus();
	}
}

void CSpaCodeCoveragePage::ToggleToNormalStatus()
{
	// Hide 2 controls.
	m_staticModule.ShowWindow(SW_HIDE);
	GetDlgItem(IDC_COMBO_SPA_MESSAGEBAR_MODULE)->ShowWindow(SW_HIDE);
	GetDlgItem(IDC_LIST_COVERAGE)->ShowWindow(SW_HIDE);
		
	// Enable 17 controls.
	m_btnRestart.EnableWindow();
	m_btnStart.EnableWindow();
	m_btnEdit.EnableWindow();

	m_btnMode.EnableWindow();
	m_btnBp.EnableWindow();
	m_editBp.EnableWindow();

	m_comboRange1.EnableWindow();
	m_comboRange2.EnableWindow();
	m_comboRange3.EnableWindow();
	m_comboRange4.EnableWindow();

	m_btnRange1.EnableWindow();
	m_btnRange2.EnableWindow();
	m_btnRange3.EnableWindow();
	m_btnRange4.EnableWindow();
	
	m_listInst.EnableWindow();
	m_listBlock.EnableWindow();

	// "Normal" to "Detail".
	SetDlgItemText(IDC_BUTTON_SPA_CODE_DETAIL, "Detail");

	// Update the progress bar.
	m_nProgress = 100;
	UpdateBar();
}

void CSpaCodeCoveragePage::ToggleToDetailStatus()
{
	// Disable 17 controls.
	m_btnRestart.EnableWindow(FALSE);
	m_btnStart.EnableWindow(FALSE);
	m_btnStop.EnableWindow(FALSE);
	m_btnEdit.EnableWindow(FALSE);

	m_btnMode.EnableWindow(FALSE);
	m_btnBp.EnableWindow(FALSE);
	m_editBp.EnableWindow(FALSE);

	m_comboRange1.EnableWindow(FALSE);
	m_comboRange2.EnableWindow(FALSE);
	m_comboRange3.EnableWindow(FALSE);
	m_comboRange4.EnableWindow(FALSE);

	m_btnRange1.EnableWindow(FALSE);
	m_btnRange2.EnableWindow(FALSE);
	m_btnRange3.EnableWindow(FALSE);
	m_btnRange4.EnableWindow(FALSE);
	
	m_listInst.EnableWindow(FALSE);
	m_listBlock.EnableWindow(FALSE);

	// "Detail" to "Normal".
	m_btnDetail.EnableWindow(FALSE);
	SetDlgItemText(IDC_BUTTON_SPA_CODE_DETAIL, "Normal");

	// Enable 2 controls.
	m_staticModule.ShowWindow(SW_SHOW);
	GetDlgItem(IDC_COMBO_SPA_MESSAGEBAR_MODULE)->ShowWindow(SW_SHOW);
	GetDlgItem(IDC_LIST_COVERAGE)->ShowWindow(SW_SHOW);

    // Update the module combo box.
    UpdateModuleInfo();
    
    // Update the first module.
	OnSelchangeComboSpaMessagebarModule();

	m_btnDetail.EnableWindow(TRUE);
}

void CSpaCodeCoveragePage::UpdateModuleInfo()
{
	// Set the module info.
	m_comboModule.ResetContent();

	CStringList* pList = new CStringList;
	if ( 0 == ::SpaGetModule(pList) ) {
	    if ( !pList->IsEmpty() ) {
	        POSITION posHead = pList->GetHeadPosition();
	        while ( posHead ) {
	            m_comboModule.AddString(pList->GetNext(posHead));
	        }
	    }
			
		if ( m_comboModule.GetCount() > 0 ) {
			m_comboModule.SetCurSel(0);
		}
	}
	pList->RemoveAll();
	delete pList;
}

void CSpaCodeCoveragePage::UpdateCodeList(const CString& strFile)
{
	// Read from the source file.
	if ( strFile.IsEmpty() ) {
		return;
	}

	// Get from the document.
	ReadSourceCode(strFile);
	
	// Set the scroll size of the listbox.
    CDC* pDC = GetDC();
    pDC->SelectStockObject(ANSI_FIXED_FONT);
    
    TEXTMETRIC tm;
    pDC->GetTextMetrics(&tm);
    int nFontWidth(tm.tmAveCharWidth);
    int nFontHeight(tm.tmHeight + tm.tmExternalLeading);

    ReleaseDC(pDC);

	m_listCode.SetHorizontalExtent((m_nMaxCol+5)*nFontWidth);

	// Update the entire listbox.
	m_listCode.ResetContent();
	POSITION pos = m_pLineList->GetHeadPosition();
	int nIndex(0);
	while ( pos ) {
		CSpaTextLine* pObj = (CSpaTextLine*)m_pLineList->GetNext(pos);
		m_listCode.AddLine(pObj);
		m_listCode.SetItemDataPtr(nIndex, pObj);
		nIndex++;
	}
}

void CSpaCodeCoveragePage::ReadSourceCode(const CString& strFile)
{
	// If the file exist.
    CFileStatus status;
	if ( !CFile::GetStatus(strFile, status) ) {
		return;
	}

	// Release space.
	POSITION pos = m_pLineList->GetHeadPosition();
	while ( pos ) {
		CSpaTextLine* pObj = (CSpaTextLine*)m_pLineList->GetNext(pos);
		delete pObj;
	}
	m_pLineList->RemoveAll();

	// Open the specific file.
	UINT nOpenFlag = CFile::modeRead | CFile::typeText;
	CStdioFile* fp = new CStdioFile(strFile, nOpenFlag);
	int nMax = 512;
	char* pszLine = new char[nMax+4];
	m_nMaxLine = 0;
	m_nMaxCol = 0;
	while ( fp->ReadString(pszLine, nMax) ) {
		CString strLine(_T(""));
		for ( int i(0); i < int(strlen(pszLine)); i++ ) {
			if ( pszLine[i] >= 0x20 && pszLine[i] <= 0x7F ) {
				strLine += pszLine[i];
			}
			else if ( '\t' == pszLine[i] ) {
				strLine += "    ";
			}
		}

		// Skip ASM module.
		if ( strFile.GetLength() > 4 ) {
			CString strExt(strFile.Right(4));
			strExt.MakeUpper();		
			if ( ".ASM" == strExt ) {
				m_nMaxLine++;
				m_pLineList->AddTail(new CSpaTextLine(strLine, TRUE));
			}
			else {
				m_pLineList->AddTail(new CSpaTextLine(strLine, IsGrayedLine(m_nMaxLine++)));
			}
		}
		else {
			m_pLineList->AddTail(new CSpaTextLine(strLine, IsGrayedLine(m_nMaxLine++)));
		}
		m_nMaxCol = max(m_nMaxCol, strLine.GetLength());
	}
	delete []pszLine;
	
	// Close the specific file.
	fp->Close();
	delete fp;
}

BOOL CSpaCodeCoveragePage::IsGrayedLine(int nLine) const
{
	// Normalize the line number.
	CString str, strModule, strLine;

//	m_comboModule.GetWindowText(strModule);
	int nIndex = m_comboModule.GetCurSel();
	if ( CB_ERR != nIndex ) {
		m_comboModule.GetLBText(nIndex, strModule);
	}

	strLine.Format("%d", nLine+1);
	str = '#';
	str += strModule;
	str += '#';
	str += strLine;

	// Query from symbol server.
	BYTE bType;
	DWORD dwAddr;
	if ( 0 != ::SymToAddr((char*)(const char*)str, &bType, &dwAddr) ) {
		return TRUE;
	}
	
	WORD wLine;
	DWORD dwStart, dwEnd;
	if ( 0 != ::SrcAddr2LinenumRange(bType, dwAddr, wLine, dwStart, dwEnd) ) {
		return TRUE;
	}
	
	// It's comment line.
	if ( nLine + 1 != int(wLine) ) {
		return TRUE;
	}

	// Compare with m_CodeData.
	ASSERT(dwStart <= dwEnd);
	for ( int i(0); i <= m_CodeGetData.uchNumber*2-1; i += 2 ) {
		if ( dwStart >= m_CodeGetData.usAddr[i] && dwStart <= m_CodeGetData.usAddr[i+1] && 
			 bType == m_CodeGetData.bType[i] && bType == m_CodeGetData.bType[i+1] ) {
			return FALSE;
		}
		if ( dwEnd >= m_CodeGetData.usAddr[i] && dwEnd <= m_CodeGetData.usAddr[i+1] &&
			 bType == m_CodeGetData.bType[i] && bType == m_CodeGetData.bType[i+1] ) {
			return FALSE;
		}
	}
	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// CSpaCodeCoveragePage message handlers

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

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

	// Disabled when "Normal".
	char szButton[8];
	memset(&szButton, 0, sizeof(szButton));
	GetDlgItemText(IDC_BUTTON_SPA_CODE_DETAIL, szButton, 7);
	if ( stricmp(szButton, "Normal") == 0 ) {
		return FALSE;
	}

	return CPropertyPage::OnKillActive();
}

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

	// Set the help ID.
	m_nIDHelp = IDD_SPA_CODE;

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

	return CPropertyPage::OnSetActive();
}

void CSpaCodeCoveragePage::OnOK()
{
	// TODO: Add extra cleanup here

	// Don't close the sheet.
	((CSpaGroupSheet*)GetParent())->SetModeless(TRUE);
}
	
void CSpaCodeCoveragePage::OnCancel()
{
	// TODO: Add extra cleanup here
	
	// Kill one-shot timer.
	if ( 0 != m_uTimerID ) {
		KillTimer(m_uTimerID);
	}

    DeleteMerge();
	// Restore HW configuration.
	BeginWaitCursor();
	::AbiAbort();
	::AbiClrAllBp();
	::RestoreAllConfig();

	EndWaitCursor();

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

void CSpaCodeCoveragePage::OnHelp()
{
	// TODO: Add your control notification handler code here
	
	// Active the dialog Help function.
	OnCommandHelp(0, 0);
}

void CSpaCodeCoveragePage::OnButtonSpaEdit()
{
	// TODO: Add your control notification handler code here
	
	// Open the user defined dialog.
	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	CSpaUserDefineDlg dlg(pSheet);
	dlg.DoModal();

	// Update current selection.
	BeginWaitCursor();

	UpdateData();
              
	UpdateCombo();

	UpdateData(FALSE);

	EndWaitCursor();
}

void CSpaCodeCoveragePage::OnButtonSpaStart()
{
	// TODO: Add your control notification handler code here
	
	// Clear current result.
	UpdateData();

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

	// Set coverage data.
	BeginWaitCursor();
	BOOL bOK = SetCoverageData();
    EndWaitCursor();
    if ( !bOK ) {
    	return;
    }

	// Grayed the some controls.
	m_bStop = FALSE;
	DisableControl();
	
	// Enable ESC to cancel this page.
	SetFocus();

	// 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 CSpaCodeCoveragePage::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 coverage info.
		UpdateCoverage(1);
	}
    
	// Grayed some controls.
	m_bStop = TRUE;
	DisableControl();
	DetectDisplayMode();
}

void CSpaCodeCoveragePage::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_listBlock.SetFont(font.FromHandle(hFont));
		m_listInst.SetFont(font.FromHandle(hFont));

		m_listBlock.SetHorizontalExtent(300);
		m_listInst.SetHorizontalExtent(500);

		UpdateCombo();

		UpdateData(FALSE);
	
		EndWaitCursor();
	}
}

void CSpaCodeCoveragePage::OnTimer(UINT nIDEvent)
{
	// TODO: Add your message handler code here and/or call default

	// Added by John.
	if(!(GetXviewAppJohn()->m_bCanTimer)) return; //the abi communication is on
	
	// Not our timer.
	if ( m_uTimerID != nIDEvent ) {
		CPropertyPage::OnTimer(nIDEvent);
		return;
	}
    
	// Update coverage info.
	if ( !m_bStop ) {
		UpdateCoverage();
	}
	else {
		// Kill the timer.
		KillTimer(m_uTimerID);
		m_uTimerID = 0;
		
		// Update the progress bar.
		UpdateBar();
	}
}

void CSpaCodeCoveragePage::OnSelchangeListSpaCodeBlock()
{
	// TODO: Add your control notification handler code here

	// Update Instruction list box.
	UpdateData();
	DetectDisplayMode();
	UpdateInst();
	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnButtonSpaRestart() 
{
	// TODO: Add your control notification handler code here

	// It's as same as OnStart().
    m_nWhichBtn = btnRestart;

	OnButtonSpaStart();
	m_nWhichBtn = btnStart;
}

void CSpaCodeCoveragePage::OnCheckSpaCodeRange1() 
{
	// TODO: Add your control notification handler code here

	// Update check box.
	UpdateData();
	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnCheckSpaCodeRange2() 
{
	// TODO: Add your control notification handler code here
	
	// Update check box.
	UpdateData();
	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnCheckSpaCodeRange3() 
{
	// TODO: Add your control notification handler code here
	
	// Update check box.
	UpdateData();
	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnCheckSpaCodeRange4() 
{
	// TODO: Add your control notification handler code here
	
	// Update check box.
	UpdateData();
	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnButtonSpaCodeMode() 
{
	// TODO: Add your control notification handler code here

	// Toggle Source/Assembly mode.
	UpdateData();
	CString strCaption;
	switch ( m_nMode ) {
		case modeAsm:
			m_nMode = modeSrc;
			strCaption = "=> Assembly";
			break;
		case modeSrc:
			m_nMode = modeAsm;
			strCaption = "=> Source";
			break;
		default:
			ASSERT(FALSE);
			return;
	}
	m_btnMode.SetWindowText(strCaption);
	
	// Update list box.
	if ( m_listBlock.GetCount() > 0 ) {
		UpdateInst();
	}
}

void CSpaCodeCoveragePage::OnButtonSpaBp() 
{
	// TODO: Add your control notification handler code here
	
	// Open the BP set dialog.
	UpdateData();

	CSpaGroupSheet* pSheet = (CSpaGroupSheet*)GetParent();
	CSpaBpSetDlg dlg(pSheet);
	if ( IDOK == dlg.DoModal() ) {
		m_strRange0 = dlg.m_strBp;
	}

	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnEditchangeComboSpaCodeRange1() 
{
	// TODO: Add your control notification handler code here

	// Uncheck the check-box if erasing the input.
	UpdateData();

	m_bRange1 = m_strRange1.IsEmpty() ? FALSE : TRUE;

	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnEditchangeComboSpaCodeRange2() 
{
	// TODO: Add your control notification handler code here
	
	// Uncheck the check-box if erasing the input.
	UpdateData();
	
	m_bRange2 = m_strRange2.IsEmpty() ? FALSE : TRUE;

	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnEditchangeComboSpaCodeRange3() 
{
	// TODO: Add your control notification handler code here
	
	// Uncheck the check-box if erasing the input.
	UpdateData();
	
	m_bRange3 = m_strRange3.IsEmpty() ? FALSE : TRUE;

	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnEditchangeComboSpaCodeRange4() 
{
	// TODO: Add your control notification handler code here
	
	// Uncheck the check-box if erasing the input.
	UpdateData();
	
	m_bRange4 = m_strRange4.IsEmpty() ? FALSE : TRUE;

	UpdateData(FALSE);
}

void CSpaCodeCoveragePage::OnSelchangeComboSpaCodeRange1() 
{
	// TODO: Add your control notification handler code here
	
	// Check the check-box if erasing the input.
	m_bRange1 = TRUE;
	m_btnRange1.SetCheck(1);
}

void CSpaCodeCoveragePage::OnSelchangeComboSpaCodeRange2() 
{
	// TODO: Add your control notification handler code here
	
	// Check the check-box if erasing the input.
	m_bRange2 = TRUE;
	m_btnRange2.SetCheck(1);
}

void CSpaCodeCoveragePage::OnSelchangeComboSpaCodeRange3() 
{
	// TODO: Add your control notification handler code here
	
	// Check the check-box if erasing the input.
	m_bRange3 = TRUE;
	m_btnRange3.SetCheck(1);
}

void CSpaCodeCoveragePage::OnSelchangeComboSpaCodeRange4() 
{
	// TODO: Add your control notification handler code here
	
	// Check the check-box if erasing the input.
	m_bRange4 = TRUE;
	m_btnRange4.SetCheck(1);
}

void CSpaCodeCoveragePage::OnButtonSpaCodeDetail() 
{
	// TODO: Add your control notification handler code here
	
  	// Change some controls to show the detail coverage information.
  	ControlToDetail();
	
/*
  	// Open a dialog to show the detail coverage information.
  	DialogToDetail();
*/

/*
	// Open a child window to show the detail coverage information.
  	WindowToDetail();
*/
}

BOOL CSpaCodeCoveragePage::OnInitDialog()
{
	CPropertyPage::OnInitDialog();
	
	// TODO: Add extra initialization here

	// subclass the control
	VERIFY(m_listCode.SubclassDlgItem(IDC_LIST_COVERAGE, this));
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CSpaCodeCoveragePage::OnSelchangeComboSpaMessagebarModule()
{
	// TODO: Add your control notification handler code here

	// Get from the combo box.
	CString str;
//	m_comboModule.GetWindowText(str);
	int nIndex = m_comboModule.GetCurSel();
	if ( CB_ERR != nIndex ) {
		m_comboModule.GetLBText(nIndex, str);
	}

	// Convert the full path name.
	str = ::SrcGetModuleFullName(str);

	// Update the listbox.
	BeginWaitCursor();
	UpdateCodeList(str);
	EndWaitCursor();
}
