// ReadLogsDlg.cpp : implementation file
//

#include "stdafx.h"
#include "emshell.h"
#include "ReadLogsDlg.h"
#include "EmShell.h"

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

extern BSTR CopyBSTR( LPBYTE  pb, ULONG   cb );

const char*     gslCarriageReturn           = "\r";
const TCHAR*    gtcFileOpenFlags            = _T("w+b");
const TCHAR*    gtcTempFilenameSeed         = _T("ems");
const char*     gslFirstChance              = "first chance";
const char*     gslCode                     = " - code";
const char*     gslKV                       = "> kv";
const char*     gslChildEBP                 = "ChildEBP";
const char*     gslPrompt                   = ">";
const char*     gslUEIP                     = "> u eip";
const char*     gslSemiColon                = ":";
const char*     gslReadLogsAV               = "READLOGS_AV";
const char*     gslReadLogsDB               = "READLOGS_DB";
const char*     gslTildaStarKV              = "~*kv";
const char*     gslBangLocks                = "!locks";
const char*     gslIDColon                  = "id: ";
const char*     gslCritSecText              = "CritSec ";
const char      gslSpace                    = ' ';
const char*     gslOwningThread             = "OwningThread";
const char*     gslPeriod                   = ".";
const char*     gslWaitForSingleObject      = "WaitForSingleObject";
const char*     gslWaitForMultipleObjects   = "WaitForMultipleObjects";
const char*     gslWaitForCriticalSection   = "WaitForCriticalSection";

/////////////////////////////////////////////////////////////////////////////
// CReadLogsDlg dialog


CReadLogsDlg::CReadLogsDlg(PEmObject pEmObj, IEmManager *pEmMgr, CWnd* pParent /*=NULL*/)
	: CDialog(CReadLogsDlg::IDD, pParent)
{
    _ASSERTE( pEmObj != NULL );
    _ASSERTE( pEmMgr != NULL );

    m_pEmObject         = pEmObj;
    m_pIEmManager       = pEmMgr;
    m_bAdvancedWindow   = FALSE;
    m_pLogFile          = NULL;

	//{{AFX_DATA_INIT(CReadLogsDlg)
	m_csCompleteLog = _T("");
	m_strExceptionType = _T("");
	m_strExceptionLocation = _T("");
	m_strFailingInstruction = _T("");
	//}}AFX_DATA_INIT
}


void CReadLogsDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CReadLogsDlg)
	DDX_Control(pDX, IDC_STATIC_EXCEPINFO, m_ctlStaticExcepInfo);
	DDX_Control(pDX, IDC_STATIC_HANGINFO, m_staticHangInfo);
	DDX_Control(pDX, IDC_STATIC_FAILING_INSTRUCTION, m_ctlStaticFailingInstruction);
	DDX_Control(pDX, IDC_STATIC_EXCEPTION_LOCATION, m_ctlStaticExceptionLocation);
	DDX_Control(pDX, IDC_STATIC_EXCEPTION_TYPE, m_ctlStaticExceptionType);
	DDX_Control(pDX, IDC_STATIC_CALL_STACK, m_ctlStaticCallStack);
	DDX_Control(pDX, IDC_EDIT_FAILING_INSTRUCTION, m_ctlEditFailingInstruction);
	DDX_Control(pDX, IDC_EDIT_EXCEPTION_TYPE, m_ctlEditExceptionType);
	DDX_Control(pDX, IDC_EDIT_EXCEPTION_LOCATION, m_ctlEditExceptionLocation);
	DDX_Control(pDX, IDC_LIST_CALL_STACK, m_ctlListControl);
	DDX_Control(pDX, IDC_ADVANCED, m_ctrlAdvancedBtn);
	DDX_Control(pDX, IDC_EDIT_READLOGS, m_ctrlCompleteReadLog);
	DDX_Text(pDX, IDC_EDIT_READLOGS, m_csCompleteLog);
	DDX_Text(pDX, IDC_EDIT_EXCEPTION_TYPE, m_strExceptionType);
	DDX_Text(pDX, IDC_EDIT_EXCEPTION_LOCATION, m_strExceptionLocation);
	DDX_Text(pDX, IDC_EDIT_FAILING_INSTRUCTION, m_strFailingInstruction);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CReadLogsDlg, CDialog)
	//{{AFX_MSG_MAP(CReadLogsDlg)
	ON_BN_CLICKED(IDC_ADVANCED, OnAdvanced)
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CReadLogsDlg message handlers

BOOL CReadLogsDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// TODO: Add extra initialization here

    HRESULT hr                                  = E_FAIL;
    ULONG   lRead                               = 0L;
    size_t  tWritten                            = 0;
    BSTR    bstrEmObj                           = NULL;
    TCHAR   szTempDirPath[MAX_PATH]             = {0};
    TCHAR   szTempFileName[MAX_PATH]            = {0};
    char    lpszLogData[ISTREAM_BUFFER_SIZE];

    do {
        CWaitCursor wait;
        
        if( !m_pEmObject || !m_pIEmManager ) break;

        bstrEmObj = CopyBSTR( (LPBYTE) m_pEmObject, sizeof EmObject );

        //Load the read logs stream from the manager
        hr = m_pIEmManager->GetEmFileInterface( bstrEmObj, (IStream **)&m_pIEmStream );
        if( FAILED(hr) ) break;

        SysFreeString( bstrEmObj ); 

        //Get the temporary system path
        if ( 0 == GetTempPath( MAX_PATH, szTempDirPath ) ) break;

        //Create a temp filename
        GetTempFileName( szTempDirPath, gtcTempFilenameSeed, 0, szTempFileName);

        m_pTempLogFileName = szTempFileName;

        //Create a temp file in the system temp directory
        m_pLogFile = _tfopen( m_pTempLogFileName, gtcFileOpenFlags );
        if ( m_pLogFile == NULL ) break;

        //Check the second line, if it's not either READLOGS_AV OR READLOGS_DB, cancel
        for (int i = 1; i < 2; i++) {

            hr = m_pIEmStream->Read( (void *)lpszLogData, ISTREAM_BUFFER_SIZE, &lRead );
            if ( lRead == 0 || FAILED( hr ) ) break;
        
            m_csCompleteLog += lpszLogData;

            tWritten = fwrite( lpszLogData, sizeof( char ), lRead, m_pLogFile );
            if ( tWritten == 0 ) {
                hr = E_FAIL;
                break;
            }
            
            if ( i == 1) {

                //Check to see which version of the dlg we should be showing
                if ( strstr( lpszLogData, gslReadLogsAV ) )
                    m_eReadLogType = ReadLogsType_Exception;
                else if ( strstr( lpszLogData, gslReadLogsDB ) )
                    m_eReadLogType = ReadLogsType_Hang;
                else
                    m_eReadLogType = ReadLogsType_None;

            }
        } while ( FALSE );

        if ( FAILED( hr) ) break;

        //Continue to read the log into the temp file
        do {
        
            hr = m_pIEmStream->Read( (void *)lpszLogData, ISTREAM_BUFFER_SIZE, &lRead );
            if ( lRead == 0 || FAILED( hr ) ) break;
        
            m_csCompleteLog += lpszLogData;

            tWritten = fwrite( lpszLogData, sizeof( char ), lRead, m_pLogFile );
            if ( tWritten == 0 ) {
                hr = E_FAIL;
                break;
            }

        } while (TRUE);

        if ( FAILED( hr ) ) break;

        //Flush the data to the file.
        fflush( m_pLogFile );

        switch ( m_eReadLogType ) {
        case ReadLogsType_Exception:
            ParseAndInitExceptionView();
            break;
        case ReadLogsType_Hang:
            ParseAndInitHangView();
            break;
        case ReadLogsType_None:
            ParseAndInitNoneView();
            break;
        default:
            break;
        }
        
        UpdateData(FALSE);
    } while ( FALSE );

    SysFreeString( bstrEmObj ); 

	if (m_pIEmStream) m_pIEmStream->Release();

    //
    // a-mando
    //
    ShowAppropriateControls();
    ResizeAndReposControl();
    // a-mando

    SetDialogSize(FALSE);

    if( FAILED(hr) ) { 
		//Show msg box
		((CEmshellApp*)AfxGetApp())->DisplayErrMsgFromHR(hr);
		return FALSE; 
	}

    return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CReadLogsDlg::SetDialogSize(BOOL bAdvanced)
{
    CRect   rtCompleteLog,
            rtDlg;

    GetWindowRect( &rtDlg );
    m_ctrlCompleteReadLog.GetWindowRect( &rtCompleteLog );

    rtDlg.bottom = rtCompleteLog.top;

    if( bAdvanced ) {

        rtDlg.bottom = rtCompleteLog.bottom + DLG_PIXEL_EXTEND_SIZE;
        m_ctrlCompleteReadLog.ShowWindow(SW_SHOW);
    }

    MoveWindow(rtDlg);
}

void CReadLogsDlg::OnAdvanced() 
{
    CString csTemp;

	// TODO: Add your control notification handler code here

    if( !m_bAdvancedWindow )
    {
        SetDialogSize( TRUE );
        m_bAdvancedWindow = TRUE;

        csTemp.LoadString( IDS_READLOGS_ADVOPEN );
        m_ctrlAdvancedBtn.SetWindowText( csTemp );
    }
    else
    {
        SetDialogSize(FALSE);
        m_bAdvancedWindow = FALSE;

        csTemp.LoadString( IDS_READLOGS_ADVCLOSE );
        m_ctrlAdvancedBtn.SetWindowText( csTemp );
    }
}

CReadLogsDlg::~CReadLogsDlg()
{
    POSITION pos = NULL; 
    CString key;
    CString* pVal = NULL;

    ASSERT( m_pLogFile == NULL );

}

void CReadLogsDlg::ParseAndInitHangView()
{
    //Show the controls for this view
    //Hide the controls for this view

    //Build map of critical sections
    BuildCriticalSectionsMap();

    //Build map of thread ID's
    BuildThreadIDMap();

    //Set the file cursor to the beginning of the logfile
    ProcessKvThreadBlocks();
}

//
// a-mando
//
void CReadLogsDlg::ShowAppropriateControls()
{
    //Enable the controls based on what view is selected
    switch ( m_eReadLogType ) {
    case ReadLogsType_None:
    case ReadLogsType_Exception:
        m_ctlStaticExcepInfo.ShowWindow(SW_SHOW);
        m_staticHangInfo.ShowWindow(SW_HIDE);
	    m_ctlStaticFailingInstruction.ShowWindow(SW_SHOW);
	    m_ctlStaticExceptionLocation.ShowWindow(SW_SHOW);
	    m_ctlStaticExceptionType.ShowWindow(SW_SHOW);
	    m_ctlStaticCallStack.ShowWindow(SW_SHOW);
	    m_ctlEditFailingInstruction.ShowWindow(SW_SHOW);
	    m_ctlEditExceptionType.ShowWindow(SW_SHOW);
	    m_ctlEditExceptionLocation.ShowWindow(SW_SHOW);
	    m_ctlListControl.ShowWindow(SW_SHOW);
        break;
    case ReadLogsType_Hang:
        m_staticHangInfo.ShowWindow(SW_SHOW);
        //Disable all the controls except for the m_ctlHangListControl
        break;
    }
}
// a-mando

void CReadLogsDlg::ParseAndInitNoneView()
{
    //Show the controls for this view
    //Hide the controls for this view

}

void CReadLogsDlg::ParseAndInitExceptionView()
{
    char    szBuffer[MAX_TEMP_BUFFER_SIZE]      = {0};
    TCHAR   szTmpBuffer[MAX_TEMP_BUFFER_SIZE]   = {0};
    char*   pszOffset                           = NULL;
    long    lLastLineOffset                     = 0L;
    char    szException[MAX_TEMP_BUFFER_SIZE]   = {0};
    BOOL    bFound                              = FALSE;

    //Show the controls for this view
    //Hide the controls for this view

    do {
        //Set the file cursor to the beginning of the logfile
        fseek( m_pLogFile, 0, SEEK_SET );

        do {

            //Search through each line looking for the "(first chance)" text
            pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
            if ( pszOffset == NULL ) break;

            pszOffset = strstr( szBuffer, gslFirstChance );
            if ( pszOffset == 0 ) continue;

            //Get the current byte offset.  Note this is the next line, not the first chance line
            lLastLineOffset = ftell( m_pLogFile );
            if ( lLastLineOffset == -1L ) break;

            //Store off the line just matched
            strcpy( szException, szBuffer );
        
            bFound = TRUE;

        } while ( TRUE );

        if ( !bFound ) break;

        //Parse the szException for the readable exception text
        //Get the position of the word "code", and then only get the string up to that point
        pszOffset = strstr( szException, gslCode );

	if ( pszOffset != NULL ) //a-kjaw, bug ID: 296028
            *pszOffset = '\0'; 

        //Store off szException to the dialog control
        m_strExceptionType = szException;

        bFound = FALSE;     //Reset

        //Handle ~KV
        //Set the file pointer back to the last exception position or break if there is a problem
        do {
            if ( fseek( m_pLogFile, lLastLineOffset, SEEK_SET ) ) break;

            do {

                //Search through each line looking for the "> kv" text
                pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszOffset == NULL ) break;

                pszOffset = strstr( szBuffer, gslKV );
                if ( pszOffset == 0 ) continue;

                bFound = TRUE;

                break;

            } while ( TRUE );
        
            if ( !bFound ) break;

            bFound = FALSE;     //Reset

            do {

                //Search through each line looking for the "ChildEBP" text
                pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszOffset == NULL ) break;

                pszOffset = strstr( szBuffer, gslChildEBP );
                if ( pszOffset == 0 ) continue;

                bFound = TRUE;

                break;

            } while ( TRUE );

            if ( !bFound ) break;
        
            bFound = FALSE;     //Reset

            do {

                //Search through each line getting the call stack strings and 
                //populating the list control with them
                pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszOffset == NULL ) break;

                pszOffset = strstr( szBuffer, gslPrompt );
                if ( pszOffset != 0 ) break;

                pszOffset = strstr( szBuffer, gslCarriageReturn );
                *pszOffset = 0;

                //Get the string from offset 45 on and insert into list control
                mbstowcs( szTmpBuffer, szBuffer + sizeof( char[45] ), MAX_TEMP_BUFFER_SIZE );
                
                m_ctlListControl.AddString( szTmpBuffer );

            } while ( TRUE );

        } while ( FALSE );
        
        //Handle u eip
        do {

            if ( fseek( m_pLogFile, lLastLineOffset, SEEK_SET ) ) break;

            do {

                //Search through each line looking for the "> u eip" text
                pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszOffset == NULL ) break;

                pszOffset = strstr( szBuffer, gslUEIP );
                if ( pszOffset == 0 ) continue;

                bFound = TRUE;

                break;

            } while ( TRUE );
        
            if ( !bFound ) break;

            bFound = FALSE;     //Reset

            //Get the first item in the list control
            m_ctlListControl.GetText( 0, m_strExceptionLocation );

            do {

                //Get the immediate next line and stuff it into the failing instruction 
                pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszOffset == NULL ) break;

                //If the line has a semicolon, skip it. 
                pszOffset = strstr( szBuffer, gslSemiColon );
                if ( pszOffset != NULL ) {
                    pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                }

                pszOffset = strstr( szBuffer, gslCarriageReturn );
                *pszOffset = 0;

                m_strFailingInstruction = szBuffer + sizeof( char[26] );
                
                bFound = TRUE;

                break;

            } while ( TRUE );

        } while ( FALSE );

    } while ( FALSE );

    if ( !bFound ) {

        //We didn't find an exception, error to the user
    }
}

void CReadLogsDlg::OnDestroy() 
{
	CDialog::OnDestroy();
	
	// TODO: Add your message handler code here
	//Release the handle to the file
    if ( m_pLogFile ) {

        fclose( m_pLogFile );
        m_pLogFile = NULL;
        DeleteFile( m_pTempLogFileName );
    }
}


void CReadLogsDlg::BuildCriticalSectionsMap()
{
    BOOL    bFound                              = FALSE;
    char    *pszOffset                          = NULL;
    char    *pszTempOffset                      = NULL;
    char    szBuffer[MAX_TEMP_BUFFER_SIZE]      = {0};
    CString csAddress;
    CString *pcsOwningThread    = NULL;
    
    do {
        //Set the file cursor to the beginning of the logfile
        fseek( m_pLogFile, 0, SEEK_SET );

        do {

            //Search through each line looking for the "!Locks" command
            pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
            if ( pszOffset == NULL ) break;

            pszOffset = strstr( szBuffer, gslBangLocks );
            if ( pszOffset == NULL ) continue;

            bFound = TRUE;
            break;
        } while ( TRUE );

        if ( !bFound ) break;
        bFound = FALSE;

        //We're now at the !Locks area of the log file
        do {

            //We are now poised to extract the critical section address and the internal thread ID
            do {

                //Search through the block looking for the "CritSec" text or the "> " prompt
                pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszOffset == NULL ) break;

                pszOffset = strstr( szBuffer, gslCritSecText );

                //If "CritSec" is not in the string, look for the prompt
                if ( pszOffset == NULL ) {
                
                    pszOffset = strstr( szBuffer, gslPrompt );
                
                    //If the prompt is not in the string, continue
                    if ( pszOffset == NULL ) {
                        continue;
                    }
                    else break;
                }

                pszOffset = strstr( szBuffer, gslCarriageReturn );
		if( pszOffset != NULL ) // a-mando, bug ID: 296029
                    *pszOffset = '\0';

                //We have a "CritSec", get the address from the right most edge
                pszOffset = strrchr( szBuffer, gslSpace );
                if ( pszOffset == NULL ) break;

                csAddress = pszOffset + 1;

                csAddress.MakeLower();

                bFound = TRUE;
                break;
            } while ( TRUE );

            if ( !bFound ) break;
            bFound = FALSE;
        
            do {

                //Search through the block looking for the "OwningThread" text or the "> " prompt
                pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszOffset == NULL ) break;

                pszOffset = strstr( szBuffer, gslOwningThread );

                //If "OwningThread" is not in the string, look for the prompt
                if ( pszOffset == NULL ) {
                
                    pszOffset = strstr( szBuffer, gslPrompt );
                
                    //If the prompt is not in the string, continue
                    if ( pszOffset == NULL ) {
                        continue;
                    }
                    else break;
                }

                //We have an "OwningThread", get the internal thread ID from the right most edge
                pszOffset = strrchr( szBuffer, gslSpace );
                if ( pszOffset == NULL ) break;

                pszTempOffset = strstr( pszOffset, gslCarriageReturn );
                if ( pszTempOffset != NULL ) *pszTempOffset = '\0';

                CString pcsOwningThread = pszOffset + 1 ;

                //Add the address and owning thread to the critical section map
                m_mapCriticalSection.SetAt( csAddress, (CString&) pcsOwningThread );

                bFound = TRUE;
                break;
            } while ( TRUE );

            if ( !bFound ) break;
            bFound = FALSE;
        
        } while ( TRUE );

        if ( !bFound ) break;
        bFound = FALSE;

    } while ( FALSE );
}

void CReadLogsDlg::BuildThreadIDMap()
{
    BOOL    bFound                              = FALSE;
    char    *pszStartOffset                     = NULL;
    char    *pszEndOffset                       = NULL;
    char    szBuffer[MAX_TEMP_BUFFER_SIZE]      = {0};
    CString* pcsThreadVal                       = NULL;
    CString csThreadKey;

    do {
        //Set the file cursor to the beginning of the logfile
        fseek( m_pLogFile, 0, SEEK_SET );

        do {

            //Search through each line looking for the "~*kv" command
            pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
            if ( pszStartOffset == NULL ) break;

            pszStartOffset = strstr( szBuffer, gslTildaStarKV );
            if ( pszStartOffset == NULL ) continue;

            bFound = TRUE;
            break;
        } while ( TRUE );

        if ( !bFound ) break;
        bFound = FALSE;

        //We're now at the ~*kv area of the log file
        do {

            //We are now poised to extract the critical section address and the internal thread ID
            do {

                //Search through the block looking for the "id: " text or the "> " prompt
                pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszStartOffset == NULL ) break;

                pszStartOffset = strstr( szBuffer, gslIDColon );

                //If "id: " is not in the string, look for the prompt
                if ( pszStartOffset == NULL ) {
                
                    pszStartOffset = strstr( szBuffer, gslPrompt );
                
                    //If the prompt is not in the string, continue
                    if ( pszStartOffset == NULL ) {
                        continue;
                    }
                    else break;
                }

                //We have an "id: ", get the internal thread ID and ordered thread ID
                CString pcsThreadVal = GetThreadID( szBuffer );

                csThreadKey = GetThreadNumber( szBuffer );
                
                csThreadKey.MakeLower();

                m_mapThreadID.SetAt( csThreadKey, (CString&) pcsThreadVal );

                bFound = TRUE;
                break;
            } while ( TRUE );

            if ( !bFound ) break;
            bFound = FALSE;
        
        } while ( TRUE );

        if ( !bFound ) break;
        bFound = FALSE;

    }while ( FALSE );

}

char* CReadLogsDlg::GetThreadID( char* szBuffer )
{
    char    *pszStartOffset                     = NULL;
    char    *pszEndOffset                       = NULL;

    do {
        pszStartOffset = strstr( szBuffer, gslPeriod );
        if ( pszStartOffset == NULL ) break;

        if ( pszStartOffset == szBuffer ) {
            szBuffer++;
            continue;
        }

        pszStartOffset++;

        //increment 1 past the period we're sitting on.  Unless it's the first one we're encountering
        pszEndOffset = strchr( pszStartOffset, gslSpace );
        if ( pszEndOffset == NULL ) break;
        *pszEndOffset = '\0';

        break;
    } while ( TRUE );

    return pszStartOffset;
}

char* CReadLogsDlg::GetThreadNumber( char* szBuffer )
{
    char    *pszStartOffset                     = NULL;
    char    *pszEndOffset                       = NULL;

    //Look for the first occurance of a numeric number
    pszStartOffset = szBuffer;
    for ( ; (!isdigit( *pszStartOffset ) || *pszStartOffset == '.') && *pszStartOffset != '\0';  ) {
        pszStartOffset++;
    }
    pszEndOffset = strchr( pszStartOffset, gslSpace );
    *pszEndOffset = '\0';

    return pszStartOffset;
}

void CReadLogsDlg::GetFirstParameter( char* szBuffer, CString &str ) 
{
    char* token = NULL;

    //Tokenize the buffer and get the 3rd token and set to str
    token =  strtok( szBuffer, &gslSpace );

   for ( int i = 1; i < 3 && token != NULL; i++)
   {
      /* Get next token: */
      token = strtok( NULL, &gslSpace );
   }

   str = token;
}

void CReadLogsDlg::GetSecondParameter( char* szBuffer, CString &str ) 
{
    char* token = NULL;

    //Tokenize the buffer and get the 3rd token and set to str
    token =  strtok( szBuffer, &gslSpace );

   for ( int i = 1; i < 4 && token != NULL; i++)
   {
      /* Get next token: */
      token = strtok( NULL, &gslSpace );
   }

   str = token;
}

void CReadLogsDlg::GetThirdParameter( char* szBuffer, CString &str ) 
{
    char* token = NULL;

    //Tokenize the buffer and get the 3rd token and set to str
    token =  strtok( szBuffer, &gslSpace );

   for ( int i = 1; i < 5 && token != NULL; i++)
   {
      /* Get next token: */
      token = strtok( NULL, &gslSpace );
   }

   str = token;
}

void CReadLogsDlg::ProcessKvThreadBlocks()
{
    BOOL    bFound                              = FALSE;
    char    *pszStartOffset                     = NULL;
    char    *pszEndOffset                       = NULL;
    char    szBuffer[MAX_TEMP_BUFFER_SIZE]      = {0};
    char    szOriginalBuffer[MAX_TEMP_BUFFER_SIZE]      = {0};
    CString csThreadID;
    CString csThreadNumber;
    CString csOutput;
    CString csFirstParameter;
    CString csSecondParameter;
    CString csThirdParameter;
    CString csOwningThread;

    do {
        //Set the file cursor to the beginning of the logfile
        fseek( m_pLogFile, 0, SEEK_SET );

        do {

            //Search through each line looking for the "~*kv" command
            pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
            if ( pszStartOffset == NULL ) break;
            
            pszStartOffset = strstr( szBuffer, gslTildaStarKV );
            if ( pszStartOffset == NULL ) continue;

            bFound = TRUE;
            break;
        } while ( TRUE );

        if ( !bFound ) break;
        bFound = FALSE;

        //We're now at the ~*kv area of the log file
        do {

            //We are now poised to handle determining output string for thread states
            do {
                
                //Search through the block looking for the "id: " text or the "> " prompt
                pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszStartOffset == NULL ) break;

                //Let's keep a copy of the original around
                strcpy( szOriginalBuffer, szBuffer );

                pszStartOffset = strstr( szBuffer, gslIDColon );

                //If "id: " is not in the string, look for the prompt
                if ( pszStartOffset == NULL ) {
                
                    pszStartOffset = strstr( szBuffer, gslPrompt );
                
                    //If the prompt is not in the string, continue
                    if ( pszStartOffset == NULL ) {
                        continue;
                    }
                    else break;
                }

                csThreadNumber = GetThreadNumber( szBuffer );
                strcpy( szBuffer, szOriginalBuffer );

                csThreadID = GetThreadID( szBuffer );
                strcpy( szBuffer, szOriginalBuffer );

                //Search through the block looking for the "ChildEBP" text or the "> " prompt
                pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszStartOffset == NULL ) break;

                //Let's keep a copy of the original around
                strcpy( szOriginalBuffer, szBuffer );

                pszStartOffset = strstr( szBuffer, gslChildEBP );

                //If "ChildEBP" is not in the string, look for the prompt
                if ( pszStartOffset == NULL ) {
                
                    pszStartOffset = strstr( szBuffer, gslPrompt );
                
                    //If the prompt is not in the string, continue
                    if ( pszStartOffset == NULL ) {
                        continue;
                    }
                    else break;
                }

                //We have found the "ChildEBP", so skip it! hahahahaa (what a waste)
                pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                if ( pszStartOffset == NULL ) break;

                //Let's keep a copy of the original around
                strcpy( szOriginalBuffer, szBuffer );

                if ( strstr( szBuffer, gslWaitForSingleObject ) ) {
                    //Get the next line and look for WaitForCriticalSection
                    pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
                    if ( pszStartOffset == NULL ) break;

                    //Let's keep a copy of the original around
                    strcpy( szOriginalBuffer, szBuffer );

                    pszStartOffset = strstr( szBuffer, gslWaitForCriticalSection );

                    //If "WaitForCriticalSection" is not in the string, look for the prompt
                    if ( pszStartOffset == NULL ) {
                
                        pszStartOffset = strstr( szBuffer, gslPrompt );
                
                        //If the prompt is not in the string, continue
                        if ( pszStartOffset == NULL ) {
                            GetFirstParameter( szBuffer, csFirstParameter );
                            strcpy( szBuffer, szOriginalBuffer );
                            csOutput.Format( _T("Thread %s is in a WaitForSingleObject() call on object %s"), csThreadNumber, csFirstParameter );
                            bFound = TRUE;
                            break;
                        }
                        else break;
                    }

                    //"WaitForCriticalSection" is in the string, 
                    //Get the 5th token (3rd parameter) and look it up in the critical section map
                    GetThirdParameter( szBuffer, csThirdParameter );
                    strcpy( szBuffer, szOriginalBuffer );
                    csThirdParameter.MakeLower();
                    BOOL bFoundInMap = m_mapCriticalSection.Lookup( csThirdParameter, (CString&) csOwningThread );

                    //If not found in map,
                    if ( !bFoundInMap ) { 
                        csOutput.Format( _T("Thread %s id: %s is in WaitForCriticalSection() call on object %s"), csThreadNumber, csThreadID, csThirdParameter );
                        bFound = TRUE;
                        break;
                    }
                    else {
                        csOutput.Format( _T("Thread %s id: %s is in WaitForCriticalSection() call on object %s.  Thread %s is the owning thread."), csThreadNumber, csThreadID, csThirdParameter, csOwningThread);
                        bFound = TRUE;
                        break;
                    }

                }
                else if ( strstr( szBuffer, gslWaitForMultipleObjects ) ) {
                    GetFirstParameter( szBuffer, csFirstParameter );
                    strcpy( szBuffer, szOriginalBuffer );
                    GetSecondParameter( szBuffer, csSecondParameter );
                    strcpy( szBuffer, szOriginalBuffer );
    
                    csOutput.Format( _T("Thread %s id: %s is in a WaitForMultipleObjects() call on %s objects at address %s"), csThreadNumber, csThreadID, csFirstParameter, csSecondParameter );
                    bFound = TRUE;
                    break;
                }
                else {
                    csOutput.Format( _T("Thread %s is not in a known wait state"), csThreadNumber );
                    bFound = TRUE;
                    break;
                }

                if ( !bFound ) break;
                bFound = FALSE;

            } while ( TRUE );

            if ( !bFound ) break;
            bFound = FALSE;
            
            //Output the text to the list control
            m_ctlListControl.AddString( csOutput );

        } while ( TRUE );

        if ( !bFound ) break;
        bFound = FALSE;

    } while ( TRUE );
}

//
// a-mando
//
void CReadLogsDlg::ResizeAndReposControl()
{
    CRect   rtListCtrl,
            rtHangInfo,
            rtDlg;
    
    GetWindowRect( &rtDlg );
    m_staticHangInfo.GetWindowRect( &rtHangInfo );
    m_ctlListControl.GetWindowRect( &rtListCtrl );
    ScreenToClient( &rtDlg );
    ScreenToClient( &rtHangInfo );
    ScreenToClient( &rtListCtrl );

    switch ( m_eReadLogType ) {

    case ReadLogsType_Exception:
        break;

    case ReadLogsType_Hang:
        m_staticHangInfo.ShowWindow(SW_SHOW);
        rtListCtrl.left = rtDlg.left + DLG_PIXEL_EXTEND_SIZE;
        rtListCtrl.top = rtHangInfo.bottom + DLG_PIXEL_EXTEND_SIZE;
        m_ctlListControl.MoveWindow(&rtListCtrl);
	    m_ctlListControl.ShowWindow(SW_SHOW);
        break;

    case ReadLogsType_None:
        //Disable all the controls
        break;
    }

}
// a-mando