#include "stdafx.h"
#include "FWatchApp.hpp"
#include "resource.h"

#include "SettingInfoFactory.hpp"

#include "ImpersonateUser.hpp"
#include "NameMatcher.hpp"
#include "Utility.hpp"

#include <assert.h>

#pragma warning( disable : 4290 )


CSettingInfoFactory::CSettingInfoFactory()
	: pErrorInfoListener_(NULL)
{
}

CSettingInfoFactory::CSettingInfoFactory(const CSettingInfo& v_settingInfo)
	: info_(v_settingInfo)
	, pErrorInfoListener_(NULL)
{
}

CSettingInfoFactory::CSettingInfoFactory(const CSettingInfoFactory& v_other)
	: info_(v_other.info_)
	, pErrorInfoListener_(v_other.pErrorInfoListener_)
{
}

CSettingInfoFactory& CSettingInfoFactory::operator=(const CSettingInfoFactory& v_other)
{
	if (this == &v_other) {
		return *this;
	}

	info_ = v_other.info_;
	pErrorInfoListener_ = v_other.pErrorInfoListener_;

	return *this;
}

CSettingInfoFactory::~CSettingInfoFactory()
{
}

void CSettingInfoFactory::setErrorInfoListener(ErrorInfoListener* v_pErrorInfoListener) throw()
{
	pErrorInfoListener_ = v_pErrorInfoListener;
}

bool CSettingInfoFactory::validate(const bool v_silent) const
{
	bool result = true;

	// ファイルが落ち着くまで待機する時間が妥当か?
	if (info_.nWaitWrite_ <= 0) {
		result = false;
		if ( ! v_silent) {
			notifyErrorInfo(app.LoadString(IDS_SETTINGMES_WAITTIME));
		}
	}

	// 監視ディレクトリが空でないか?
	if (info_.watchDir_.empty()) {
		result = false;
		if ( ! v_silent) {
			notifyErrorInfo(app.LoadString(IDS_SETTINGMES_NEEDFOLDER));
		}
	}

	// 監視通知APIを使用しない場合は定期フォルダチェックが有効であるか?
	if ( !info_.bUsingNotificationAPI_ && info_.nForceInterval_ == 0) {
		result = false;
		if ( !v_silent) {
			notifyErrorInfo(app.LoadString(IDS_SETTINGMES_UNSETDIRNOTIFICATION));
		}
	}

	// ユーザの偽装を使用する場合は偽装ユーザが指定されているか?
	if (info_.impersonate_) {
		if (info_.impersonateUser_.empty()) {
			result = false;
			if ( !v_silent) {
				notifyErrorInfo(app.LoadString(IDS_SETTINGMES_IMPERSONATEUSER_REQUIRED));
			}
		}
		else if ( !v_silent) {
			CImpersonateUser checkLogon;
			try {
				checkLogon.logon(
					info_.impersonateUser_.c_str(),
					info_.impersonateDomain_.c_str(),
					info_.impersonatePassword_.c_str()
					);
			}
			catch (const CImpersonateUserException& exception) {
				DWORD err = exception.GetErrorCode();
				result = false;
				notifyErrorInfo(ToErrorMessage(err));
			}
		}
	}
	

	return result;
}

CSettingInfo CSettingInfoFactory::create() const throw(CSettingInfoFactoryException)
{
	if ( !validate(true)) {
		throw CSettingInfoFactoryException("構築パラメータが不正なためオブジェクトを作成することはできません。");
	}
	return info_;
}

/*!
 * リスナにエラーを通知します。
 * リスナはエラーを受け入れて修正することを望む場合はtrueを返すことができます。
 * この場合、このメソッドもtrueを返します。
 * リスナが登録されていない場合は常にfalseを返します。
 * \param エラーメッセージ
 * \return エラーを修正し続行する場合、true
 */
bool CSettingInfoFactory::notifyErrorInfo(const tstring& v_errorInfo) const
{
	if (pErrorInfoListener_ != NULL) {
		return pErrorInfoListener_->notifyErrorInfo(v_errorInfo);
	}
	return false;
}

void CSettingInfoFactory::setWatchDir(const tstring& v_watchDir)
{
	info_.watchDir_ = StrTrim(v_watchDir);
	if ( !info_.watchDir_.empty()) {
		info_.watchDir_ = EnsureLast(info_.watchDir_, _T("\\"));
	}
}

void CSettingInfoFactory::setWatchFile(const tstring& v_watchFile)
{
	info_.watchFile_ = StrTrim(v_watchFile);
	CNameMatcher matcher(info_.watchFile_, false);
	if (matcher.empty()) {
		// ファイル名の指定がない場合は全マッチにする
		info_.watchFile_ = _T("*");

	} else {
		// スキップされたファイル名を除去するために再構築する.
		info_.watchFile_ = matcher.str();
	}
}

void CSettingInfoFactory::setAction(const tstring& v_action)
{
	info_.action_ = StrTrim(v_action);
	if (info_.action_.empty()) {
		info_.action_ = _T("OPEN");
	}
}

void CSettingInfoFactory::setAppName(const tstring& v_appName)
{
	info_.appName_ = StrTrim(v_appName);
}

void CSettingInfoFactory::setParam(const tstring& v_param)
{
	info_.param_ = StrTrim(v_param);
}

void CSettingInfoFactory::setLog(const tstring& v_log)
{
	info_.log_ = StrTrim(v_log);
}

void CSettingInfoFactory::setWaitWrite(const int v_waitWrite)
{
	if (v_waitWrite < 1 && ! notifyErrorInfo(app.LoadString( IDS_SETTINGMES_WAITTIME))) {
		return;
	}
	info_.nWaitWrite_ = (v_waitWrite < 1) ? 1 : v_waitWrite;
}

void CSettingInfoFactory::setMaxProcess(const unsigned int v_nMaxProcess)
{
	info_.nMaxProcess_ = (v_nMaxProcess < 0) ? 0 : v_nMaxProcess;
}

void CSettingInfoFactory::setShowWindow(const ShowWindowType& v_showWindow)
{
	info_.showWindow_ = v_showWindow;
}

void CSettingInfoFactory::setTolerance(const int v_nTolerance)
{
	info_.nTolerance_ = (v_nTolerance < 0) ? 0 : v_nTolerance;
}

void CSettingInfoFactory::setDeletePending(const int v_deletePending)
{
	info_.nDeletePending_ = (v_deletePending < 0) ? 0 : v_deletePending;
}

void CSettingInfoFactory::setMaxDepth(const int v_maxDepth)
{
	info_.nMaxDepth_ = (v_maxDepth < 0) ? 0 : v_maxDepth;
}

void CSettingInfoFactory::setForceInterval( const int v_forceInterval )
{
	if (v_forceInterval <= 0 && !info_.bUsingNotificationAPI_) {
		if ( !notifyErrorInfo(app.LoadString(IDS_SETTINGMES_UNSETDIRNOTIFICATION))) {
			return;
		}
	}
	// 念のため監視APIを使わずにインターバルも使わない場合はインターバルを180に設定する。(気休め)
	info_.nForceInterval_ = (v_forceInterval <= 0) ? (info_.bUsingNotificationAPI_ ? 0 : 180) : v_forceInterval;
}

void CSettingInfoFactory::setUsingDirNotificationAPI(const bool v_usingDirNotificationAPI)
{
	if( ! v_usingDirNotificationAPI && info_.nForceInterval_ <= 0 ) {
		if( ! notifyErrorInfo( app.LoadString( IDS_SETTINGMES_UNSETDIRNOTIFICATION ) ) ) {
			return;
		}
		info_.nForceInterval_ = 180;
	}
	info_.bUsingNotificationAPI_ = v_usingDirNotificationAPI;
}

void CSettingInfoFactory::setDirNotificationAPIRetryInterval(const int v_dirNotificationAPIRetryInterval)
{
	info_.nDirNotificationAPIRetryInterval_ = (v_dirNotificationAPIRetryInterval < 0) ? 0 : v_dirNotificationAPIRetryInterval;
}

void CSettingInfoFactory::setDirNotificationAPIExpirySpan(const int v_dirNotificationAPIExpirySpan)
{
	info_.nDirNotificationAPIExpirySpan_ = (v_dirNotificationAPIExpirySpan < 0) ? 0 : v_dirNotificationAPIExpirySpan;
}

void CSettingInfoFactory::setLogLevel(const int v_logLevel)
{
	info_.logLevel_ = (v_logLevel < 0) ? 0 :v_logLevel;
}

void CSettingInfoFactory::setAppCurrentDir(const tstring& v_appCurrentDir)
{
	info_.appCurrentDir_ = StrTrim(v_appCurrentDir);
}

void CSettingInfoFactory::setPersist(const tstring& v_persist)
{
	info_.persist_ = StrTrim(v_persist);
}

void CSettingInfoFactory::setArchiveOnly(const bool v_archiveOnly) throw()
{
	info_.archiveOnly_ = v_archiveOnly;
}

void CSettingInfoFactory::setNotifyOnStart(const bool v_notifyOnStart) throw()
{
	info_.notifyOnStart_ = v_notifyOnStart;
}

void CSettingInfoFactory::setWatchDelay(const int v_watchDelay) throw()
{
	info_.nWatchDelay_ = v_watchDelay;
}

void CSettingInfoFactory::setIgnoreDuplicate(const bool v_ignoreDuplicate) throw()
{
	info_.ignoreDuplicate_ = v_ignoreDuplicate;
}

void CSettingInfoFactory::setImpersonate(const bool v_impersonate) throw()
{
	info_.impersonate_ = v_impersonate;
}

void CSettingInfoFactory::setImpersonateUser(const tstring& v_impersonateUser) throw()
{
	info_.impersonateUser_ = StrTrim(v_impersonateUser);
}

void CSettingInfoFactory::setImpersonateDomain(const tstring& v_impersonateDomain) throw()
{
	info_.impersonateDomain_ = StrTrim(v_impersonateDomain);
}

void CSettingInfoFactory::setImpersonatePassword(const tstring& v_impersonatePassword) throw()
{
	info_.impersonatePassword_ = StrTrim(v_impersonatePassword);
}

void CSettingInfoFactory::setWatchDisabled(const bool v_watchDisabled) throw()
{
	info_.watchDisabled_ = v_watchDisabled;
}
