#include "StdAfx.h"
#include ".\dumpfileparser.h"
#include ".\resource.h"
#include ".\DumpStatisticsDlg.h"

struct CompareVectorfVersion
{
	bool operator () (const CDumpLog* lhs, const CDumpLog* rhs) const
	{
		int cnt = 0;
		if( lhs->fVersion == rhs->fVersion )
		{
			if( (cnt = strcmp( lhs->szFileName, rhs->szFileName ) ) == 0 )
			{
				return (strcmp( lhs->szFaultAddress, rhs->szFaultAddress ) < 0 );
			}
			else
				return ( cnt < 0);
		}
		return lhs->fVersion < rhs->fVersion;
	}
};


struct CompareVectorFaultAddress
{
	bool operator () (const LPFAULTLIST lhs, const LPFAULTLIST rhs) const
	{
		if( lhs->dwVersion == rhs->dwVersion )
		{
			return (strcmp( lhs->szFileName, rhs->szFileName ) < 0 );
		}
		return lhs->dwVersion < rhs->dwVersion ;
		
	}
};


CDumpFileParser::CDumpFileParser( CDumpStatisticsDlg* pDlg )
{
	m_pDlg = pDlg ;
	CWnd* pWnd = m_pDlg->GetDlgItem( IDC_DUMPFILE ) ;
	pWnd->SetWindowText( "                                                                                          " ) ;
	m_pDlg->UpdateData() ;
	m_pDlg->UpdateData( FALSE ) ;
	m_uiDumpSize = 0 ;
}

CDumpFileParser::~CDumpFileParser(void)
{
	std::vector< LPDUMPDIRECTORYINFO >::iterator	iterVer = m_vecDumpDirectoryInfo.begin() ;
	while( iterVer != m_vecDumpDirectoryInfo.end() )
	{
		LPDUMPDIRECTORYINFO lpDumpDirectoryInfo = ( *iterVer ) ;
		std::vector< LPFILENAME >::iterator iterFile = lpDumpDirectoryInfo->vecDumpFileInfo.begin() ;		// Vector Date Direcoty 
		while( iterFile != lpDumpDirectoryInfo->vecDumpFileInfo.end() )
		{
			if( (*iterFile ) )
			{
				delete ( *iterFile );
				( *iterFile ) = NULL;
			}
			iterFile++;
		}
		lpDumpDirectoryInfo->vecDumpFileInfo.clear() ;

		if ( ( *iterVer ) )
		{
			delete ( *iterVer ) ;
			( *iterVer ) = NULL ;
		}
		++ iterVer ;
	}
	m_vecDumpDirectoryInfo.clear() ;
}


//----------------------------------------------------------------------------
// 하위 디렉토리를 전부 검색하여	파일을 덤프 파일 목록과 디렉토리 목록을 만든다.
//----------------------------------------------------------------------------
VOID	
CDumpFileParser::FindDumpDirectory() 
{
	m_uiDumpSize = 0;
	FindDumpDirectory( m_szCurrentDirectory );
	CWnd* pProgressWnd = m_pDlg->GetDlgItem( IDC_DUMPPROGRESS ) ;
	pProgressWnd->SendMessage( PBM_SETRANGE, 0, MAKELPARAM( 0,m_uiDumpSize ) ) ;
	pProgressWnd->SendMessage( PBM_SETPOS, 0, 0 ) ;				

}


//----------------------------------------------------------------------------
// 해당 디렉토리에서의 파일 찾기
//----------------------------------------------------------------------------
VOID	
CDumpFileParser::FindDumpFile( LPDUMPDIRECTORYINFO pDirectoryInfo )
{
	HANDLE			hSrch ;
	WIN32_FIND_DATA	wfd ;
	BOOL			bResult = TRUE ;
	CHAR			szDirectory[ MAX_PATH ] ;
	CHAR			szTempDirectory[ MAX_PATH ] ;
	UINT			uiDirectoryNum = 0 ;

	strcpy( szDirectory, pDirectoryInfo->szDirectory ) ;
	strcpy( szTempDirectory, pDirectoryInfo->szDirectory ) ;
	strcat( szDirectory, "\\*.txt" ) ;
	hSrch = FindFirstFile( szDirectory, &wfd ) ;

	if ( hSrch == INVALID_HANDLE_VALUE )
	{
		return ;
	}
	
	while( bResult )
	{
		if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
		{
			if ( !strcmp( wfd.cFileName, "." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}

			if ( !strcmp( wfd.cFileName, ".." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}
		}	
		else
		{
			wsprintf( szTempDirectory, "%s\\%s", pDirectoryInfo->szDirectory, wfd.cFileName ) ;
			LPFILENAME	lpFileName ; 
			lpFileName = new FILENAME ;
			strcpy( lpFileName->szFileName, szTempDirectory ) ;
			pDirectoryInfo->vecDumpFileInfo.push_back( lpFileName ) ;
			m_uiDumpSize += 1;
		}
		bResult = FindNextFile( hSrch, &wfd ) ;
	}
}


//----------------------------------------------------------------------------
// 하위 디렉토리를 전부 검색하여	파일을 덤프 파일 목록과 디렉토리 목록을 만든다.
//----------------------------------------------------------------------------
VOID	
CDumpFileParser::FindDumpDirectory( const char* path )
{
	HANDLE			hSrch ;
	WIN32_FIND_DATA	wfd ;
	BOOL			bResult = TRUE ;
	CHAR			szDirectory[ MAX_PATH ] ;
	CHAR			szTempDirectory[ MAX_PATH ] ;
	
	strcpy( szDirectory, path ) ;
	strcpy( szTempDirectory, path ) ;
	strcat( szDirectory, "\\*.*" ) ;
	hSrch = FindFirstFile( szDirectory, &wfd ) ;

	if ( hSrch == INVALID_HANDLE_VALUE )
	{
		return ;
	}
	
	while( bResult )
	{
		if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
		{
			if ( !strcmp( wfd.cFileName, "." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}

			if ( !strcmp( wfd.cFileName, ".." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}
			
			if ( !strcmp( wfd.cFileName, "sort") )			//sort 디렉토리는 패스
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue;
			}
			
			LPDUMPDIRECTORYINFO	pDumpDirectory ;
			pDumpDirectory = new DUMPDIRECTORYINFO ;
			wsprintf( szTempDirectory, "%s\\%s", path, wfd.cFileName ) ;
			strcpy( pDumpDirectory->szDirectory, szTempDirectory ) ;
			FindDumpFile( pDumpDirectory );
			m_vecDumpDirectoryInfo.push_back( pDumpDirectory );

			FindDumpDirectory( szTempDirectory );
			
		}	
		bResult = FindNextFile( hSrch, &wfd ) ;
	}
	FindClose( hSrch ) ;
}

/*
//-----------------------------------------------------------------
// Date디렉토리를 찾는다.
//-----------------------------------------------------------------
UINT	CDumpFileParser::FindDumpDateDirectory( LPDUMPDIRECTORYINFO lpDumpInfo ) 
{
	HANDLE			hSrch ;
	WIN32_FIND_DATA	wfd ;
	BOOL			bResult = TRUE ;
	CHAR			szDirectory[ MAX_PATH ] ;
	CHAR			szTempDirectory[ MAX_PATH ] ;
	UINT			uiDirectoryNum = 0 ;

	strcpy( szDirectory, lpDumpInfo->szVerDirectory ) ;
	strcpy( szTempDirectory, lpDumpInfo->szVerDirectory ) ;
	strcat( szDirectory, "\\*.*" ) ;
	hSrch = FindFirstFile( szDirectory, &wfd ) ;

	if ( hSrch == INVALID_HANDLE_VALUE )
	{
		return 0 ;
	}
	
	while( bResult )
	{
		if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
		{
			if ( !strcmp( wfd.cFileName, "." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}

			if ( !strcmp( wfd.cFileName, ".." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}
			wsprintf( szTempDirectory, "%s\\%s", lpDumpInfo, wfd.cFileName ) ;
			LPDUMPFILEINFO lpTmpDumpFileInfo ;
			lpTmpDumpFileInfo = new DUMPFILEINFO ;
			strcpy( lpTmpDumpFileInfo->szDateDirectory, szTempDirectory ) ;
			lpDumpInfo->vecDumpFileInfo.push_back( lpTmpDumpFileInfo ) ;
			lpTmpDumpFileInfo->uiDirectoryNum = FindDumpFile( lpTmpDumpFileInfo ) ;
			m_uiDumpSize += lpTmpDumpFileInfo->uiDirectoryNum ;
			++ uiDirectoryNum ;
		}	
		bResult = FindNextFile( hSrch, &wfd ) ;
	}

	CWnd* pProgressWnd = m_pDlg->GetDlgItem( IDC_DUMPPROGRESS ) ;
	pProgressWnd->SendMessage( PBM_SETRANGE, 0, MAKELPARAM( 0,m_uiDumpSize ) ) ;
	pProgressWnd->SendMessage( PBM_SETPOS, 0, 0 ) ;				

	return uiDirectoryNum ;
}

//-----------------------------------------------------------------
// Date디렉토리 안의 모든 파일들을 찾는다.
//-----------------------------------------------------------------
UINT	CDumpFileParser::FindDumpFile( LPDUMPFILEINFO lpDumpFileInfo ) 
{
	HANDLE			hSrch ;
	WIN32_FIND_DATA	wfd ;
	BOOL			bResult = TRUE ;
	CHAR			szDirectory[ MAX_PATH ] ;
	CHAR			szTempDirectory[ MAX_PATH ] ;
	UINT			uiDirectoryNum = 0 ;

	strcpy( szDirectory, lpDumpFileInfo->szDateDirectory ) ;
	strcpy( szTempDirectory, lpDumpFileInfo->szDateDirectory ) ;
	strcat( szDirectory, "\\*.txt" ) ;
	hSrch = FindFirstFile( szDirectory, &wfd ) ;

	if ( hSrch == INVALID_HANDLE_VALUE )
	{
		return 0 ;
	}
	
	while( bResult )
	{
		if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
		{
			if ( !strcmp( wfd.cFileName, "." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}

			if ( !strcmp( wfd.cFileName, ".." ) )
			{
				bResult = FindNextFile( hSrch, &wfd ) ;
				continue ;
			}
		}	
		else
		{
			wsprintf( szTempDirectory, "%s\\%s", lpDumpFileInfo->szDateDirectory, wfd.cFileName ) ;
			LPFILENAME	lpFileName ; 
			lpFileName = new FILENAME ;
			strcpy( lpFileName->szFileName, szTempDirectory ) ;
			lpDumpFileInfo->vecFileName.push_back( lpFileName ) ;
			++ uiDirectoryNum ;
		}
		bResult = FindNextFile( hSrch, &wfd ) ;
	}

	return uiDirectoryNum ;
}
*/

//-----------------------------------------------------------------------------------------------
VOID	CDumpFileParser::LoadDumpFile() 
{
	HRESULT hr = S_OK ;
	FILE*	pStream = NULL ;
	char	strRead[MAX_PATH] ;
	char	tempDirectory[MAX_PATH] ;
	int     Count = 0 ;

	::GetCurrentDirectory( MAX_PATH, tempDirectory );
	CProgressCtrl* pProgressWnd = (CProgressCtrl*)(m_pDlg->GetDlgItem( IDC_DUMPPROGRESS ) );
	CWnd* pWnd = m_pDlg->GetDlgItem( IDC_DUMPFILE ) ;


	LPDUMPMETADATA lpMetaData ;
	lpMetaData = new DUMPMETADATA ;

	std::vector< LPDUMPDIRECTORYINFO >::iterator	iterVer = m_vecDumpDirectoryInfo.begin() ;
	while( iterVer != m_vecDumpDirectoryInfo.end() )
	{
		LPDUMPDIRECTORYINFO lpDumpDirectoryInfo = ( *iterVer ) ;
		if( ::SetCurrentDirectory( lpDumpDirectoryInfo->szDirectory ) )
		{
			std::vector< LPFILENAME >::iterator iterData = lpDumpDirectoryInfo->vecDumpFileInfo.begin();
			while( iterData != lpDumpDirectoryInfo->vecDumpFileInfo.end() )
			{
				LPFILENAME lpFileName = ( *iterData ) ;

				static CHAR szTemp[ MAX_PATH ] ;
				sprintf( szTemp, "%s\n", lpFileName ) ;

				OutputDebugString( szTemp ) ;


				pWnd->SetWindowText( szTemp ) ;
				pProgressWnd->SetPos( Count );

				if ( ( pStream = fopen( lpFileName->szFileName, "rt" ) ) == NULL )
				{
					continue ;
				}
				
				lpMetaData->ClearData();

				strcpy( lpMetaData->szFileName, lpFileName->szFileName );
				while(fgets(strRead, MAX_PATH - 1, pStream))
				{
					strRead[MAX_PATH - 1] = 0;
					if ( FAILED( CheckLine( strRead, lpMetaData ) ) )
					{
						CheckMoreDump( pStream, lpMetaData );
						break ;
					}
				}
				if( CopyFileExt( lpMetaData, lpFileName->szFileName ) )
				{
					m_DumpReport.PushFaultLog ( lpMetaData );
				}
				fclose( pStream );

				Count++ ;
				iterData++;
			}

		}
		iterVer++;
	}

	delete lpMetaData;
	pProgressWnd->SetPos( Count ) ;
	pWnd->SetWindowText( "리포트 파일 생성중" ) ;
	::SetCurrentDirectory( tempDirectory );
	

	m_DumpReport.Write2File( "report.txt" );
	pWnd->SetWindowText( "End" ) ;
	pProgressWnd->SetPos( 0 ) ;
}


HRESULT		CDumpFileParser::CheckLine( CHAR* strLine, LPDUMPMETADATA lpMetaData ) 
{
	CHAR		seps[] = " ,\t\n[];" ;
	CHAR		*token, strCommand[ MAX_PATH ], strName[ MAX_PATH ] ;
	CHAR		strTemp[ 256 ];
	strncpy( strTemp, strLine, 256);

	token = strtok( strLine, seps ) ;
	if ( token )
	{
		strcpy( strCommand, token ) ;
		token = strlwr( strCommand ) ;

		// 서버 이름
		if (!strcmp(token, "server"))
		{
			BOOL bExcept = FALSE;

			token = strtok(NULL, seps);
			if (token)
			{
				strncpy( strName, token, sizeof(CHAR)*32 ) ;
				token = strtok( NULL, seps ) ;
				if ( token )
				{
					if (!strcmp(token, "Test"))
					{
						strncpy( lpMetaData->szServerName, "Test Server Version", sizeof(CHAR)*32) ;
					}
				} 
				else 
					return E_FAIL;
			} 
			else 
				return E_FAIL;
			return S_OK;
		}

		// 클라이언트 버전
		if (!strcmp(token, "client"))
		{
			BOOL bExcept = FALSE;

			token = strtok(NULL, seps);
			if (token)
			{
				token = strtok( NULL, seps ) ;
				token = strtok( NULL, seps ) ;
				if ( token )
				{
					lpMetaData->fVersion = atof( token ) ;
					if( lpMetaData->fVersion > 0 )
						strncpy( lpMetaData->szVersion , token, sizeof(CHAR)*8 );
					else
					{
						strcpy( lpMetaData->szVersion , "0.00" );
						lpMetaData->fVersion = 0;
					}

					
				} 
				else 
					return E_FAIL;
			} 
			else 
				return E_FAIL;

			return S_OK;
		}

		// exception address
		if (!strcmp(token, "exception"))
		{
			BOOL bExcept = FALSE;

			token = strtok(NULL, seps);
			if (token)
			{
				token = strtok( NULL, seps ) ;
				if ( token )
				{
					memcpy( lpMetaData->byException, token, 8 ) ;
					lpMetaData->byException[ 8 ] = 0;
				} 
				else 
					return E_FAIL;
			} 
			else 
				return E_FAIL;
			return S_OK;
		}

		// Fault address
		if (!strcmp(token, "fault"))
		{
			BOOL bExcept = FALSE;

			token = strtok(NULL, seps);
			if (token)
			{
				token = strtok( NULL, seps ) ;
				
				if ( token )
				{
					memcpy( lpMetaData->byFaultAddress[ lpMetaData->nFaultCnt ], token, 8 ) ;
					lpMetaData->byFaultAddress[ lpMetaData->nFaultCnt ][ 8 ] = 0;
					lpMetaData->nFaultCnt += 1;
					return E_FAIL;
				} 
				else 
					return E_FAIL;
			} 
			else 
				return E_FAIL;
			return S_OK;
		}

		//AvailableVirtualMemory 
		if(!strcmp(token, "availablevirtualmemory"))
		{
			token = strtok(NULL, seps);
			if (token)
			{
				token = strtok( NULL, seps ) ;
				if ( token )
				{
					strncpy( lpMetaData->szAvailabelVirtualMemory , token, sizeof(CHAR)*15 );
				} 
			}
			return S_OK;
		}

		if(!strcmp(token, "totalphysicalmemory") )
		{
			
			token = strtok(NULL, seps);
			if (token)
			{
				token = strtok( NULL, seps ) ;
				if ( token )
				{
					strncpy( lpMetaData->szTotalPhysicalMemory , token, sizeof(CHAR)*15 );
				} 
			}
			return S_OK;
		}

		if(!strcmp(token, "adapterram") )
		{
			token = strtok(NULL, seps);
			if (token)
			{
				token = strtok( NULL, seps ) ;
				if ( token )
				{
					strncpy( lpMetaData->szAdapterRAM , token, sizeof(CHAR)*15 );
				} 
			}
			return S_OK;
		}

		if(!strcmp(token, "videoprocessor") )
		{
			int lenLeft ;
			int lenPrev ;
			lenPrev =  strlen( strLine );
			lenLeft = strlen( strTemp ) - lenPrev;
			if( lenLeft > 7 )
			{
				strncpy(  lpMetaData->szVideoProcessor, &strTemp[lenPrev+4], sizeof(CHAR)*(lenLeft-4-3) );
				lpMetaData->szVideoProcessor[ lenLeft-4-3 ] = 0 ;
			}
			return S_OK;
		}

		//Available Memory
		if(!strcmp(token, "available") )
		{
			token = strtok(NULL, seps);
			if (token)
			{
				token = strtok( NULL, seps ) ;
				if ( token )
				{
					token = strtok(NULL, seps);
					if( token )
					{
						strncpy( lpMetaData->szAvailableMemory, token, sizeof(CHAR)*15 );
					}
				} 
			}
			return S_OK;
		}
	}

	return S_OK ;
}

HRESULT	CDumpFileParser::CheckMoreDump( FILE* pFile, LPDUMPMETADATA lpMetaData ) 
{
	CHAR strRead[MAX_PATH];
	CHAR		seps[] = " ,\t\n" ;
	CHAR		*token ;

	while(fgets(strRead, MAX_PATH - 1, pFile))
	{
		strRead[MAX_PATH - 1] = 0;
		strlwr( strRead );
		if( strstr( strRead, "address" ) )
		{
			if( strstr( strRead, "frame" ) )
			{
				while(fgets(strRead, MAX_PATH - 1, pFile))
				{
					strlwr( strRead );
					if( strstr( strRead, "client.exe" ) )
					{
						token = strtok( strRead, seps ) ;
						if ( token )
						{
							memcpy( lpMetaData->byFaultAddress[ lpMetaData->nFaultCnt ], token, 8 ) ;
							lpMetaData->nFaultCnt += 1;
							if( lpMetaData->nFaultCnt >= 50 ) //갯수 제한.
							{
								return S_OK;
							}
						}
						token = strtok(NULL, seps);
					}
				}
				return S_OK;

			}
		}
	}

	return S_OK ;
}



const char*	
// 해당 덤프하는 디렉토리를 만들고 해당 디렉토리 위치를 리턴한다.
CDumpFileParser::MakeDirectory( LPDUMPMETADATA lpMetaData, int nCnt )
{
	static CHAR	tempDirectory[ MAX_PATH ];
	CHAR	buff[ MAX_PATH ];
	CHAR	temp[ MAX_PATH ];

	if( lpMetaData->nFaultCnt > nCnt )
	{
		::GetCurrentDirectory( MAX_PATH, temp );
		if( !::SetCurrentDirectory( m_szCopyDirectory ) )
		{
			return NULL;
		}
		//sprintf( buff, "%.2f", lpMetaData->fVersion );		
		strcpy( buff, lpMetaData->szVersion );
		::CreateDirectory( buff, NULL );
		
		sprintf( tempDirectory, "%s\\%s", m_szCopyDirectory, lpMetaData->szVersion );
		if( !::SetCurrentDirectory( tempDirectory) )
		{
			::SetCurrentDirectory( temp );
			return NULL;
		}

		memset( buff, 0, sizeof( CHAR ) * MAX_PATH );
		strncpy( buff, lpMetaData->byFaultAddress[ nCnt ], sizeof( CHAR ) * 8 );
		::CreateDirectory( buff, NULL );

		if( !::SetCurrentDirectory( buff ) )
		{
			::SetCurrentDirectory( temp );
			return NULL;
		}

		::SetCurrentDirectory( temp );
		sprintf( tempDirectory, "%s\\%s\\%s", m_szCopyDirectory, lpMetaData->szVersion, buff );		// 버젼/뻗은 주소
		return tempDirectory ;
	}
	return NULL;
}

BOOL
CDumpFileParser::CopyFileExt( LPDUMPMETADATA lpMetaData, LPSTR lpszFileName )
{
	if( !lpMetaData )
		return FALSE;
	CHAR szDumpDirectory[ MAX_PATH ] ;
	CHAR szTemp[ 9 ] ;
	CHAR filename[ MAX_PATH ];

	CHAR		seps[] = "\\" ;
	CHAR		*token;
	

	const char* path;
	memcpy( szTemp, lpMetaData->byFaultAddress[0], 8 ) ;
	szTemp[ 8 ] = 0 ;

	strcpy( szDumpDirectory, lpszFileName );
	token = strtok( szDumpDirectory, seps ) ;
	while( token )
	{
		strcpy( filename, token );
		token = strtok( NULL, seps );
	}

	int i ;
	for( i = 0 ; i < lpMetaData->nFaultCnt  ; i++ )
	{
		path = MakeDirectory( lpMetaData, i );
		if( !path )
			continue;

		sprintf( szDumpDirectory, "%s\\%s", path, filename );
		if ( !CopyFile( lpszFileName, szDumpDirectory, FALSE ) )
		{
			return  FALSE;
		}

		INT iLen = strlen( lpszFileName ) ;
		lpszFileName[ iLen - 1] = 'p' ;
		lpszFileName[ iLen - 2 ] = 'm' ;
		lpszFileName[ iLen - 3 ] = 'd' ;

		iLen = strlen( filename ) ;
		filename[ iLen - 1] = 'p' ;
		filename[ iLen - 2 ] = 'm' ;
		filename[ iLen - 3 ] = 'd' ;
		
		sprintf( szDumpDirectory, "%s\\%s", path, filename );
		if ( !CopyFile( lpszFileName, szDumpDirectory, FALSE ) )
		{
			return FALSE;
		}
		iLen = strlen( lpszFileName ) ;
		lpszFileName[ iLen - 1] = 't' ;
		lpszFileName[ iLen - 2 ] = 'x' ;
		lpszFileName[ iLen - 3 ] = 't' ;

		iLen = strlen( filename ) ;
		filename[ iLen - 1] = 't' ;
		filename[ iLen - 2 ] = 'x' ;
		filename[ iLen - 3 ] = 't' ;
	}

    return TRUE;
}



BOOL 
CDumpReport::Write2File( const char* filename )
{
	FILE* pFile;
	int nCnt;
	std::vector< LPFAULTLIST >	vecHotList;
	pFile = fopen( filename, "w" );
	std::sort(vecDumpFile.begin(), vecDumpFile.end(), CompareVectorfVersion());
	std::sort(vecFaultList.begin(), vecFaultList.end(), CompareVectorFaultAddress() );
	if( pFile )
	{

		fprintf( pFile,"오류주소\t메모리(KB)\t사용가능한메모리(KB)\t비디오램(KB)\t비디오프로세서\t버젼\t파일이름\n");
		std::vector< CDumpLog* >::iterator iterFile;
		for( iterFile = vecDumpFile.begin() ; iterFile !=vecDumpFile.end() ; iterFile++ )
		{
			if( *iterFile )
			{
				(*iterFile)->Print2File( pFile );
			}

		}
		fprintf( pFile,"--------------------------------------------------------------------------------\n");
		fprintf( pFile,"\n\n\n");
		fprintf( pFile,"--------------------------------------------------------------------------------\n");



		std::vector< LPFAULTLIST >::iterator iterList;
		for( iterList = vecFaultList.begin() ; iterList !=vecFaultList.end() ; iterList++ )
		{
			nCnt = 0;
			for( iterFile = vecDumpFile.begin() ; iterFile !=vecDumpFile.end() ; iterFile++ )
			{
				if( (*iterFile)->fVersion == (*iterList)->dwVersion )
				{
					if( strcmp( (*iterFile)->szFaultAddress, (*iterList)->szFileName ) == 0 )
					{
						nCnt++;
					}
				}
			}
			if( nCnt > 0 )
			{
				fprintf( pFile,"버젼%.2f\t주소:[ %s ] \t%d개\n", (*iterList)->dwVersion, (*iterList)->szFileName, nCnt );
				if( nCnt > 20 )
					vecHotList.push_back( (*iterList) );
			}
		}
		fprintf( pFile,"--------------------------------------------------------------------------------\n");
		fprintf( pFile,"\n\n\n");
		fprintf( pFile,"------------------------Hot----List---------------------------------------------\n");
		for( iterList = vecHotList.begin() ; iterList !=vecHotList.end() ; iterList++ )
		{
			fprintf( pFile,"버젼%.2f\t주소:[ %s ] \n", (*iterList)->dwVersion, (*iterList)->szFileName );
		}
		fprintf( pFile,"\n\n----E-N-D----\n");
		fclose( pFile );

		vecHotList.clear();
		return TRUE;
	}
	return FALSE;
}

VOID 
CDumpReport::PushFaultLog( LPDUMPMETADATA lpMeta )
{
	std::vector< CDumpLog* >::iterator iterFile;
	for( int i = 0 ; i < lpMeta->nFaultCnt ; i++ )
	{
		bool	bExist = false;
		for( iterFile = vecDumpFile.begin(); iterFile != vecDumpFile.end(); iterFile++ )
		{
			if( (*iterFile)->fVersion == lpMeta->fVersion )
			{
				if( strcmp( (*iterFile)->szFileName, lpMeta->szVersion ) == 0 )
				{
					if( strcmp( (*iterFile)->szFaultAddress, lpMeta->byFaultAddress[i]) == 0 )
					{
						bExist = true;
						break;
					}
				}
			}
		}
		if( bExist )
			continue;

		CDumpLog*	pLog;
		pLog = new CDumpLog();
		pLog->fVersion = lpMeta->fVersion;						// 버전
		strcpy( pLog->szFaultAddress, lpMeta->byFaultAddress[ i ] );		// Fault Address
		strcpy( pLog->szFileName, lpMeta->szFileName ) ;		// 파일명
		strcpy( pLog->szVersion, lpMeta->szVersion ) ;			// 버전
		strcpy( pLog->szGraphicCard, lpMeta->szVideoProcessor ) ;		//그래픽 카드
		pLog->nBaseSystemMemory = 0;				//기본 시스템 메모리
		pLog->nUsedSystemMemory = 0;				//사용 시스템 메모리
		pLog->nBaseLocalMemory = atoi( lpMeta->szTotalPhysicalMemory );				//기본 Local 메모리
		pLog->nLeftMemory = atoi( lpMeta->szAvailableMemory );				//기본 Local 메모리
		pLog->nBaseAGPMemory = atoi( lpMeta->szAdapterRAM );					//기본 AGP 메모리
		pLog->nBaseAGPMemory = pLog->nBaseAGPMemory / 1024 ;
		pLog->nUsedAGPMemory = 0;					//기본 AGP 메모리
		vecDumpFile.push_back( pLog );

		std::vector< LPFAULTLIST >::iterator iterList;
		bExist = false;
		for( iterList = vecFaultList.begin() ; iterList !=vecFaultList.end() ; iterList++ )
		{
			if( (*iterList)->dwVersion == pLog->fVersion )
			{
				if( strcmp( (*iterList)->szFileName, pLog->szFaultAddress ) == 0 )
				{
					bExist = true ;
					break;
				}
			}
		}
		if( !bExist )
		{
			LPFAULTLIST pList;
			pList = new FAULTLIST;
			strcpy( pList->szFileName, pLog->szFaultAddress );
			pList->dwVersion = pLog->fVersion;
			vecFaultList.push_back( pList );
		}
	}
}

CDumpReport::~CDumpReport()
{ 
	std::vector< CDumpLog* >::iterator iterFile;
	for( iterFile = vecDumpFile.begin() ; iterFile !=vecDumpFile.end() ; iterFile++ )
	{
		if( *iterFile )
		{
			delete (*iterFile);
			(*iterFile) = NULL;
		}

	}
	vecDumpFile.clear(); 

	std::vector< LPFAULTLIST >::iterator iterList;
	for( iterList = vecFaultList.begin() ; iterList !=vecFaultList.end() ; iterList++ )
	{
		if( *iterList )
		{
			delete (*iterList);
			(*iterList) = NULL;
		}
	}
	vecFaultList.clear();

}


VOID						
CDumpLog::Print2File( FILE* pFile )
{
	if( !pFile )
		return;
	fprintf( pFile,"%s\t%d\t%d\t%d\t%s\t%s\t%s\n", szFaultAddress, nBaseLocalMemory, nLeftMemory, nBaseAGPMemory, szGraphicCard, szVersion, szFileName );
	return;
}