#include "Mix/Private/IO/Manager.h"
#include <Shlwapi.h>

namespace Mix{ namespace IO{

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::File::Manager
////////////////////////////////////////////////////////////////////////////////////////////////////

const wchar_t* Manager::FAILED_INITIALIZE            = L"ファイルマネージャの初期化に失敗";
const wchar_t* Manager::FAILED_GETABSPATH            = L"絶対パスの取得に失敗";
const wchar_t* Manager::FAILED_EXISTFILE             = L"ファイルの有無の確認に失敗";
const wchar_t* Manager::FAILED_CREATEFILEREADER      = L"ファイルリーダーの作成に失敗";
const wchar_t* Manager::FAILED_CREATEFILEWRITER      = L"ファイルライターの作成に失敗";
const wchar_t* Manager::FAILED_CREATEBUFFEREDREADER  = L"バッファドリーダーの作成に失敗";
const wchar_t* Manager::FAILED_CREATEFILEBUFFER      = L"ファイルバッファの作成に失敗";

const wchar_t* Manager::MSG_DIR_PATH_NOT_SOLVE  = L"ディレクトリパスを解決できません";
const wchar_t* Manager::MSG_FILE_PATH_NOT_SOLVE = L"ファイルパスを解決できません";
const wchar_t* Manager::MSG_FILE_NOT_OPEN       = L"ファイルを開けません";
const wchar_t* Manager::MSG_FILE_NOT_READ       = L"ファイルを読み取れません";
const wchar_t* Manager::MSG_FILE_IN_USE         = L"ファイルは使用中です";
const wchar_t* Manager::MSG_FILE_SIZE_LARGE     = L"ファイルサイズが大きすぎます";

Manager::~Manager( void )
{
}

Boolean Manager::CreateDirectory( const wchar_t* pFailedMsg, const wchar_t* pDirectoryPath )
{
	UIntT i;
	UIntT len;
	Boolean ret;
	Mix::String directoryName;
	Mix::String work;
	HANDLE hFind;
	WIN32_FIND_DATAW wfd;
	const wchar_t* src;

	//ディレクトリ名を解決

	if( ModifyPath( P_DIR, pDirectoryPath, directoryName ) == False )
	{
		MIX_LOG_ERROR( L"%s : ディレクトリ名を解決できません : %s[%s]", pFailedMsg, Mix::STR_DIRPATH, pDirectoryPath );
		return False;
	}

	//サーチパスを作成
	work.Sprintf( L"%s*.*", directoryName.GetConstPtr() );

	//フォルダがすでに存在しているかチェックする
	hFind = ::FindFirstFileW( work.GetConstPtr(), &wfd );
	if( hFind != INVALID_HANDLE_VALUE )
	{
		//すでに作成されている
		::FindClose( hFind );
		return True;
	}

	//フォルダを作成する
	ret = True;
	len = directoryName.GetNum();
	src = directoryName.GetConstPtr();
	for( i = 0; i < len; i++ )
	{
		if( ( i > 3 ) &&
			( src[i] == L'\\' ) ||
			( src[i] == L'/' ) )
		{
			work = directoryName.Left( i + 1 );

			if( ( ::CreateDirectoryW( work.GetConstPtr(), NULL ) == FALSE ) &&
				( i == ( len - 1 ) ) )
			{
				ret = False;
			}
		}
	}

	if( ret == False )
	{
		MIX_LOG_ERROR( L"%s : CreateDirectoryW %s : %s[%s]", pFailedMsg, Mix::STR_RETERROR, Mix::STR_DIRPATH, pDirectoryPath );
	}

	return ret;
}

Boolean Manager::ModifyPath( UInt32 flags, const wchar_t* pSrc, Mix::String& dst )
{
	wchar_t* pDst;
	wchar_t* pDstEnd;

	if( IsAbsolutePath( pSrc ) == True )
	{
		//絶対パス
		dst = pSrc;
	}
	else
	{
		//相対パス
		wchar_t work[MAX_PATH];

		if( ::PathCombineW( work, m_RootDirectoryPath.GetConstPtr(), pSrc ) != NULL )
		{
			dst = work;
		}
		else
		{
			return False;
		}
	}

	pDst = dst.GetPtr();
	pDstEnd = pDst + dst.GetNum();

	while( pDst != pDstEnd )
	{
		if( *pDst == L'/' )
		{
			*pDst = L'\\';
		}

		pDst++;
	}

	if( MIX_TESTBIT( flags, P_DIR ) == P_DIR )
	{
		wchar_t lastChar = dst[dst.GetNum() - 1];

		if( ( lastChar != L'\\' ) && ( lastChar != L'/' ) )
		{
			dst += L'\\';
		}
	}

	if( MIX_TESTBIT( flags, P_LOW ) == P_LOW )
	{
		dst.Lower();
	}

	return True;
}

Boolean Manager::Initialize( const wchar_t* pRootDirPath, const wchar_t* pUserDirPath )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ルートディレクトリ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( Mix::IO::CombinePath( NULL, False, pRootDirPath, m_RootDirectoryPath ) == False )
	{
		MIX_LOG_ERROR( L"%s : Mix::IO::CombinePath %s", FAILED_INITIALIZE, Mix::STR_RETERROR );
		return False;
	}

	if( Mix::IO::CombinePath( m_RootDirectoryPath.GetConstPtr(), True, L"\\", m_RootDirectoryPath ) == False )
	{
		return False;
	}

	m_RootDirectoryPath.Lower();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ユーザーディレクトリ ( マイドキュメント )
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( Mix::IO::GetSpecialDirectoryPath( Mix::IO::SPDIR_MYDOCUMENT, m_UserDirectoryPath ) == False )
	{
		MIX_LOG_ERROR( L"%s : マイドキュメントのパスを取得できません %s", FAILED_INITIALIZE );
		return False;
	}

	if( ( pUserDirPath != NULL ) && ( ::wcslen( pUserDirPath ) > 0 ) )
	{
		m_UserDirectoryPath += pUserDirPath;
	}
	else
	{
		m_UserDirectoryPath += Mix::DEF_USERDIRECTORYNAME;
	}

	if( Mix::IO::CombinePath( m_UserDirectoryPath.GetConstPtr(), False, L"\\", m_UserDirectoryPath ) == False )
	{
		return False;
	}

	m_UserDirectoryPath.Lower();

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return True;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::File::IManager
////////////////////////////////////////////////////////////////////////////////////////////////////

const wchar_t* Manager::GetRootDirectoryPath( void ) const
{
	return m_RootDirectoryPath.GetConstPtr();
}

const wchar_t* Manager::GetUserDirectoryPath( void ) const
{
	return m_UserDirectoryPath.GetConstPtr();
}

}}
