#pragma once

#include "ActionInvoker.hpp"

/*!
 * プロセスを起動するアクションの抽象クラス。
 * 起動パラメータの展開、プロセスハンドルの管理、同時実行の判定等を行います。
 */
class AbstractProcessExecActionInvoker
	: public ActionInvoker
{
private:
	AbstractProcessExecActionInvoker(const AbstractProcessExecActionInvoker&); //<! 実装なし
	AbstractProcessExecActionInvoker& operator=(const AbstractProcessExecActionInvoker&); //<! 実装なし

private:

	/*!
	 * 監視するプロセスハンドルと、それに関連するターゲットファイル
	 */
	typedef std::map<HANDLE, tstring> ProcessHandleMap;

	ProcessHandleMap processHandleMap_;

protected:

	DWORD runCount_;

public:
	AbstractProcessExecActionInvoker(const CSettingInfo& v_settingInfo);

	virtual ~AbstractProcessExecActionInvoker() = 0;

	virtual bool canDoAction() throw();

	virtual unsigned int sweepGarbage() throw();

	virtual void Reset();

	virtual void Load(CObjectReader &reader);

	virtual void Save(CObjectWriter &writer);

	/*!
	 * アクションを実行します。
	 * アクションの最大数を超えているかは判定されないため、
	 * 呼び出しもとで適宜にcanDoActionでチェックする必要があります。
	 * \param v_absolutePath ターゲットファイルの絶対パス
	 * \param fileInfo 監視ファイル情報
	 */
	virtual bool doAction(const tstring& v_absolutePath, const CFileInfo& fileInfo) throw();

protected:

	/*!
	 * 指定したターゲットファイルと、それに関連するプロセスハンドルを指定して
	 * プロセスの終了を監視する。
	 * \param v_hProcess プロセスハンドル
	 * \param v_absolutePath ターゲットファイル
	 */
	virtual void addTraceProcessHandle(HANDLE v_hProcess, const tstring& v_absolutePath) throw();

	/*!
	 * 指定したターゲットファイルに関連するプロセスが監視中であるか?
	 * \param ターゲットファイル
	 * \return 監視中であればtrue、そうでなければfalse
	 */
	virtual bool isWatchedProcess(const tstring& v_absolutePath) const throw();

	/*!
	 * 特殊変数COUNTの展開に使用する総実行回数を取得ます。
	 * \return 総実行回数
	 */
	virtual DWORD internalGetRunCount();
};


/*!
 * ShellExecuteExでプロセスを起動するアクション
 */
class ShellExecActionInvoker
	: public AbstractProcessExecActionInvoker
{
private:
	ShellExecActionInvoker(const ShellExecActionInvoker&); //<! 実装なし
	ShellExecActionInvoker& operator=(const ShellExecActionInvoker&); //<! 実装なし

public:
	ShellExecActionInvoker(const CSettingInfo& v_settingInfo);

	virtual ~ShellExecActionInvoker() throw();

protected:
	/*!
	 * プロセスの実行
	 * \param v_absoluePath ターゲットの絶対パス
	 * \param v_fileInfo ターゲットのファイル情報
	 * \param verb アクションタイプ
	 * \param appName アプリケーション名(展開済み)
	 * \param param パラメータ(展開済み)
	 * \param appCurrentDir カレントディレクトリ(展開済み)
	 */
	virtual bool internalDoAction(
		const tstring v_absolutePath,
		const CFileInfo& v_fileInfo,
		const tstring& verb,
		const tstring& appName, 
		const tstring& param,
		const tstring& appCurrentDir) throw();
};

/*!
 * CreateProcessAsLogonでプロセスを起動するアクション
 */
class CreateProcessAsLogonActionInvoker
	: public AbstractProcessExecActionInvoker
{
private:
	enum VERB_TYPE
	{
		VERB_PROCESS = 1,
		VERB_RUN_AS_USER,
		VERB_RUN_AS_USER_WITH_PROFILE
	};

	VERB_TYPE verbType_;

	CreateProcessAsLogonActionInvoker(const CreateProcessAsLogonActionInvoker&); //<! 実装なし
	CreateProcessAsLogonActionInvoker& operator=(const CreateProcessAsLogonActionInvoker&); //<! 実装なし

public:
	CreateProcessAsLogonActionInvoker(const CSettingInfo& v_settingInfo);

	virtual ~CreateProcessAsLogonActionInvoker() throw();

protected:
	/*!
	 * プロセスの実行
	 * \param v_absoluePath ターゲットの絶対パス
	 * \param v_fileInfo ターゲットのファイル情報
	 * \param verb アクションタイプ
	 * \param appName アプリケーション名(展開済み)
	 * \param param パラメータ(展開済み)
	 * \param appCurrentDir カレントディレクトリ(展開済み)
	 */
	virtual bool internalDoAction(
		const tstring v_absolutePath,
		const CFileInfo& v_fileInfo,
		const tstring& verb,
		const tstring& appName, 
		const tstring& param,
		const tstring& appCurrentDir) throw();
};
