
/***************************************************************************
**
**    $Header:   D:/PICSLDV/SRC/LOG/STKVIEW.CPP   1.14   09 Jan 1997 14:25:40   ZJRD  $
**
**    $Log:   D:/PICSLDV/SRC/LOG/STKVIEW.CPP  $
** 
**    Rev 1.0   13 Aug 1996 09:19:22   ZJRD
** Initial revision.
** 
****************************************************************************/

/////////////////////////////////////////////////////////////////////////////
//
//  File name: STKVIEW.CPP
//
//  Description: The implementation file for the class: CStackView.
//
//  Author: Chen Jun
//
//  Date: 07/29/95
//
//  Modification:
//      1. 07/29/95, Initial version of the class: CStackView.
//      2. 09/08/95, Fix bug 44, "UpdateGrid()".
//		3.    04/95, Modified by Jerry for replace Grid.VBX with CYYHGrid.
//
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
// Include files.
#include "stdafx.h"
#include "resource.h"
#include "EP196.h"
#include "abitype.h"

#include "symblsvr.h"
#include "stkinit.h"
#include "varinit.h" 
#include "stkexp.h"
#include "cpusvr.h"
#include "stkview.h"    
#include "goapi.h"
#include "uicom2.h"

#include "srcdef.h"


/////////////////////////////////////////////////////////////////////////////
// Debug flags.
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// Global variables.
CStackView* pStkView;

HHOOK hookStkKeyFilter = 0;


/////////////////////////////////////////////////////////////////////////////
// External variables.
extern class VarServer stkObject;

extern BOOL bStkShowAddress;
extern BOOL bStkShowEntryPoint;
extern BOOL bStkShowModule;
extern BOOL bStkShowParameters;


/////////////////////////////////////////////////////////////////////////////
// Local define.
/*
#define AFX_NUM_EVENTPARAM(type, lpParams) (type FAR&)(**(type FAR* FAR*)lpParams)
#define AFX_HLSTR_EVENTPARAM(lpParams) (HLSTR FAR&)(*(HLSTR FAR*)lpParams)
#define AFX_NUM_EVENTPARAMINDEX(type, lpParams, index) (short FAR&)(**((type FAR* FAR*)(lpParams) + index))
#define AFX_HLSTR_EVENTPARAMINDEX(lpParams, index) (HLSTR FAR&)(*((HLSTR FAR*)(lpParams) + index))
*/


/////////////////////////////////////////////////////////////////////////////
// External function prototypes.

// Defined in Stack server: STKSVR.CPP
//int StkGetStkLevelNum(int& num );
//int StkGetStkFirstNode(STKNode* & node);
//nt StkGetStkNextNode(STKNode* & node, STKNode* & nextNode);
//int StkGetNodeDisplayString(STKNode* node, CString& s1, CString& s2,
//                                  CString& s3, CString& s4, CString& s5);
//int StkLevelToNode(int nLevel , struct STKNode* &node);

// Defined in STKLOCAL.CPP
void StkUpdateLocalWindow(int nLevel);

// Defined in EMUGO.CPP
void EmuServerGo(ADDR addr);


/////////////////////////////////////////////////////////////////////////////
// Global function prototypes.
void StkUpdateStackWindow(BOOL bUpdateStackOnly = FALSE);
void StkViewSource(void);
void StkRunUntil(void);
void StkSetBreakpoint(void);
int StkGetActiveLevel(void);

LRESULT CALLBACK StkKeyFilterHook(int nCode, WORD wParam, LPMSG /* lpMsg */);

IMPLEMENT_DYNCREATE(CStackView, CView)
/////////////////////////////////////////////////////////////////////////////
// Public functions.

// Filter the special key.
LRESULT CALLBACK StkKeyFilterHook(int nCode, WORD wParam, LPMSG /* lpMsg */)
{
    // Assertion of the input parameters.
    ASSERT( ::pStkView );

    // Hook the special key.
    LRESULT lRetValue = 0;
    
    switch ( nCode ) {
        case HC_ACTION:
            switch ( wParam ) {
                case VK_HOME:
                    ::pStkView->GetDlgItem(IDC_YYHGRID)->SendMessage(WM_HSCROLL, SB_TOP);
                    lRetValue = 1;
                    break;
                case VK_END:
                    ::pStkView->GetDlgItem(IDC_YYHGRID)->SendMessage(WM_HSCROLL, SB_BOTTOM);
                    lRetValue = 1;
                    break;
                case VK_SPACE:
                    lRetValue = 1;
                    break;
                case VK_PRIOR:
                    if ( GetKeyState(VK_CONTROL) & 0x8000 ) {
                        lRetValue = 1;
                    }
                    break;
                case VK_NEXT:
                    if ( GetKeyState(VK_CONTROL) & 0x8000 ) {
                        lRetValue = 1;
                    }
                    break;
                case VK_LEFT:
                    ::pStkView->GetDlgItem(IDC_YYHGRID)->SendMessage(WM_HSCROLL, SB_LINELEFT);
                    lRetValue = 1;
                    break;
                case VK_RIGHT:
                    ::pStkView->GetDlgItem(IDC_YYHGRID)->SendMessage(WM_HSCROLL, SB_LINERIGHT);
                    lRetValue = 1;
                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }
    
    return (lRetValue);
}
    

// Update the stack view.
void StkUpdateStackWindow(BOOL bUpdateStackOnly)
{
    // Assertion of the input parameters.
    ASSERT( ::pStkView );
    
    // Update the stack view.
    ::pStkView->UpdateStackWindow(bUpdateStackOnly);
//	StkUpdateLocalWindow(0);
    
}

// Inspect the source line.
void StkInspectSource(void)
{
    // Assertion of the input parameters.
    ASSERT( ::pStkView );
    
    // Inspect source line.
    ::pStkView->InspectSource();
}

// Set the breakpoint at the specific address.
void StkSetBreakpoint(void)
{
    // Assertion of the input parameters.
    ASSERT( ::pStkView );
    
    // Set breakpoint.
    ::pStkView->SetBreakpoint();
}

// Run until the specific address.
void StkRunUntil(void)
{
    // Assertion of the input parameters.
    ASSERT( ::pStkView );
    
    // Go till address.
    ::pStkView->RunUntil();
}

// Get the current active level.
int StkGetActiveLevel(void)
{
    // Assertion of the input parameters.
    ASSERT( ::pStkView );

    // Get the current active level.
    return (::pStkView->GetActiveLevel());
}


/////////////////////////////////////////////////////////////////////////////
// CStackView


void CStackView::InitialMember(void)
{
    // Depand on design.
    m_nMaxColumn = totalColumn;

    m_strLevel = " ";
    m_strAddress = " ";
    m_strEntryPoint = " ";
    m_strModule = " ";
    m_strFunction = " ";

    // Havn't initail grid.
    m_bUpdateStackOnly = FALSE;
    // Get the maximum level number.
    GetMaxLevel();
}

CStackView::CStackView():CView()
{
    //{{AFX_DATA_INIT(CStackView)
	//}}AFX_DATA_INIT
    
    // Initial.
    InitialMember();

    // Set the global pointer.
    ::pStkView = this;
}

CStackView::~CStackView()
{}  


void CStackView::OnDraw(CDC* pDC) 
{
   //CWnd::OnDraw(pDC);
}

void CStackView::DoDataExchange(CDataExchange* pDX)
{
    CView::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CStackView)
	//}}AFX_DATA_MAP
}

CStackDoc* CStackView::GetDocument() // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CStackDoc)));
    return (CStackDoc*)m_pDocument;
}


/////////////////////////////////////////////////////////////////////////////
// Public function.

// Update the whole stack pane.
void CStackView::UpdateStackWindow(BOOL bUpdateStackOnly)
{
    // Assertion of the input parameters.
    
    // Initial again.
    if ( !bUpdateStackOnly ) {
        GetMaxLevel();
    }
    
    // Refresh the grid.
    m_bUpdateStackOnly = bUpdateStackOnly;
    UpdateGrid();
//    int num;
//    Stk_GetNumber(num);
//	if(!bUpdateStackOnly&& m_nMaxLevel) StkUpdateLocalWindow(m_nCurRow-1);
	
	// added for stack overflow    
    CString strTitle;
    if ( !strTitle.LoadString(IDR_STACK) ) return;
    if (Stk_IsOverFlow() > 0 ) strTitle += " - Overflow";
    else if ( Stk_IsOverFlow() < 0 ) strTitle += " - Underflow";
	extern CMDIChildWnd* pStackWnd; // Defined in UICOM.H
//	pStackWnd->SetWindowText(strTitle);
// Modified by Gates Hua
	CStackDoc* pDoc = GetDocument();
//	pStackWnd->SetWindowText(strTitle);
	pDoc->SetTitle(strTitle);
}

// Inspect the source line.
void CStackView::InspectSource(void)
{
    // Assertion of the input parameters.

    // Get the entry point address.
    if ( 0 == ::StkLevelToNode((int)(m_Grid.m_nActiveRow-1), m_pStkNode) ) {
        // John will fix this bug
        ::SrcInspectSource(((DWORD)m_pStkNode->addr)&0xffff, (((DWORD)m_pStkNode->addr)>>16)+1);
    }
}

// Set the breakpoint at the specific address.
void CStackView::SetBreakpoint(void)
{
    // Assertion of the input parameters.

    // Get the entry point address.
    if ( 0 == ::StkLevelToNode((int)(m_Grid.m_nActiveRow-1), m_pStkNode) ) {
        // John will fix this bug
		 ::BptSetBpFromList(CSourceAddr(((DWORD)m_pStkNode->addr)&0xffff, (((DWORD)m_pStkNode->addr)>>16)+1));
        ::SrcInspectSource(((DWORD)m_pStkNode->addr)&0xffff, (((DWORD)m_pStkNode->addr)>>16)+1);
    }
}

// Run until the specific address.
void CStackView::RunUntil(void)
{
    // Assertion of the input parameters.

    // Get the entry point address.
    if ( 0 == ::StkLevelToNode((int)(m_Grid.m_nActiveRow-1), m_pStkNode) ) {
        // Call EMUGO routine.
        ADDR addr;
        addr.addr = ((DWORD)m_pStkNode->addr1)&0xffff;
        addr.addrType = (((DWORD)m_pStkNode->addr1)>>16)+1;
        ::EmuServerGo(3,addr);

	
        // Call SRCWIN routine.
        ::SrcInspectSource(((DWORD)m_pStkNode->addr1)&0xffff, (((DWORD)m_pStkNode->addr1)>>16)+1);

        ::OnEmulation();
    }
}

// Get the active level.
int CStackView::GetActiveLevel(void)
{
    // Assertion of the input parameters.

    // Get the maximum level.
    if ( m_nMaxLevel < 1 ) {
        return (-1);
    }
    else {
        return m_Grid.m_nActiveRow-1;
    }
}


/////////////////////////////////////////////////////////////////////////////
// Common function.

// Get the maximum stack level.
void CStackView::GetMaxLevel(void)
{
    // Assertion of the input parameters.
    
    // Delete all the local variables & stack information.
    Stk_VarDeleteAll();

    // Get from Stack server.
    if ( -1 == ::StkGetStkLevelNum(m_nMaxLevel) ) {
        m_nMaxLevel = 0;
    }
}

// Get the information from Stack server.
void CStackView::GetStackInfo(void)
{
    // Assertion of the input parameters.
    ASSERT( m_nMaxLevel > 0 );

    // Get the first node.
    if ( -1 == ::StkGetStkFirstNode(m_pStkNode) ) {
        return;
    }
        
    // Get the detail information by referring to m_pStkNode.
    if ( m_Grid.m_nActiveRow < 1 ) m_Grid.m_nActiveRow = 1;
    m_nCurRow = 0;
    do {
        int nRetValue = ::StkGetNodeDisplayString(m_pStkNode, m_strLevel,
                m_strAddress, m_strEntryPoint, m_strModule, m_strFunction);
        if ( -1 == nRetValue ) {
            return;
        }
        else if ( 0 == nRetValue ) {
            m_nCurRow++;
            //SetColumnWidth();
			HideColumn();
            ShowStackInfo();
        }
        else {
            ASSERT( FALSE );
        }
    } while ( 0 == ::StkGetStkNextNode(m_pStkNode, m_pStkNode) );
    m_Grid.UpdateWindow();
}


/////////////////////////////////////////////////////////////////////////////
// Grid operation.

// Update grid.
void CStackView::UpdateGrid(void)
{

//    int nMaxRow ;//= (int)
	m_Grid.ResetContent(m_nMaxLevel+1);  
    if ( 0 == m_nMaxLevel ) {
        // Clear the Local window when reset to no stack information.
        //m_Grid.ResetContent(m_nMaxLevel+1);
        ::StkUpdateLocalWindow(-1);
        return;
    }
    // Get the Stack information from server.
    if ( m_nMaxLevel > 0 ) {     
        
        GetStackInfo();
        OnUpdateLocal(1,1);	// for local window refresh
    }
    
	m_Grid.ResizeCell(0,0);		// added by Jamoon for Format Function List
    // Reset the active row.
//    ResetRow();
}


// Hide the special columns.
void CStackView::HideColumn(void)
{
    // Assertion of the input parameters.

    // Hide or show address.
    BOOL bInvalidate=0;
    if(!::bStkShowAddress)
    {	m_Grid.m_nColWidth[addressColumn]=0; bInvalidate=1;}
    else if(m_Grid.m_nColWidth[addressColumn]==0)
         { m_Grid.m_nColWidth[addressColumn]=m_Grid.m_nDefColWidth;
           bInvalidate=1; 	   
         }  
    // Hide or show entry point.                
    if(!::bStkShowEntryPoint)
    {	m_Grid.m_nColWidth[entryPointColumn]=0;    
    	bInvalidate=1;
    }	
    else if(m_Grid.m_nColWidth[entryPointColumn]==0)
         {
             m_Grid.m_nColWidth[entryPointColumn]=m_Grid.m_nDefColWidth;
             bInvalidate=1;
         }    
    // Hide or show module.
    if(!::bStkShowModule)
    {	m_Grid.m_nColWidth[moduleColumn]=0;    
    	bInvalidate=1;
    }	
    else if(m_Grid.m_nColWidth[moduleColumn]==0)  
         {
            m_Grid.m_nColWidth[moduleColumn]=m_Grid.m_nDefColWidth;
            bInvalidate=1;
         }   
    // Hide or show function parameters.
    if ( ::bStkShowParameters ) {
        m_Grid.SetCellText(functionColumn,m_nCurRow,m_strFunction.GetBuffer(24));
        m_Grid.UpdateWindow();
        m_strFunction.ReleaseBuffer();
    }
    else {
        int i = m_strFunction.Find('(');
        if ( -1 != i && ')' != m_strFunction[i+1] ) {
            CString str = m_strFunction.Left(i);
            str += "(...)";
            m_Grid.SetCellText(functionColumn,m_nCurRow,str.GetBuffer(24));
            m_Grid.UpdateWindow();
            str.ReleaseBuffer();
        }
        else if ( -1 != i ) {
		    m_Grid.SetCellText(functionColumn,m_nCurRow,m_strFunction.GetBuffer(24));
		    m_Grid.UpdateWindow();
		}
    } 
   	m_Grid.ActiveColValidate();

    if(bInvalidate){
    	m_Grid.Invalidate();
    	m_Grid.UpdateWindow();
    }	
}                                       


// Show stack information in the grid.
void CStackView::ShowStackInfo(void)
{
    // Assertion of the input parameters.
                         
    // Set the current row.
//    m_pGrid->SetNumProperty("Row", m_nCurRow);
      
    // Show level number.
//    m_pGrid->SetNumProperty("Col", levelColumn);
//    m_pGrid->SetStrProperty("Text", m_strLevel);
      m_Grid.SetCellText(levelColumn,m_nCurRow,(m_strLevel.GetBuffer(24)));  
      m_strLevel.ReleaseBuffer();
    // Show address.
//    m_pGrid->SetNumProperty("Col", addressColumn);
//    m_pGrid->SetStrProperty("Text", "0x" + m_strAddress);
      CString s=("0x" + m_strAddress);
      m_Grid.SetCellText(addressColumn,m_nCurRow,s.GetBuffer(24));
      s.ReleaseBuffer();
    // Show entry point.
//    m_pGrid->SetNumProperty("Col", entryPointColumn);
//    m_pGrid->SetStrProperty("Text", m_strEntryPoint);
      m_Grid.SetCellText(entryPointColumn,m_nCurRow,(m_strEntryPoint.GetBuffer(24)));
	m_strEntryPoint.ReleaseBuffer();
    // Show module.
//    m_pGrid->SetNumProperty("Col", moduleColumn);
//    m_pGrid->SetStrProperty("Text", m_strModule);
     m_Grid.SetCellText(moduleColumn,m_nCurRow,(m_strModule.GetBuffer(24)));
     m_strModule.ReleaseBuffer();
    // Show function.
//    m_pGrid->SetNumProperty("Col", functionColumn);
//    m_pGrid->SetStrProperty("Text", m_strFunction);
   	 if ( ::bStkShowParameters ) {
        m_Grid.SetCellText(functionColumn,m_nCurRow,m_strFunction.GetBuffer(24));
        m_Grid.UpdateWindow();
        m_strFunction.ReleaseBuffer();
     }
     else {
        int i = m_strFunction.Find('(');
        if ( -1 != i && ')' != m_strFunction[i+1] ) {
            CString str = m_strFunction.Left(i);
            str += "(...)";   
            m_Grid.SetCellText(functionColumn,m_nCurRow,str.GetBuffer(24));
            m_Grid.UpdateWindow();
            str.ReleaseBuffer();
        }
     } 
//	m_Grid.SetCellText(functionColumn,m_nCurRow,m_strFunction.GetBuffer(24));
//	m_strFunction.ReleaseBuffer();
}


// Hihglight the active row.
LONG CStackView::OnUpdateLocal(UINT,LONG)
{
    // Assertion of the input parameters.
    
        // Update the local variables.
        if ( !m_bUpdateStackOnly ) {
            ::StkUpdateLocalWindow((int)(m_Grid.m_nActiveRow-1));
        }
        else {
            m_bUpdateStackOnly = FALSE;
        }                         
        return 1;
}

/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CStackView, CView)
    //{{AFX_MSG_MAP(CStackView)
    ON_WM_SIZE()
    ON_WM_SETCURSOR()
    ON_WM_DESTROY()
    ON_WM_RBUTTONDOWN()
	ON_WM_SETFOCUS()
	ON_WM_KILLFOCUS()                
	ON_MESSAGE(SM_UPDATELOCAL,OnUpdateLocal)
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CStackView message handlers



void CStackView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
    
    // TODO: Add your message handler code here

    // Get the client area size.
    GetClientRect(m_rectClient);
    m_Grid.MoveWindow(&m_rectClient);
    // Update grid contents.
}

BOOL CStackView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    // TODO: Add your message handler code here and/or call default

    // Send the WM_RBUTTONDOWN message to implement local menu.
    if( HTCLIENT == nHitTest && WM_RBUTTONDOWN == message ) {
        return FALSE;
    }

    return CView::OnSetCursor(pWnd, nHitTest, message);
}



void CStackView::OnDestroy()
{
    CView::OnDestroy();
    
    // TODO: Add your message handler code here
    
    // Remove the hook function from the hook chain.
    if ( ::hookStkKeyFilter ) {
        UnhookWindowsHookEx(::hookStkKeyFilter);
        ::hookStkKeyFilter = 0;
    }
}

void CStackView::OnRButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Add your message handler code here and/or call default
    
    // Create the local menu.
    CMenu* pLocalMenu = new CMenu;
    ASSERT( NULL != pLocalMenu );
    if ( !pLocalMenu ) {
        AfxMessageBox("Insufficient memory.");
        return;
    }
    pLocalMenu->CreatePopupMenu();
    
    // Define the local menu.
    pLocalMenu->AppendMenu(MF_STRING, ID_EDIT_INSPECTSOURCE, "&Inspect Source");
    pLocalMenu->AppendMenu(MF_STRING, ID_VIEW_SETBREAKPOINT, "Set &Breakpoint");
    pLocalMenu->AppendMenu(MF_STRING, ID_VIEW_RUNUNTIL, "&Run Until");
    pLocalMenu->AppendMenu(MF_STRING, ID_VIEW_FORMATFUNCTIONLIST, "For&mat Function List...");
    
// Modified by Gates Hua -- start
//    // Adjust the cursor location.
//    CPoint pt(m_rectClient.Width()/2, m_rectClient.Height()/2);

    // Adjust the cursor location.
    CPoint pt(point.x, point.y);

    if ( 0 == pt.x && 0 == pt.y ) {
        CRect rect;
        GetClientRect(&rect);
        pt = CPoint(rect.left+rect.Width()/2, rect.top+rect.Height()/2);
    }
// -- end

    // Display the local menu.
    ClientToScreen(&pt);
    
    // Active the local menu.
    pLocalMenu->TrackPopupMenu(TPM_LEFTALIGN, pt.x, pt.y, GetParent()->GetParent());
    
    // Release the allocated buffer.
    delete pLocalMenu;

    CView::OnRButtonDown(nFlags, point);
}

void CStackView::OnSetFocus(CWnd* pOldWnd)
{
	CView::OnSetFocus(pOldWnd);
	
	m_Grid.SetFocus(); 
/*	   if ( !::hookStkKeyFilter ) {
        ::hookStkKeyFilter = 
            SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)::StkKeyFilterHook,
                             AfxGetApp()->m_hInstance, GetCurrentTask());
    }
*/	
}

void CStackView::OnKillFocus(CWnd* pNewWnd)
{
	CView::OnKillFocus(pNewWnd);
	
	    if ( ::hookStkKeyFilter ) {
        UnhookWindowsHookEx(::hookStkKeyFilter);
        ::hookStkKeyFilter = 0;
    }
	
}

int CStackView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1; 
    DWORD dwStyle=WS_HSCROLL|WS_VSCROLL|WS_VISIBLE;
	
	CRect rect;
	GetClientRect(&rect);
	if(!m_Grid.Create(this,dwStyle,rect,IDC_YYHGRID) ) 
	     return -1;
	m_Grid.SetCellText(0,0,"Level");     
	m_Grid.SetCellText(1,0,"Address");     
	m_Grid.SetCellText(2,0,"Entry Point");     
    m_Grid.SetCellText(3,0,"Module");     
	m_Grid.SetCellText(4,0,"Function");        
	// TODO: Add your specialized creation code here
	return 0;
}
