#include "Mix/Private/Logger.h"
#include <list>

using namespace Mix;

Logger* Logger::g_pThis = NULL;

Boolean Logger::CreateInstance( const wchar_t* userFolderName, const wchar_t* logFileName )
{
	MIX_ASSERT( g_pThis == NULL );

	g_pThis = MIX_LIB_NEW_T( Mix::Memory::SECTION_GENERAL, Logger );

	if( g_pThis != NULL )
	{
		if( g_pThis->Initialize( userFolderName, logFileName ) == False )
		{
			return False;
		}
	}
	else
	{
		return False;
	}

	return ( g_pThis != NULL );
}

void Logger::ReleaseInstance( void )
{
	if( g_pThis != NULL )
	{
		g_pThis->Finalize();
	}

	MIX_LIB_DELETE_T( Logger, g_pThis );
}

Logger* Logger::Instance( void )
{
	return Logger::g_pThis;
}

Logger::Logger( void ) :
m_bInit( False ),
m_ParCount( 0 )
{
}

Boolean Logger::Initialize( const wchar_t* userFolderName, const wchar_t* logFileName )
{
#ifndef _DEBUG
	SYSTEMTIME st;

	if( m_File.Initialize( userFolderName, logFileName ) == False )
	{
		return False;
	}

	::GetLocalTime( &st );

	m_File.WriteLine( L"INFO    : ログの記録を開始 : %d/%d/%d %d:%d:%d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
#endif //_DEBUG

	return True;
}

void Logger::Finalize( void )
{
#ifndef _DEBUG
	SYSTEMTIME st;

	::GetLocalTime( &st );

	m_File.WriteLine( L"INFO    : ログの記録を終了 : %d/%d/%d %d:%d:%d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
#endif //_DEBUG
}

void Logger::WriteText( Mix::Logger::LEVEL level, UInt32 flags, const wchar_t* format, ... )
{
	va_list args;
	wchar_t basic[MAX_CHAR] = L"";

	va_start( args, format );
	_vsnwprintf_s( basic, sizeof( basic ) >> 1, _TRUNCATE, format, args );
	va_end( args );

	InternalWriteText( level, flags, basic );
}

void Logger::WriteSectionLine( Mix::Logger::LEVEL level, UInt32 flags )
{
	InternalWriteText( level, flags, L"----------------------------------------------------------------------------------------------------" );
}

void Logger::WriteSctionStart( Mix::Logger::LEVEL level, UInt32 flags, const wchar_t* format, ... )
{
	va_list args;
	wchar_t basic[MAX_CHAR] = L"";

	va_start( args, format );
	_vsnwprintf_s( basic, sizeof( basic ) >> 1, _TRUNCATE, format, args );
	va_end( args );

//	WriteSectionLine( level, flags );
	InternalWriteText( level, flags, basic );
//	InternalWriteText( level, flags, L"" );
	Par( +1 );
}

void Logger::WriteSctionEnd( Mix::Logger::LEVEL level, UInt32 flags )
{
	Par( -1 );
//	WriteSectionLine( level, flags );
}

void Logger::Par( Int32 count )
{
	m_ParCount += Logger::PAR_SIZE * count;
}

void Logger::InternalWriteText( Mix::Logger::LEVEL level, UInt32 flags, const wchar_t* basic )
{
#ifdef NDEBUG
	if( ( level == Mix::Logger::L_INFO ) ||
		( MIX_TESTBIT( flags, Mix::Logger::F_DEVELOP ) == Mix::Logger::F_DEVELOP ) )
	{
		return;
	}
#endif NDEBUG

	/*
		基本のテキストを作成
	*/

	wchar_t par[MAX_CHAR] = L"";
	wchar_t first[MAX_CHAR] = L"";
	wchar_t text[MAX_CHAR] = L"";

	/*
		重複処理
	*/

	if( ( MIX_TESTBIT( flags, Mix::Logger::F_NO_OVERLAP ) == Mix::Logger::F_NO_OVERLAP ) &&
		( m_PreLog == basic ) )
	{
		//同じログは流さない
		return;
	}

	/*
		直前のログとして保存
	*/

	m_PreLog = basic;

	/*
		段落
	*/

	Int32 parCount = 0;

	if( ( MAX_CHAR - 1 ) <= m_ParCount )
	{
		parCount = MAX_CHAR - 1;
	}
	else if( m_ParCount > 0 )
	{
		parCount = m_ParCount;
	}

	for( Int32 i = 0; i < parCount; i++ )
	{
		par[i] = L' ';
	}

	par[parCount] = L'\0';

	/*
		ログレベルのテキストを作成
	*/

#ifdef _DEBUG
	switch( level )
	{
	case Mix::Logger::L_INFO:
		::wsprintf( first, L"Mix : (INFO)       : " );
		break;
	case Mix::Logger::L_INFO_FORCE:
		::wsprintf( first, L"Mix : (INFO_FORCE) : " );
		break;
	case Mix::Logger::L_WARNING:
		::wsprintf( first, L"Mix : (WARNING)    : " );
		break;
	case Mix::Logger::L_ERROR:
		::wsprintf( first, L"Mix : (ERROR)      : " );
		break;
	}
#else //_DEBUG
	switch( level )
	{
	case Mix::Logger::L_INFO_FORCE:
		::wsprintf( first, L"INFO    : " );
		break;
	case Mix::Logger::L_WARNING:
		::wsprintf( first, L"WARNING : " );
		break;
	case Mix::Logger::L_ERROR:
		::wsprintf( first, L"ERROR   : " );
		break;
	}
#endif //_DEBUG

	/*
		ログレベルと基本のテキストを結合
	*/

	::wcscpy_s( text, sizeof( text ) >> 1, first );
	::wcscat_s( text, sizeof( text ) >> 1, par );
	::wcscat_s( text, sizeof( text ) >> 1, basic );

#ifdef _DEBUG
	::wcscat_s( text, sizeof( text ) >> 1, L"\n" );
#endif //_DEBUG

	/*
		出力
	*/

#ifdef _DEBUG
	::OutputDebugStringW( text );
#else //_DEBUG
	m_File.WriteLine( text );
#endif //_DEBUG
}
