// ErrorReport.cpp : implementation file
//

#include "stdafx.h"
#include "ErrorMessage.h"

#include "LocalErrors.h"

#include "ErrorReport.h"

#include "InfoDlg.h"
#include "NonCritDlg.h"
#include "SevereErrDlg.h"
#include "UserErrorDlg.h"
#include "RetryErrorDlg.h"
#include "PopupWnd.h"
#include "resource.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CErrorReport

IMPLEMENT_DYNCREATE(CErrorReport, CWinThread)

//extern "C" 
PASCAL EXPORT 
CErrorReport::CErrorReport()
{
	m_csWhatHappened.Empty();
	m_csResult.Empty();
	m_csCorrectiveAction.Empty();

	m_csCaption_WhatHappened.Empty();
	m_csCaption_CorrectiveAction.Empty();
	m_csCaption_Results.Empty();
	m_csCaption_Comments.Empty();

	m_nErrorCode = 0;
	m_nVarsWhat = 0;
	m_nVarsResult = 0;
	m_nVarsAction = 0;
	m_hAppKey = NULL;
}

CErrorReport::~CErrorReport()
{
}

BOOL CErrorReport::InitInstance()
{
	// TODO:  perform and per-thread initialization here
	return TRUE;
}

int CErrorReport::ExitInstance()
{
	// TODO:  perform any per-thread cleanup here
	return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(CErrorReport, CWinThread)
	//{{AFX_MSG_MAP(CErrorReport)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CErrorReport message handlers

int PASCAL EXPORT CErrorReport::ReportError( HKEY hAppKey, ERRORMSG errMsg, UINT delay, CString csCaptions )
{
	int		retval = 0;

	m_hAppKey = hAppKey;
	m_nErrorCode = errMsg.nErrorCode;
	ParseString( errMsg.ErrorType, errMsg.csErrorString );
	if( ! csCaptions.IsEmpty() )
		ParseCaptions( csCaptions );
	m_nErrorType = errMsg.ErrorType;
	switch( m_nErrorType )
	{
		case USER_ERROR:
			retval = ReportUserError( delay );		// time-delay is optional
			break;
		case INFORMATION:
			retval = ReportInformation( delay );	// time-delay is optional
			break;
		case NON_CRITICAL:
			retval = ReportNonCritical();			// no time-delay permitted
			break;
		case SEVERE_ERROR:
			retval = ReportSevereError();			// no time-delay permitted
			break;
		case RETRY_ERROR:
			if( ! delay ) delay = 15;				// default time-delay for retry
			retval = ReportRetryError( delay );
			break;
	}
	return retval;
}

void PASCAL EXPORT CErrorReport::ReportError( ERRORMSG errMsg, UINT delay, CPoint cPoint, WORD wAlign )
{
	CPopupWnd*	pPopup = new CPopupWnd;
	pPopup->m_wAlign = wAlign;
	pPopup->m_nTimeout = delay;
	pPopup->m_csMessage = errMsg.csErrorString;
	pPopup->Create( _T("Popup"), WS_POPUP | WS_VISIBLE, cPoint, NULL );
	return;
}

void CErrorReport::ParseString( ERRORTYPE errType, CString csErrorString )
{
	int		nOfs;
	
	m_nVarsWhat = 0;
	m_nVarsResult = 0;
	m_nVarsAction = 0;

	nOfs = csErrorString.Find( (char) '|' ); 
	m_csWhatHappened.Format( "%s", csErrorString.Left( nOfs ) );
	csErrorString = csErrorString.Right( csErrorString.GetLength() - ( ++nOfs ) );

	nOfs = csErrorString.Find( (char) '|' ); 
	m_csResult.Format( "%s", csErrorString.Left( nOfs ) ); 
	csErrorString = csErrorString.Right( csErrorString.GetLength() - ( ++nOfs ) );

	m_csCorrectiveAction = csErrorString;
	if( ( errType == USER_ERROR ) &&
		( m_csCorrectiveAction.GetLength() == 0 ) &&
		( m_csResult.GetLength() > 0 ) )
	{
		m_csCorrectiveAction = m_csResult;
		m_nVarsAction = m_nVarsResult;
	}
}

void CErrorReport::LogError( CString csCommentString )
{
	m_csComments = csCommentString;
	LogError();
}

void CErrorReport::LogError()
{
	CString	csLogEntry, csErrFormat, csTime, csError;
	char	szFileName[_MAX_PATH];
	ULONG	lFileNameLen = _MAX_PATH;
	struct	tm *newtime;
	time_t	long_time;

	time( &long_time );								// Get time as long integer
	newtime = localtime( &long_time );				// Convert to local time
	csTime.Format( "%.19s", asctime( newtime ) );
	switch( m_nErrorType )
	{
		case USER_ERROR:	csErrFormat = "%s\tUSER ERROR  \t#%d:\t%s";			break;
		case INFORMATION:	csErrFormat = "%s\tINFORMATION \t#%d:\t%s";			break;
		case NON_CRITICAL:	csErrFormat = "%s\tNON_CRITICAL\t#%d:\t%s\r\n\t%s";	break;
		case SEVERE_ERROR:	csErrFormat = "%s\tSEVERE_ERROR\t#%d:\t%s\r\n\t%s";	break;
		case RETRY_ERROR:	csErrFormat = "%s\tRETRY_ERROR \t#%d:\t%s";			break;
	}
	switch( m_nErrorType )
	{
		case USER_ERROR:
		case INFORMATION:
		case RETRY_ERROR:
			csLogEntry.Format( csErrFormat, csTime, m_nErrorCode, m_csWhatHappened );
			break;
		case NON_CRITICAL:
		case SEVERE_ERROR:
			csLogEntry.Format( csErrFormat, csTime, m_nErrorCode, m_csWhatHappened, m_csComments );
			break;
	}

	if( m_hAppKey == NULL )		// no application registry key received
	{
		strcpy( szFileName, "C:\\DefaultError.LOG" );
		csError.LoadString( IDS_ERRORNOLOG );
		AfxMessageBox( csError );
	}
	else
		if( RegQueryValueEx( m_hAppKey,			// handle of key to query
							 "Error Log Name",	// name of value to query
							 0,					// reserved, must be zero
							 NULL,				// address of value type buffer
			 (unsigned char*)szFileName,		// address of buffer for path/filename
							 &lFileNameLen		// size of buffer / string size
						   ) != ERROR_SUCCESS )
		{
			strcpy( szFileName, "C:\\DefaultError.LOG" );
			csError.LoadString( IDS_ERRORNOLOG );
			AfxMessageBox( csError );
		}

	TRY
	{
		CFile cFile( szFileName, CFile::modeCreate | 
								 CFile::modeNoTruncate | 
								 CFile::modeReadWrite );
		cFile.SeekToEnd();
		cFile.Write( csLogEntry, csLogEntry.GetLength() );
		cFile.Write( "\r\n", 2 );
		cFile.Close();
	}
	CATCH( CFileException, e )
	{
		#ifdef _DEBUG
			 afxDump << "File could not be opened " << e->m_cause << "\n";
		#else
			csError.LoadString( IDS_LOGERROR );
			csError.Format( csError, e->m_cause );
			AfxMessageBox( csError );
		#endif
	}
	END_CATCH
}

void CErrorReport::ParseCaptions( CString csCaptions )
{		// caption string expected format:
		//	"What Happened|Results|Corrective Actions|Comments"
	int		nOfs;
	
	nOfs = csCaptions.Find( (char) '|' ); 
	if( nOfs > 0 )
		m_csCaption_WhatHappened.Format( "%s", csCaptions.Left( nOfs ) );
	csCaptions = csCaptions.Right( csCaptions.GetLength() - ( ++nOfs ) );

	nOfs = csCaptions.Find( (char) '|' ); 
	if( nOfs > 0 )
		m_csCaption_Results.Format( "%s", csCaptions.Left( nOfs ) ); 
	csCaptions = csCaptions.Right( csCaptions.GetLength() - ( ++nOfs ) );

	nOfs = csCaptions.Find( (char) '|' ); 
	if( nOfs > 0 )
		m_csCaption_CorrectiveAction.Format( "%s", csCaptions.Left( nOfs ) ); 
	csCaptions = csCaptions.Right( csCaptions.GetLength() - ( ++nOfs ) );

	m_csCaption_Comments = csCaptions;
}

int	CErrorReport::ReportUserError( UINT nTimeout = 0 )
{
	int	nResult;

	MessageBeep( MB_OK );
//	CUserErrorDlg * pDlg = new CUserErrorDlg(AfxGetApp()->m_pMainWnd);
	CUserErrorDlg * pDlg = new CUserErrorDlg();
	pDlg->m_csWhatHappened = m_csWhatHappened;
	pDlg->m_csCorrectiveAction = m_csCorrectiveAction;
	pDlg->m_nTimeout = nTimeout;
	if( ! m_csCaption.IsEmpty() )
		pDlg->m_csCaption = m_csCaption;
	else
		pDlg->m_csCaption.Format( IDS_USERERROR_CAPTION, m_nErrorCode );
	//=== optional caption changes =======================================
	if( ! m_csCaption_WhatHappened.IsEmpty() )
		pDlg->m_csCaption_WhatHappened = m_csCaption_WhatHappened;
	if( ! m_csCaption_CorrectiveAction.IsEmpty() )
		pDlg->m_csCaption_CorrectiveAction = m_csCaption_CorrectiveAction;
	//====================================================================
	nResult = pDlg->DoModal();
	LogError();
	delete pDlg;
	return nResult;
}

int	CErrorReport::ReportInformation( UINT nTimeout = 0 )
{
	int	nResult;

	MessageBeep( MB_ICONHAND );
//	CInfoDlg * pDlg = new CInfoDlg(AfxGetApp()->m_pMainWnd);
	CInfoDlg * pDlg = new CInfoDlg();
	pDlg->m_csWhatHappened = m_csWhatHappened;
	pDlg->m_csResults = m_csResult;
	pDlg->m_csCorrectiveAction = m_csCorrectiveAction;
	pDlg->m_nTimeout = nTimeout;
	if( ! m_csCaption.IsEmpty() )
		pDlg->m_csCaption = m_csCaption;
	else
		pDlg->m_csCaption.Format( IDS_INFORMATION_CAPTION, m_nErrorCode );
	//=== optional caption changes =======================================
	pDlg->m_csCaption_WhatHappened = m_csCaption_WhatHappened;
	pDlg->m_csCaption_CorrectiveAction = m_csCaption_CorrectiveAction;
	pDlg->m_csCaption_Results = m_csCaption_Results;
	//====================================================================
	nResult = pDlg->DoModal();
	LogError();
	delete pDlg;
	return nResult;
}

int	CErrorReport::ReportNonCritical()
{
	CString	csCaption;
	int		nResult;

//	CNonCritDlg * pDlg = new CNonCritDlg(AfxGetApp()->m_pMainWnd);
	CNonCritDlg * pDlg = new CNonCritDlg();
	MessageBeep( MB_ICONASTERISK );
	pDlg->m_csWhatHappened = m_csWhatHappened;
	pDlg->m_csResults = m_csResult;
	pDlg->m_csCorrectiveAction = m_csCorrectiveAction;
	if( ! m_csCaption.IsEmpty() )
		pDlg->m_csCaption = m_csCaption;
	else
		pDlg->m_csCaption.Format( IDS_NONCRITICAL_CAPTION, m_nErrorCode );
	//=== optional caption changes =======================================
	pDlg->m_csCaption_WhatHappened = m_csCaption_WhatHappened;
	pDlg->m_csCaption_CorrectiveAction = m_csCaption_CorrectiveAction;
	pDlg->m_csCaption_Results = m_csCaption_Results;
	pDlg->m_csCaption_Comments = m_csCaption_Comments;
	//====================================================================
	pDlg->DoModal();
	nResult = pDlg->m_nResult;			// this is the only result we want to test
	if( nResult == RESULT_LOG_LOCAL )
		LogError( pDlg->m_csComments );	// log with comments
	else
		LogError();						// log without comments on OK or Cancel
	delete pDlg;
	return nResult;
}

int	CErrorReport::ReportSevereError()
{
	CString	csCaption;
	int		nResult;

//	CSevereErrDlg * pDlg = new CSevereErrDlg(AfxGetApp()->m_pMainWnd);
	CSevereErrDlg * pDlg = new CSevereErrDlg();
	MessageBeep( MB_ICONQUESTION );
	pDlg->m_csWhatHappened = m_csWhatHappened;
	pDlg->m_csResults = m_csResult;
	pDlg->m_csCorrectiveAction = m_csCorrectiveAction;
	if( ! m_csCaption.IsEmpty() )
		pDlg->m_csCaption = m_csCaption;
	else
		pDlg->m_csCaption.Format( IDS_SEVERERROR_CAPTION, m_nErrorCode );
	//=== optional caption changes =======================================
	pDlg->m_csCaption_WhatHappened = m_csCaption_WhatHappened;
	pDlg->m_csCaption_CorrectiveAction = m_csCaption_CorrectiveAction;
	pDlg->m_csCaption_Results = m_csCaption_Results;
	pDlg->m_csCaption_Comments = m_csCaption_Comments;
	//====================================================================
	pDlg->DoModal();
	nResult = pDlg->m_nResult;			// this is the only result we want to test
	if( nResult == RESULT_REPORT_ERROR )
		LogError( pDlg->m_csComments );	// log with comments
	else
		LogError();						// log without comments on OK or Cancel
	delete pDlg;
	return nResult;
}

int	CErrorReport::ReportRetryError( UINT nTimeout = 15 )
{
	int	nResult;

	MessageBeep( MB_ICONEXCLAMATION );
//	CRetryErrorDlg * pDlg = new CRetryErrorDlg(AfxGetApp()->m_pMainWnd);
	CRetryErrorDlg * pDlg = new CRetryErrorDlg();
	pDlg->m_nTimeout = nTimeout;
	pDlg->m_csWhatHappened = m_csWhatHappened;
	pDlg->m_csCorrectiveAction = m_csCorrectiveAction;
	if( ! m_csCaption.IsEmpty() )
		pDlg->m_csCaption = m_csCaption;
	else
		pDlg->m_csCaption.Format( IDS_RETRYERROR_CAPTION, m_nErrorCode );
	//=== optional caption changes =======================================
	pDlg->m_csCaption_WhatHappened = m_csCaption_WhatHappened;
	pDlg->m_csCaption_CorrectiveAction = m_csCaption_CorrectiveAction;
	//====================================================================
	nResult = pDlg->DoModal();
	LogError();
	delete pDlg;
	return nResult;
}

