#include"CRegistry.h"
#include"../Debug/CAssert.h"

#include"../CString.h"


namespace Maid
{

/*!
 	@class CRegistry CRegistry.h
 	@brief レジストリキーを取得・作成するクラス
 
 		すでにキーが存在しているときは上書きします
 */

inline HKEY ConvertKey( CRegistry::KEY k )
{
	HKEY hKey;

	switch( k )
	{
	case CRegistry::KEY_CLASSES_ROOT:	{ hKey = HKEY_CLASSES_ROOT; }break;
	case CRegistry::KEY_CURRENT_USER:	{ hKey = HKEY_CURRENT_USER; }break;
	case CRegistry::KEY_LOCAL_MACHINE:	{ hKey = HKEY_LOCAL_MACHINE; }break;
	case CRegistry::KEY_USERS:			{ hKey = HKEY_USERS; }break;
	default: { MAID_ASSERT( true, "範囲外のキーです" ); } break;
	}
	return hKey;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! コンストラクタ
/*!	
 *
 */
CRegistry::CRegistry()
{
	m_hKey = NULL;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! デストラクタ
/*!	
 *
 */
CRegistry::~CRegistry()
{
	Close();
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レジストリキーを開く
/*!	
 
 	@param	hKey	[i ]	大元のキー
 	@param	SubKey	[i ]	サブキーの名前
 
	@exception CException オープンに失敗した場合
 */
void CRegistry::Open( CRegistry::KEY hKey, const mstring& SubKey )
{
	Close();

	const MySTL::string sjis_sub = CString::ConvertMAIDtoSJIS(SubKey);

	if( ::RegOpenKeyEx( ConvertKey(hKey), sjis_sub.c_str(), 0, KEY_ALL_ACCESS, &m_hKey )!=ERROR_SUCCESS ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegOpenKeyEx()"));
	}
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レジストリキーを作成、開く
/*!	
 
 	@param	hKey	[i ]	大元のキー
 	@param	SubKey	[i ]	サブキーの名前
 
	@exception CException	キーを作成して、オープンに失敗した場合
									キーが存在していて、オープンに失敗した場合
 */
void CRegistry::Create( CRegistry::KEY hKey, const mstring& SubKey )
{
	Close();
	const MySTL::string sjis_sub = CString::ConvertMAIDtoSJIS(SubKey);

	DWORD ret=0;

	const LONG code = ::RegCreateKeyEx( ConvertKey(hKey), sjis_sub.c_str(), 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &m_hKey, &ret );
	if( code!=ERROR_SUCCESS )
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegCreateKeyEx()"));
	}
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! DWORD 値をセットする
/*!	
 
 	@param	Name	[i ]	作成する名前
 	@param	Data	[i ]	セットする値
 
	@exception CException 関数の失敗時
 */
void CRegistry::SetValue( const mstring& Name, unt32 Data )
{
	MAID_ASSERT( m_hKey==NULL, "キーを開いていません" );
	if( m_hKey==NULL ) { return ; }

	const MySTL::string sjis_name = CString::ConvertMAIDtoSJIS(Name);
	if( ::RegSetValueEx( m_hKey, sjis_name.c_str(), 0, REG_DWORD, (BYTE*)&Data, sizeof(Data) )!=ERROR_SUCCESS ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegSetValueEx()"));
	}
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 値をセットする
/*!	
 
 	@param	Name	[i ]	作成する名前
 	@param	Data	[i ]	セットする文字列
 
	@exception CException 関数の失敗時
 */
void CRegistry::SetValue( const mstring& Name, const mstring& Data )
{
	MAID_ASSERT( m_hKey==NULL, "キーを開いていません" );
	if( m_hKey==NULL ) { return ; }

	const MySTL::string sjis_name = CString::ConvertMAIDtoSJIS(Name);
	const MySTL::string sjis_data = CString::ConvertMAIDtoSJIS(Data);
	if( ::RegSetValueEx( m_hKey, sjis_name.c_str(), 0, REG_SZ, (BYTE*)sjis_data.c_str(), (DWORD)sjis_data.length()+1 )!=ERROR_SUCCESS ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegSetValueEx()"));
	}
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 値をセットする
/*!	
 
 	@param	Name	[i ]	作成する名前
 	@param	pData	[i ]	セットするバイナリデータ
 	@param	Length	[i ]	_pData の長さ
 
	@exception CException 関数の失敗時
 */
void CRegistry::SetValue( const mstring& Name, const void* pData, unt32 Length )
{
	MAID_ASSERT( m_hKey==NULL, "キーを開いていません" );
	if( m_hKey==NULL ) { return ; }

	const MySTL::string sjis_name = CString::ConvertMAIDtoSJIS(Name);
	if( ::RegSetValueEx( m_hKey, sjis_name.c_str(), 0, REG_BINARY, (BYTE*)pData, Length+1 )!=ERROR_SUCCESS )
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegSetValueEx()"));
	}
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! DWORD 値を取得する
/*!	
 
 	@param	Name	[i ]	取得する名前
 	@param	Data	[ o]	取得するDWORD値
 
	@exception CException 関数の失敗時
 */
void CRegistry::GetValue( const mstring& Name, unt32& Data )
{
	MAID_ASSERT( m_hKey==NULL, "キーを開いていません" );
	if( m_hKey==NULL ) { return ; }

	DWORD	dwKeyType;
	DWORD	dwKeyData;
	DWORD	dwKeyBuffLen = 4;
	const MySTL::string sjis_name = CString::ConvertMAIDtoSJIS(Name);

	if( ::RegQueryValueEx( m_hKey, sjis_name.c_str(), NULL, &dwKeyType, (BYTE*)&dwKeyData, &dwKeyBuffLen )!=ERROR_SUCCESS )
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegQueryValueEx()"));
	}

	if( dwKeyType!=REG_DWORD ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("dwKeyType!=REG_DWORD"));
	}
	Data = dwKeyData;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 文字列 値を取得する
/*!	
 
 	@param	Name	[i ]	取得する名前
 	@param	Data	[ o]	取得する文字列
 
	@exception CException 関数の失敗時
 */
void CRegistry::GetValue( const mstring& Name, mstring& Data )
{
	MAID_ASSERT( m_hKey==NULL, "キーを開いていません" );
	if( m_hKey==NULL ) { return ; }


	const MySTL::string sjis_name = CString::ConvertMAIDtoSJIS(Name);

	DWORD	dwKeyType;
	DWORD	dwKeyBuffLen=0;

	if( ::RegQueryValueEx( m_hKey, sjis_name.c_str(), NULL, &dwKeyType, NULL, &dwKeyBuffLen )!=ERROR_SUCCESS )
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegQueryValueEx()"));
	}
	if( dwKeyType!=REG_SZ )
	{
		MAID_THROWEXCEPTION(MAIDTEXT("dwKeyType!=REG_SZ"));
	}

	MySTL::string s;
	s.resize(dwKeyBuffLen-1);

	if( ::RegQueryValueEx( m_hKey, sjis_name.c_str(), NULL, &dwKeyType, (BYTE*)s.data(), &dwKeyBuffLen )!=ERROR_SUCCESS )
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegQueryValueEx()"));
	}

	Data = CString::ConvertSJIStoMAID(s);
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! バイナリデータ 値を取得する
/*!	
 
 	@param	Name	[i ]	取得する名前
 	@param	pData	[ o]	取得するバイナリデータ
 	@param	Length	[ o]	バイナリデータの長さ
 
	@exception CException 関数の失敗時
 */
void CRegistry::GetValue( const mstring& Name, boost::shared_array<unt08>& pData, unt32& Length )
{
	MAID_ASSERT( m_hKey==NULL, "キーを開いていません" );
	if( m_hKey==NULL ) { return ; }

	DWORD	dwKeyType;
	DWORD	dwKeyBuffLen=0;

	const MySTL::string sjis_name = CString::ConvertMAIDtoSJIS(Name);

	if( ::RegQueryValueEx( m_hKey, sjis_name.c_str(), NULL, &dwKeyType, NULL, &dwKeyBuffLen )!=ERROR_SUCCESS )
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegQueryValueEx()"));
	}
	if( dwKeyType!=REG_BINARY ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("dwKeyType!=REG_BINARY"));
	}

	pData.reset( new unt08[dwKeyBuffLen] );

	if( ::RegQueryValueEx( m_hKey, sjis_name.c_str(), NULL, &dwKeyType, pData.get(), &dwKeyBuffLen )!=ERROR_SUCCESS ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegQueryValueEx()"));
	}
	Length = dwKeyBuffLen;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 値を削除する
/*!	
 	@param	ValueName	[i ]	削除する値の名前
 
	@exception CException 関数の失敗時
 */
void CRegistry::DeleteValue( const mstring& ValueName )
{
	MAID_ASSERT( m_hKey==NULL, "キーを開いていません" );
	if( m_hKey==NULL ) { return ; }

	const MySTL::string sjis_name = CString::ConvertMAIDtoSJIS(ValueName);
	if( ::RegDeleteValue( m_hKey, sjis_name.c_str() )!=ERROR_SUCCESS ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegDeleteValue()"));
	}
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レジストリの操作を終了する
/*!	
 */
void CRegistry::Close()
{
	if( m_hKey!=NULL )
	{
		::RegCloseKey( m_hKey );
		m_hKey = NULL;
	}
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レジストリキーの削除
/*!	
 	@param	hKey	[i ]	削除したいキー
 	@param	SubKey	[i ]	削除したいサブキー
 
	@exception CException 削除の失敗時
 */
void CRegistry::DeleteKey( KEY hKey, const mstring& SubKey )
{
	const MySTL::string sjis_key = CString::ConvertMAIDtoSJIS(SubKey);
	if( ::RegDeleteKey( ConvertKey(hKey), sjis_key.c_str() )!=ERROR_SUCCESS ) 
	{
		MAID_THROWEXCEPTION(MAIDTEXT("RegDeleteKey()"));
	}
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レジストリの値の削除
/*!	
 	@param	hKey		[i ]	削除したいキー
 	@param	SubKey		[i ]	探すサブキー
 	@param	ValueName	[i ]	削除したい値
 
	@exception CException 削除の失敗時
 */
void CRegistry::DeleteValue( KEY hKey, const mstring& SubKey, const mstring& ValueName )
{
	CRegistry hReg;
	hReg.Open( hKey, SubKey );
	hReg.DeleteValue( ValueName );
}


}