/***************************************************************************
**
**    $Header$
**
**    $Log$
** 
****************************************************************************/

// srcimp.cpp : implementation file
//

#include "stdafx.h"
#include "ep196.h"
#include "srcdef.h"
#include "mainfrm.h"

#include "address.h"
#include "abiextfn.h"
#include "dadextfn.h"
#include "ldrexp.h"
#include "symblsvr.h"

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

/////////////////////////////////////////////////////////////////////////////
// External function

void ShowLine(char* pszBuffer);
void VarAddVariable(const CString strToken);

/////////////////////////////////////////////////////////////////////////////
// Imported function

#ifdef __cplusplus
extern "C" {
#endif	// __cplusplus

void WINAPI SrcShowLine(const CString& strLine)
{
	// Show line within Shell window
	::ShowLine((char*)(const char*)strLine);
}

BOOL WINAPI SrcGetStartAddr(const CSourceAddr& AddrBase, CSourceAddr& AddrStart, const int nUpLine /* = 1 */)
{
	// Reset: 0x2080
	const DWORD cdwReset = 0x2080;
	if ( AddrBase == cdwReset ) {
		AddrStart = AddrBase;
		return TRUE;
	}

	// Get minPC & maxPC
	DWORD dwMinPC(0), dwMaxPC(0xFFFF);

	// Call DAD server to get instruction: 20 bytes
	const DWORD cdwPreFetchByte = 20;

	::ADDR addrStart, addrEnd;
	addrStart.addrType = AddrBase.GetType();
	addrStart.addr = AddrBase <= dwMinPC + cdwPreFetchByte ? dwMinPC : AddrBase.GetAddr()-cdwPreFetchByte;
	addrEnd.addrType = AddrBase.GetType();
	addrEnd.addr = AddrBase.GetAddr();
	
	BOOL bMatchReset(FALSE);
	if ( addrStart.addr <= cdwReset && addrEnd.addr >= cdwReset ) {
		if ( nUpLine > 1 ) {
			AddrStart = CSourceAddr(cdwReset, AddrBase.GetType());
			return TRUE;
		}
		addrStart.addr = cdwReset;
		bMatchReset = TRUE;
	}

	CDADExtFnBase* pObj = new CDADExtFnCom(addrStart, addrEnd);
	DWORD dw;
	if ( !pObj ) {
		goto _UpOneByte;
	}
	for ( dw = 0; dw < cdwPreFetchByte; dw++ ) {
		if ( pObj->GetResult() == CDADExtFnBase::DAD_OK ) {
			CWordArray* pDirty = &pObj->GetIsDirtyResultArray();
			if ( !pDirty->GetAt(pDirty->GetSize()-1) ) {
				if ( nUpLine > 1 ) {
					AddrStart = CSourceAddr(addrStart.addr, addrStart.addrType);
				}
				else {
					CString strAddr = (&pObj->GetAddrList())->GetTail();
					::SrcTextToAddr(strAddr, AddrStart);
				}
				delete pObj;
				return TRUE;
			} 
		}

		addrStart.addr++;
		if ( addrStart.addr <= addrEnd.addr ) {
			pObj->SetAddress(addrStart, addrEnd);
			pObj->Disasm(FALSE);
		}
	}
	delete pObj;
	
	if ( bMatchReset ) {
		AddrStart = CSourceAddr(cdwReset, AddrBase.GetType());
		return TRUE;
	}

	goto _UpOneByte;

//	// Query from Symbol server
//	if ( ::SrcIsLoadedSymbol() ) {
//		// Get the last Line & Label address
//		int SymGetLastLabel(const DWORD dwAddrBase, const int nBank, DWORD& dwAddr);
//	
//		RETCODE WINAPI
//		SymMapAddr2Symbol(ADDRESS_TYPE   inputAddr,
//		                  MEM_ADDR_CLASS FAR *memoryClass,
//		                  SYM_TYPE_TYPE  FAR *symbolType,
//		                  U32            FAR *offset,
//		                  SYM_DESCRIPTOR FAR *outputSymbol,
//		                  SYM_DESCRIPTOR FAR *funcDescriptor,
//		                  SYM_DESCRIPTOR FAR *moduleDescriptor);
//	
//		return TRUE;
//	}
//

_UpOneByte:
	// 1st algorithm: Up n byte codes
	AddrStart = AddrBase;
	for ( int i(nUpLine); i > 1; i-- ) {
		AddrStart = AddrStart - 1;
		if ( AddrStart == dwMinPC ) {
			return TRUE;
		}
	}

	return TRUE;
}

BOOL WINAPI SrcGetAsmCodeAddr(const CSourceAddr& AddrStart, const CSourceAddr& AddrEnd, CStringList* &pCodeList, CStringList* &pInstList, CStringList* &pSymList, CStringList* &pAddrList)
{
	// Call DAD server to get instruction: MIX mode
	::ADDR addrStart, addrEnd;
	addrStart.addrType = AddrStart.GetType();
	addrStart.addr = AddrStart.GetAddr();
	addrEnd.addrType = AddrEnd.GetType();
	addrEnd.addr = AddrEnd.GetAddr();
		
	CDADExtFnBase* pObj = new CDADExtFnCom(addrStart, addrEnd);
	if ( !pObj ) {
		return FALSE;
	}
    
    BOOL bOK(FALSE);
	switch ( pObj->GetResult() ) {
	case CDADExtFnBase::DAD_NEED_MORE:
		// Object code has been changed
		//::MessageBeep(-1);
	case CDADExtFnBase::DAD_OK:
		pCodeList->AddTail(&pObj->GetCodeList());
		pInstList->AddTail(&pObj->GetInstrList());
		pSymList->AddTail(&pObj->GetSymList());
		pAddrList->AddTail(&pObj->GetAddrList());

		ASSERT(pCodeList->GetCount() > 0 && pCodeList->GetCount() == pInstList->GetCount() && pCodeList->GetCount() == pSymList->GetCount()  && pCodeList->GetCount() == pAddrList->GetCount());

		bOK = TRUE;
		break;
	default:
		ASSERT(FALSE);
		break;
	}

	delete pObj;
	
	return bOK;
}

BOOL WINAPI SrcGetAsmCodeLine(const CSourceAddr& AddrStart, const int nLine, CStringList* &pCodeList, CStringList* &pInstList, CStringList* &pSymList, CStringList* &pAddrList)
{
	// Call DAD server to get instruction: ASM mode
	::ADDR addrStart;
	addrStart.addrType = AddrStart.GetType();
	addrStart.addr = AddrStart.GetAddr();
	WORD wAsmLine = (WORD)nLine;
		
	CDADExtFnBase* pObj = new CDADExtFnCom(addrStart, wAsmLine);
	if ( !pObj ) {
		return FALSE;
	}
    
    BOOL bOK(FALSE);
	switch ( pObj->GetResult() ) {
	case CDADExtFnBase::DAD_NEED_MORE:
		// Match the boundary: P0:FFFA ~ P0:FFFF
	case CDADExtFnBase::DAD_OK:
		pCodeList->AddTail(&pObj->GetCodeList());
		pInstList->AddTail(&pObj->GetInstrList());
		pSymList->AddTail(&pObj->GetSymList());
		pAddrList->AddTail(&pObj->GetAddrList());

		ASSERT(pCodeList->GetCount() > 0 && pCodeList->GetCount() == pInstList->GetCount() && pCodeList->GetCount() == pSymList->GetCount()  && pCodeList->GetCount() == pAddrList->GetCount());

		bOK = TRUE;
		break;
	default:
		ASSERT(FALSE);
		break;
	}

	delete pObj;
	
	return bOK;
}

void WINAPI SrcPrintSetup()
{
	// Standard print setup command
	((CEp196App*)AfxGetApp())->OnFilePrintSetup();
}

LPCSTR WINAPI SrcGetBarToken()
{
	// Get token from Search combo-box within the toolbar
	char szToken[255+1];
	memset(szToken, 0, sizeof(szToken));
	((CMainFrame*)AfxGetMainWnd())->m_wndToolBar.GetDlgItemText(IDC_SERCOMBO, szToken, 255);

	return szToken;
}

void WINAPI SrcSetBarToken(const CString& strWhat)
{
	// Add token to the toolbar combo-box
	((CMainFrame*)AfxGetMainWnd())->m_wndToolBar.SetDlgItemText(IDC_SERCOMBO, strWhat);
}

void WINAPI SrcSetBarCombo()
{
	// Add to toolbar combo-box without same token
	CStringList* pList = ::SrcGetSearchList();
	
	CSuperToolBar* pToolBar = (CSuperToolBar*) &((CMainFrame*)AfxGetMainWnd())->m_wndToolBar;
	pToolBar->m_cmbSrch.ResetContent();
	POSITION pos = pList->GetHeadPosition();
	while ( pos ) {
		pToolBar->m_cmbSrch.AddString(pList->GetNext(pos));
	}
	pToolBar->m_cmbSrch.SetCurSel(0);
}

HWND WINAPI SrcGetSearchComboHwnd()
{
	// Get the handle of the search combo-box
	CSuperToolBar* pToolBar = (CSuperToolBar*) &((CMainFrame*)AfxGetMainWnd())->m_wndToolBar;
	
	return pToolBar->m_cmbSrch.GetSafeHwnd();
}

void WINAPI SrcAddVariable(const CString& strToken)
{
	// Add a variable into Variable window
	::VarAddVariable(strToken);
}

void WINAPI SrcAddToRecentFileList(const CString& strPath)
{
	// Add full path to the recent file list
	AfxGetApp()->AddToRecentFileList(strPath);
}

#ifdef __cplusplus
}
#endif	// __cplusplus
