#pragma once

#include "FileInfo.hpp"
#include "SettingInfo.hpp"

#include "Logger.hpp"
#include "ObjectReaderWriter.hpp"
#include "StringExpander.hpp"

#include <string>
#include <map>
#include <memory>


/*!
 * アクションの実行状態を永続化するためのインターフェイス
 */
class ActionInvokerData
{
public:
	virtual ~ActionInvokerData() throw() = 0 {};

	/*!
	 * 永続化状態をリセットします。
	 */
	virtual void Reset() = 0;

	/*!
	 * 永続化状態を読み込みます。
	 * \param reader オブジェクトリーダ
	 */
	virtual void Load(CObjectReader &reader) = 0;

	/*!
	 * 永続化状態を保存します。
	 * \param writer オブジェクトライタ
	 */
	virtual void Save(CObjectWriter &writer) = 0;
};


/*!
 * アクションを実行します。
 */
class ActionInvoker
	: public ActionInvokerData
{
protected:

	/*!
	 * ロガー、設定されていなければnull
	 */
	Logger* pLogger_;

	/*!
	 * 監視設定
	 */
	const CSettingInfo& settingInfo_;

private:
	ActionInvoker(const ActionInvoker&); //<! 実装なし
	ActionInvoker& operator=(const ActionInvoker&); //<! 実装なし

public:

	/*!
	 * 監視設定を指定してアクションを構築します。
	 * \param 監視設定
	 */
	ActionInvoker(const CSettingInfo& v_settingInfo) throw();
	
	/*!
	 * デストラクタ
	 */
	virtual ~ActionInvoker() throw();

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

	/*!
	 * アクションが実行可能かチェックします。
	 * \return 最大数が指定されていないか、最大数を超えていなければtrue
	 */
	virtual bool canDoAction() throw() = 0;

	/*!
	 * ガベージコレクトします。
	 *終了済みのプロセス等をチェックするために定期的に呼び出す必要があります。
	 */
	virtual unsigned int sweepGarbage() throw() = 0;

public:

	/*!
	 * ロガーを設定します。
	 * \param pLogger ロガー、もしくはnull
	 */
	virtual void setLogger(Logger* pLogger) throw();

	/*!
	 * 現在のロガーを取得します。
	 * \return ロガー、もしくはnull
	 */
	virtual Logger* getLogger() const throw();

protected:

	/*!
	 * プロセス実行パラメータの調整。
	 * アクションに応じて特殊変数・環境変数の展開し、非印字文字列を補正するなどを行う。
	 * \param expander 置換変数の展開
	 * \param v_absolutePath 絶対パス
	 * \param fileInfo ファイル情報
	 * \param verb アクションタイプを保存する
	 * \param appName アプリケーションを保存する
	 * \param param パラメータを保存する。
	 * \param appCurrentDir カレントディレクトリを保存する。
	 */
	virtual void adjustParameters(
		PropertyStringExpander expander,
		const tstring &v_absoluePath,
		const CFileInfo &fileInfo,
		tstring& verb,
		tstring& appName, 
		tstring& param,
		tstring& appCurrentDir) throw();

	/*!
	 * プロセスの実行
	 * \param v_absoluePath ターゲットの絶対パス
	 * \param v_fileInfo ターゲットのファイル情報
	 * \param verb アクションタイプ
	 * \param appName アプリケーション名(展開済み)
	 * \param param パラメータ(展開済み)
	 * \param appCurrentDir カレントディレクトリ(展開済み)
	 * \return 実行されればtrue、そうでなければfalse
	 */
	virtual bool internalDoAction(
		const tstring v_absolutePath,
		const CFileInfo& v_fileInfo,
		const tstring& verb,
		const tstring& appName, 
		const tstring& param,
		const tstring& appCurrentDir) throw() = 0;

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

/*!
 * アクションの自動ポインタ
 */
typedef std::auto_ptr<ActionInvoker> ActionInvokerPtr;


/*!
 * 監視設定のアクションタイプから、アクションの実装を構築するためのファクトリ
 */
class ActionInvokerFactory
{
private:
	ActionInvokerFactory(const ActionInvokerFactory&); //<! 実装なし
	ActionInvokerFactory& operator=(const ActionInvokerFactory&); //<! 実装なし

public:

	/*!
	 * ファクトリを構築します。
	 */
	ActionInvokerFactory();

	/*!
	 * デストラクタ
	 */
	virtual ~ActionInvokerFactory() throw();

	/*!
	 * 監視設定のアクション設定からアクション実装を構築して返します。
	 * \param v_settingInfo 監視設定
	 */
	virtual ActionInvokerPtr create(const CSettingInfo& v_settingInfo) const;
};
