#pragma once

#include <string>
#include <exception>

#include "Logger.hpp"


/*!
 * ユーザの偽装に関する例外
 */
class CImpersonateUserException
	: public std::exception
{
private:
	DWORD errcode_;

public:
	CImpersonateUserException(DWORD errorcode)
		: errcode_(errorcode)
	{
	}

	DWORD GetErrorCode() const
	{
		return errcode_;
	}
};


/*!
 * ログオンユーザを偽装します。
 */
class CImpersonateUser
{
private:

	/*!
	 * ユーザのトークン
	 */
	HANDLE userToken_;

	/*!
	 * 偽装中であるか?
	 */
	bool bImpersonate_;

	/*!
	 * ロガー
	 */
	Logger *pLogger_;

	/*!
	 * ユーザ
	 */
	tstring user_;

	/*!
	 * ドメイン
	 */
	tstring domain_;

public:

	CImpersonateUser();

	/*!
	 * 偽装されていれば偽装解除し、ログオンされていればログオフします。
	 * そうでなければ何もしません。
	 */
	~CImpersonateUser() throw();

	/*!
	 * ロガーを設定します。
	 * NULLの場合はロガーを解除します。
	 * \param pLogger ロガー、もしくはNULL
	 */
	void SetLogger(Logger *pLogger) throw()
	{
		pLogger_ = pLogger;
	}

	Logger* GetLogger() const
	{
		return pLogger_;
	}

	/*!
	 * ログオンします。
	 * すでにログオンされていてはなりません。
	 * ログインに失敗した場合はCImpersonateUserException例外が発生します。
	 * \param userName ユーザ名
	 * \param domain ドメイン、空可
	 * \param password パスワード、空可
	 */
	void logon(const tstring& userName, const tstring& domain, const tstring& password);

	/*!
	 * 偽装します。
	 * すでに偽装されていてはなりません。
	 * 失敗した場合はCImpersonateUserException例外が発生します。
	 */
	void impersonate() ;

	/*!
	 * 偽装を解除します。
	 * ログオンされていないか、偽装されていなければ何もせず、falseを返します。
	 * この場合GetLastError()はNO_ERRORを返します。
	 * 偽装解除に成功した場合はtrueを返します。
	 * 偽装解除できない場合はfalseを返し、GetLastError()でエラーコードを取得できます。
	 * \return 偽装解除された場合はtrue、偽装されていないか、解除に失敗した場合はfalse
	 */
	bool revertToSelf() throw();

	/*!
	 * ログオフします。
	 * ログインされていなければ何もしません。
	 * 偽装されている場合は偽装が解除されます。
	 * ログオフされた場合はtrueを返します。
	 * ログオフできない場合はfalseを返し、GetLastError()でエラーコードを取得できます。
	 * \return ログオンされていないか、ログオフされた場合はtrue。ログオフできなかった場合はfalse
	 */
	bool logoff() throw();
};
