#pragma once

#include <map>
#include <list>
#include <string>

class Duplicator
{
private:
	struct FILE_INFO
	{
		std::wstring name;
		FILETIME time;

		FILE_INFO( const std::wstring& _name, const FILETIME& _time )
		{
			name = _name;
			time = _time;
		}
	};

	struct DIR_INFO
	{
		std::wstring key;
		std::wstring name;

		DIR_INFO( const std::wstring& _key )
		{
			key = _key;
			name = L"";
		}

		DIR_INFO( const std::wstring& _key, const std::wstring& _name )
		{
			key = _key;
			name = _name;
		}

		bool operator == ( const DIR_INFO& info ) const
		{
			return ( key == info.key );
		}

		bool operator != ( const DIR_INFO& info ) const
		{
			return ( key != info.key );
		}
	};

	struct EXCL_DIR_INFO
	{
		std::wstring key;
		bool bFileOnly;
	};

	enum EXCL_DIR_RESULT
	{
		EDR_OK				= 0,	//ディレクトリを除外しない
		EDR_EXCLUDE_FILE	= -1,	//ディレクトリ内のファイルのみ除外( ディレクトリは作成する )
		EDR_EXCLUDE			= -2,	//ディレクトリを除外( ファイルもコピーされない )
	};

	struct EXCL_FILE_INFO
	{
		std::wstring key;
		bool bNameOnly;
	};

	typedef std::map<std::wstring, Duplicator::FILE_INFO> FileInfoMap;
	typedef std::list<Duplicator::DIR_INFO> DirectoryInfoList;
	typedef std::list<Duplicator::EXCL_DIR_INFO> DirectoryList;
	typedef std::list<Duplicator::EXCL_FILE_INFO> FileList;
	typedef std::list<std::wstring> FileExtList;

private:
	std::wstring m_SourceDirectoryPath;
	std::wstring m_TargetDirectoryPath;

	Duplicator::DirectoryList m_ExcludeDirectoryList;
	Duplicator::FileList m_ExcludeFileList;
	Duplicator::FileExtList m_ExcludeFileExtList;

public:
	Duplicator( void );

public:
	void SetSourceDirectory( const wchar_t* pDirPath );
	const wchar_t* GetSourceDirectory( void ) const;

	void SetTargetDirectory( const wchar_t* pDirPath );
	const wchar_t* GetTargetDirectory( void ) const;

	void AddExcludeDirectory( const wchar_t* pDirPath, bool bFileOnly );
	void AddExcludeFile( const wchar_t* pFilePath, bool bNameOnly );
	void AddExcludeFileExt( const wchar_t* pFileExt );

	bool IsAvailable( void ) const;

	bool Execute( void );

private:
	static void ModifyPath( bool bDirectory, bool bAppend, const wchar_t* pSource, std::wstring& target );
	static void SetDirectoryName( const wchar_t* pSource, std::wstring& target );
	static bool TrashFile( const std::wstring& fileName );
	static bool DeleteDirectory( const std::wstring& dirName );
	static wchar_t PathToKey( wchar_t ch );

	bool CreateFileInfoMap( const std::wstring& baseDirName, const std::wstring& dirName, Duplicator::FileInfoMap& fileInfoMap, Duplicator::DirectoryInfoList& dirNameList, bool bExclude );

	Duplicator::EXCL_DIR_RESULT IsExcludeDirectory( const wchar_t* pDirName );
	bool IsExcludeFile( const wchar_t* pKey );
};
