#include "Mix/Private/UserFile.h"

using namespace Mix;

UserFile::UserFile( void ) :
m_bInit( False ),
m_OpenCount( 0 ),
m_hFile( INVALID_HANDLE_VALUE )
{
}

UserFile::~UserFile( void )
{
	if( m_hFile != INVALID_HANDLE_VALUE )
	{
		::CloseHandle( m_hFile );
	}
}

Boolean UserFile::Initialize( const wchar_t* path, const wchar_t* fileName )
{
	if( m_bInit == True )
	{
		return True;
	}

	LPITEMIDLIST pItemIdList = NULL;
	IMalloc* pMalloc = NULL;
	wchar_t myDocPath[2048];

	//マイドキュメントのパスを取得
	if( ::SHGetMalloc( &pMalloc ) == S_OK )
	{
		if( ::SHGetSpecialFolderLocation( NULL, CSIDL_PERSONAL, &pItemIdList ) == S_OK )
		{
			::SHGetPathFromIDList( pItemIdList, myDocPath );
			pMalloc->Free( pItemIdList );
			pMalloc->Release();
		}
		else
		{
			pMalloc->Release();
			return False;
		}
	}
	else
	{
		return False;
	}

	//マイドキュメントのパス
	m_MyDocPath = myDocPath;

	//マイドキュメント以降のパス( ユーザーフォルダ )
	m_Path.Sprintf( L"%s", path );
	if( ( path[::wcslen( path ) - 1] == L'\\' ) ||
		( path[::wcslen( path ) - 1] == L'/' ) )
	{
		m_Path.GetPtr()[::wcslen( path ) - 1] = L'\0';
	}

	//設定
	m_SearchPath.Sprintf( L"%s/%s/*.*", m_MyDocPath.GetPtr(), m_Path.GetConstPtr() );
	m_FullFileName.Sprintf( L"%s/%s/%s", m_MyDocPath.GetConstPtr(), m_Path.GetConstPtr(), fileName );

	//ファイルをクリア
	if( CreateFolder() == True )
	{
		m_hFile = ::CreateFileW( m_FullFileName.GetConstPtr(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
		if( m_hFile != INVALID_HANDLE_VALUE )
		{
			::CloseHandle( m_hFile );
			m_hFile = INVALID_HANDLE_VALUE;
		}
		else
		{
			return False;
		}
	}
	else
	{
		return False;
	}

	//初期化済み
	m_bInit = True;

	return True;
}

Boolean UserFile::Open( void )
{
	Boolean ret = True;

	if( m_OpenCount == 0 )
	{
		if( CreateFolder() == True )
		{
			m_hFile = ::CreateFileW( m_FullFileName.GetConstPtr(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
			if( m_hFile != INVALID_HANDLE_VALUE )
			{
				DWORD filePtr = ::SetFilePointer( m_hFile, 0, NULL, FILE_END );

				if( filePtr == FILE_BEGIN )
				{
					const UInt8 bom[2] =
					{
						0xFF,
						0xFE
					};

					DWORD writeSize = 0;

					if( ::WriteFile( m_hFile, bom, sizeof( bom ), &writeSize, NULL ) == FALSE )
					{
						ret = False;
					}
				}
			}
			else
			{
				ret = False;
			}
		}
		else
		{
			ret = False;
		}
	}

	if( ret == True )
	{
		m_OpenCount++;
	}

	return ret;
}

void UserFile::Close( void )
{
	if( m_OpenCount == 0 )
	{
		return;
	}
	else
	{
		if( --m_OpenCount == 0 )
		{
			if( m_hFile != INVALID_HANDLE_VALUE )
			{
				::CloseHandle( m_hFile );
				m_hFile = INVALID_HANDLE_VALUE;
			}
		}
	}
}

Boolean UserFile::Write( const wchar_t* format, ... )
{
	Boolean ret = True;

	if( Open() == True )
	{
		va_list args;
		wchar_t text[MAX_CHAR];
		DWORD writeSize = 0;

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

		if( ::WriteFile( m_hFile, text, MIX_UIT_TO_UI32( ::wcslen( text ) << 1 ), &writeSize, NULL ) == FALSE )
		{
			ret = False;
		}

		Close();
	}

	return ret;
}

Boolean UserFile::WriteLine( const wchar_t* format, ... )
{
	Boolean ret = True;

	if( Open() == True )
	{
		va_list args;
		wchar_t text[MAX_CHAR];
		DWORD writeSize = 0;

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

		::wcscat_s( text, L"\n" );

		if( ::WriteFile( m_hFile, text, MIX_UIT_TO_UI32( ::wcslen( text ) << 1 ), &writeSize, NULL ) == FALSE )
		{
			ret = False;
		}

		Close();
	}

	return ret;
}

Boolean UserFile::CreateFolder( void )
{
	Boolean bSuccess = False;
	WIN32_FIND_DATA wfd;
	HANDLE hFind;

	hFind = ::FindFirstFileW( m_SearchPath.GetConstPtr(), &wfd );
	if( hFind == INVALID_HANDLE_VALUE )
	{
		UInt32 i = 0;
		UInt32 ii = 0;
		const wchar_t* path = m_Path.GetConstPtr();

		for( ;; )
		{
			if( ( path[i] == L'\\' ) ||
				( path[i] == L'/' ) ||
				( path[i] == L'\0' ) )
			{
				Mix::String subPath = m_Path.Left( i );

				if( i != ii )
				{
					Mix::String createFolderPath;
				
					createFolderPath = m_MyDocPath;
					createFolderPath += L'/';
					createFolderPath += subPath;
					createFolderPath += L'/';

					if( ::CreateDirectoryW( createFolderPath.GetConstPtr(), NULL ) == TRUE )
					{
						bSuccess = True;
					}

					ii = ( i + 1 );
				}

				if( path[i] == L'\0' )
				{
					break;
				}
			}

			i++;
		}
	}
	else
	{
		::FindClose( hFind );
		bSuccess = True;
	}

	return bSuccess;
}
