#include "StdAfx.h"
#include "LogManager.h"
#include "ServerStartErrorException.h"
#include "Dir.h"

#define	CLASS_NAME	"LogManager"
#define	MAX_LOG_CACHE	50000

CLogManager::CLogManager(void)
{
}

CLogManager::~CLogManager(void)
{
	Stop();
}


///////////////////////////////////////////////////////////////////////////////////////////////////
//	操作
///////////////////////////////////////////////////////////////////////////////////////////////////
/*!
	開始
*/
void CLogManager::Start(IServerToolPtr serverTool)
{
	//	初期化済み？
	if(m_init)
		return;
	m_init = TRUE;

	//	コピー、初期化
	m_serverTool = serverTool;

	//	設定取得
	m_setting = m_serverTool->GetManagerSetting(m_setting.GetSettingName());

	//	設定初期化
	m_intervalTime = m_setting.GetUpdateInterval();

	//	スレッド起動
	if(StartThread())
		throw CServerStartErrorException(CLASS_NAME, "スレッドの起動に失敗しました");
}

/*!
	停止
*/
void CLogManager::Stop()
{
	//	初期化チェック
	if(!m_init)
		return;
	m_init = FALSE;

	//	スレッド停止
	EndThread();
}

/*!
	アクセスログ出力
*/
void CLogManager::WriteAccessLog(CString filePath, CString log)
{
	SCOPE_LOCK();

	//	数チェック
	if(m_logList.GetSize() > MAX_LOG_CACHE)
		return;
	m_logList.AddTail(CLogManagerEntry(filePath, log));
}


/////////////////////////////////////////////////////////////////////////////////////
//	スレッド関数
/////////////////////////////////////////////////////////////////////////////////////
/*!
	スレッド
*/
void CLogManager::ThreadMain()
{
	while(!GetBreak())
	{
		//	待機
		WaitForSomeObjects(m_intervalTime, GetBreakEvent());

		//	ログ吐き出し
		FlashLog();
	}
}

/*!
	ログ出力
*/
void CLogManager::FlashLog()
{
	SCOPE_LOCK();

	while(!m_logList.IsEmpty())
	{
		//	ディレクトリ作成
		CString	dir = CPathTools::PathToDir(m_logList.GetHead().m_filePath);
		if(m_oldDir != dir)
		{
			CFileDirTools::MakeAllDirectory(dir);
			m_oldDir = dir;
		}

		//	ファイルを開く
		FILE	*log;
		if(fopen_s(&log, m_logList.GetHead().m_filePath, "at+"))
			log = NULL;	//	エラーファイルは無視する

		//	書き出し
		WriteLogs(log, m_logList.GetHead().m_filePath);

		//	閉じる
		if(log != NULL)
			fclose(log);
	}
}


/*!
	ログをファイルへ
	同じファイルパスを書き出し
*/
void CLogManager::WriteLogs(FILE *log, CString filePath)
{
	POSITION	pos = m_logList.GetHeadPosition();
	while(pos)
	{
		//	ファイルパスは一致？
		if(m_logList.GetAt(pos).m_filePath == filePath)
		{
			if(log != NULL)
			{
				//	ログエスケープ
				CString	slog = m_logList.GetAt(pos).m_log;
				slog.Replace("\n", "");
				slog.Replace("\r", "");

				//	出力
				fprintf_s(log, "%s\n", slog);
			}

			//	削除して次を取得
			POSITION	del = pos;
			m_logList.GetNext(pos);
			m_logList.RemoveAt(del);
		}
		else
		{
			//	次を取得
			m_logList.GetNext(pos);
		}
	}
}
