//********************************************************************************
//*	ファイル名：DailyLogManagerS.cpp	
//*	用　　　途：ログ管理クラス
//*	備　　　考：シングルトンパターン
//*	履　　　歴：
//********************************************************************************
/****************************
*	 プリコンパイル設定		*
****************************/
#include "stdafx.h"
/****************************
*	 コンパイル環境設定		*
****************************/
/****************************
*	インクルードファイル	*
****************************/
#include "DailyLogManagerS.h"
#include "Atomic.h"
#include "System.h"
/****************************
*		 マクロ定数			*
****************************/
/****************************
*		 構造体定義			*
****************************/
/****************************
*		 クラス定義			*
****************************/
/****************************
*		 関数　宣言			*
****************************/
/****************************
*		 変数　宣言			*
****************************/

//********************************************************************************
//*	関数名：CDailyLogManagerS
//*	用　途：デフォルトコンストラクタ
//*	引き数：
//*	戻り値：
//*	備　考
//********************************************************************************
CDailyLogManagerS::CDailyLogManagerS(void)  : CDailyLogManager()
{
	m_strFilePath	= _T("") ;

	for( INT32 i = 0 ; i < NOF_LOG ; i++ ){
		m_uaLogID[i] = -1 ;
	}

	::CreateDirectoryA( AbsPath( LOG_PATH			), NULL ) ;		// ログフォルダ

	////***** 出力関連サブフォルダ
	::CreateDirectoryA( AbsPath( LOG_SYSTEM_PATH	), NULL ) ;		// システムログフォルダ
	::CreateDirectoryA( AbsPath( LOG_ERROR_PATH		), NULL ) ;		// エラーログフォルダ
	::CreateDirectoryA( AbsPath( LOG_MINING_PATH	), NULL ) ;		// マイニングログフォルダ
	::CreateDirectoryA( AbsPath( LOG_SETTING1_PATH	), NULL ) ;		// 設定１ログフォルダ
	::CreateDirectoryA( AbsPath( LOG_SETTING2_PATH	), NULL ) ;		// 設定２ログフォルダ
	::CreateDirectoryA( AbsPath( LOG_SETTING3_PATH	), NULL ) ;		// 設定３ログフォルダ
	::CreateDirectoryA( AbsPath( LOG_SETTING4_PATH	), NULL ) ;		// 設定4ログフォルダ
	::CreateDirectoryA(	AbsPath( LOG_PRODUCTINFO_PATH ), NULL);		// 生産情報ログフォルダ
}

//********************************************************************************
//*	関数名：~CDailyLogManagerS
//*	用　途：デストラクタ
//*	引き数：
//*	戻り値：
//*	備　考
//********************************************************************************
CDailyLogManagerS::~CDailyLogManagerS(void)
{

}

//********************************************************************************
//*	関数名：GetInstance
//*	用　途：インスタンス取得（初回は生成）
//*	引き数：
//*	戻り値：
//*	備　考
//********************************************************************************
CDailyLogManagerS& CDailyLogManagerS::GetInstance(void)
{
	static CDailyLogManagerS Singleton;
	return Singleton; 
}


//********************************************************************************
//*	関数名：Initialize
//*	用　途：初期化
//*	引き数：
//*	戻り値：
//*	備　考：設定ファイルを読み込んで初期化する
//********************************************************************************
void CDailyLogManagerS::Initialize( CString strFilePath )
{
	CFileFind	filefind ;
	CIniFile	IniFile ;
	BOOL		bRet ;
	INT32		nDefault ;

	CString		section ;
	TCHAR		*s ;

	tagParamDailyLog *tpParamLog ;

	// ファイルが無ければ終了
	if( !filefind.FindFile( strFilePath ) ) return  ;

	m_strFilePath = strFilePath ;
	
	// ファイル読み込み
	bRet = IniFile.Load( strFilePath );

	// Iniファイルデータ→パラメータ構造体

	// ログ設定
	for( INT32 i = 0 ; i < NOF_LOG ; i++ ){
		tpParamLog = &m_taParamLog[i] ;

		section = m_szLogName[i] ;
		s = (TCHAR *)(LPCTSTR)section;

		IniFile.AccessProfile( FLAG_ACCESS_GET, s, _T("Enable"		)	, &( tpParamLog->bEnable		), DATA_ATTR_BOOL	, &( nDefault	= 0	 ) ) ;
		IniFile.AccessProfile( FLAG_ACCESS_GET, s, _T("RestSize"	)	, &( tpParamLog->nRestSize		), DATA_ATTR_INT32	, &( nDefault	= 2	 ) ) ;
		IniFile.AccessProfile( FLAG_ACCESS_GET, s, _T("DaysOfDeadLine")	, &( tpParamLog->nDaysOfDeadLine), DATA_ATTR_INT32	, &( nDefault	= 30 ) ) ;

		tpParamLog->hDspMessageWnd	= 0 ;
		tpParamLog->nDspMessageID	= 0 ;

		_stprintf_s( tpParamLog->szPath		, _MAX_PATH, AbsPath(m_szLogPath[i]) );
		_stprintf_s( tpParamLog->szFileName	, _MAX_PATH, m_szLogName[i] );

		m_uaLogID[i] = AddDailyLog(*tpParamLog);
	}

	CDailyLogManager::Initialize(5000 , 100000);
}

//********************************************************************************
//*	関数名：PrintLog											
//*	用　途：ログに１データ出力する							
//*	引き数：データ											
//*	戻り値：
//*	備　考：
//********************************************************************************
BOOL CDailyLogManagerS::PrintLog(INT32 nLogIndex, TCHAR *szFmt, ...)
{
	CString		strPrint ;		// 結果文字列
	LPTSTR		psz      ;		// 文字列
	va_list		argList  ;		// 可変長引数リスト

	va_start( argList, szFmt ) ;
	psz = strPrint.GetBufferSetLength( LENGTH_DAILYLOG ) ;
	_vsntprintf_s( psz, LENGTH_DAILYLOG ,LENGTH_DAILYLOG, szFmt, argList ) ;
	strPrint.ReleaseBuffer() ;
	va_end( argList );

	return Print( m_uaLogID[nLogIndex], strPrint ) ;
}

//********************************************************************************
//*	関数名：PrintLog											
//*	用　途：ログに１データ出力する							
//*	引き数：データ											
//*	戻り値：
//*	備　考：
//********************************************************************************
BOOL CDailyLogManagerS::PrintLog(INT32 nLogIndex, CString &str)
{
	return Print( m_uaLogID[nLogIndex], str ) ;
}

//********************************************************************************
//*	関数名：SetLogMessage											
//*	用　途：表示用メッセージ情報セット						
//*	引き数：ログID、message送信先、ID											
//*	戻り値：
//*	備　考：
//********************************************************************************
BOOL CDailyLogManagerS::SetLogMessage( INT32 nLogIndex, HWND hDspMessageWnd , INT32 nDspMessageID )
{
	tagParamDailyLog tParamDailyLog;
	
	//パラメータ取得
	if( !GetParam( m_uaLogID[nLogIndex], &tParamDailyLog ) ) return FALSE ;

	//パラメータ更新
	tParamDailyLog.hDspMessageWnd	= hDspMessageWnd;
	tParamDailyLog.nDspMessageID	= nDspMessageID;

	if( !SetParam( m_uaLogID[nLogIndex], tParamDailyLog ) ) return FALSE ;

	return TRUE;
}

/*******************************************************************************
*	関　数　名：GetEnvPath
*	用　　　途：作業フォルダのパス名を取得します
*				パス名先頭が実行ファイル名と同じパスを抽出します
*	引　き　数：作業フォルダパス名返却先
*	戻　り　値：
*	備　　　考：Debug/Releaseの各実行モードやテスト環境になるべく関わらない形で
*			　　デバッグ・実行することが目的です。
*				※非公開メンバー
********************************************************************************/
void CDailyLogManagerS::GetEnvPath( LPTSTR pszEnvPath )
{
	TCHAR		szExePath[_MAX_PATH] ;			// 実行ファイルパス名
	LPTSTR		psz ;							// 探索ポインタ
	LPTSTR		pszStart ;						// 階層毎探索開始ポインタ
	int			nPathLength ;					// 階層名文字列長
	int			nExeNameLength ;				// 実行ファイル名文字列長
	CString		strExeName ;					// 実行ファイル名

	// 実行ファイル名取得
	pszEnvPath[0]	= _T('\0') ;
	strExeName		= ::AfxGetAppName() ;
	nExeNameLength	= strExeName.GetLength() ;

	// 実行ディレクトリ名の取得
	::GetModuleFileName( NULL, szExePath, sizeof(szExePath) ) ;	// 実行ファイルの絶対パス取得
	::PathRemoveFileSpec(szExePath) ;							// パスからファイル名を除く

	// ループ初期設定
	psz				= szExePath - 1 ;
	pszStart		= szExePath ;

	// 各部分フォルダ名の先頭が実行ファイル名と一致するか、終端に
	// 到達するまでループ
	do{ // loop
		psz++ ;
		if( *psz!=_T('\\') && *psz!=_T('\0') ){ 
			continue ;
		}

		nPathLength = (int)( psz - pszStart ) ;
		if( nPathLength < strExeName.GetLength() ){ 
			pszStart = psz + 1 ;
			continue ;
		}

		// 大文字小文字に関係なく比較
		// フォルダ名の先頭と実行ファイル名が同一ならそこが
		// 実行環境と解釈する
		if( _tcsnicmp(pszStart, strExeName, nExeNameLength) == 0 ){ 
			nPathLength			= (int)( psz - szExePath ) ;
			_tcsncpy_s( pszEnvPath, _MAX_PATH, szExePath, nPathLength ) ;
			pszEnvPath[nPathLength] = _T('\0') ;

			break ;
		}

		pszStart = psz + 1 ;
	}while( *psz != _T('\0') ) ;
}


/*******************************************************************************
*	関　数　名：EnvPath
*	用　　　途：作業フォルダパス取得
*	引　き　数：最後のバックスラッシュの有無
*	戻　り　値：作業フォルダパス名
*	備　　　考：静的固定領域に作業パス文字列を１度だけ取得しておき、
*				２度目以降は、この領域の文字列を返却する
*				本来はありえないが、メインスレッド以外のスレッドが最初に
*				本関数を呼んだ場合のロックを行っている
********************************************************************************/
CString CDailyLogManagerS::EnvPath( BOOL bAddLastSlash )
{
	/// 静的変数宣言と初期化
	static	ATOMIC_LONG	s_lbInitEnvPath				= FALSE ;		// 初期化(パス取得済みフラグ)
	static	ATOMIC_LONG	s_lbInitLock				= 0 ;			// 初期化用ロック
	static	TCHAR		s_szEnvPath[_MAX_PATH+1]	= { 0 } ;		// 取得済み作業パス名保持

	/// 本文
						CString	strEnvPath = _T("") ;		// 返却パス

	do{ // once
		// 初期化済みならば終了
		if( s_lbInitEnvPath ){ 
			strEnvPath = s_szEnvPath ; 
			break ;
		}

		// 初期化ロック獲得
		while( ::InterlockedCompareExchange(&s_lbInitLock, 1, 0) != 0 ){ 
			::Sleep( 10 ) ;
		}

		// 再度初期化状態を確認し、ロック獲得の一瞬の間に初期化されていたならば
		// 終了
		// (スレッドセーフ対応用double checked locking)
		if( s_lbInitEnvPath ){ 
			strEnvPath = s_szEnvPath ; 
			break ;
		}

		// 作業パスを取得して保持
		//GetEnvPath( s_szEnvPath ) ;
		GetMyPath(s_szEnvPath);

		// 初期化ロック解除
		::InterlockedExchange( &s_lbInitLock, 0 ) ;

		// 作業パスセットおよび初期化済みセット
		strEnvPath		= s_szEnvPath ;
		s_lbInitEnvPath	= TRUE ; 
	} while ( FALSE ) ;

	// 必要であれば、バックスラッシュを追加する
	if( bAddLastSlash ){ 
		strEnvPath += _T('\\') ;
	}

	return strEnvPath ;
}


/*******************************************************************************
*	関　数　名：AbsPath
*	用　　　途：作業フォルダからの相対パスを絶対パスに変換する
*	引　き　数：対象相対パス
*	戻　り　値：絶対パス
*	備　　　考：
********************************************************************************/
CString CDailyLogManagerS::AbsPath( LPCTSTR szRelativePath )
{
	if( szRelativePath != NULL ){ 
		return EnvPath(FALSE) + szRelativePath ;
	}
	else{ 
		return EnvPath(FALSE) ;
	}
}