Imports System.Collections.Generic

Namespace System
Namespace IO

Class DirectoryInfo
	Inherits FileSystemInfo
Public
	/*!
	@brief	コンストラクタ
	@author	OverTaker
	@date	2007/11/11
	@param	ディレクトリのパス
	*/
	Sub DirectoryInfo(path As String)
		OriginalPath = path
		FullPath = Path.GetFullPath(path)
	End Sub

	Sub ~DirectoryInfo()
	End Sub

	'----------------------------------------------------------------
	' パブリック プロパティ
	'----------------------------------------------------------------

	/*!
	@brief	ひとつ上のディレクトリを取得する
	@author	OverTaker
	@date	2007/11/11
	@return	親ディレクトリ
	*/
	Function Parent() As DirectoryInfo
		Return New DirectoryInfo(Path.GetDirectoryName(FullPath))
	End Function

	/*!
	@brief	ルートディレクトリを取得する
	@author	OverTaker
	@date	2007/11/11
	@return	ルートディレクトリ
	*/
	Function Root() As DirectoryInfo
		Return New DirectoryInfo(Path.GetPathRoot(FullPath))
	End Function

	'----------------------------------------------------------------
	' パブリック メソッド
	'----------------------------------------------------------------

	/*!
	@brief	ディレクトリを作成する
	@author	OverTaker
	@date	2007/11/11
	*/
	Sub Create()
		If CreateDirectory(ToTCStr(FullPath), NULL) = False Then
			Dim error = GetLastError()
			Select Case error
				Case ERROR_ALREADY_EXISTS
					Throw New IOException("DirectoryInfo.CreateDirectory: The directory has already existed.")
				Case Else
					Throw New IOException("DirectoryInfo.CreateDirectory: Failed to CreateDirectory")
			End Select
		End If
	End Sub

/*	Sub Create(directorySecurity As DirectorySecurity)
	End Sub*/

	/*!
	@brief	ディレクトリを削除する。ただしディレクトリが空の場合
	@author	OverTaker
	@date	2007/11/11
	*/
	Override Sub Delete()
		RemoveDirectory(ToTCStr(FullPath))
	End Sub

	/*!
	@brief	ディレクトリを削除する
	@author	OverTaker
	@date	2007/11/11
	@param	ディレクトリのファイルごと消すかどうか
	*/
	Sub Delete(recursive As Boolean)
		If recursive Then
			' ディレクトリ内のすべての情報を削除する

			Dim dirPath = FullPath As String

			' 終端の '\' を除去
			If dirPath[dirPath.Length-1] = Asc("\") Then
				dirPath = dirPath.Substring(0, dirPath.Length-1)
			End If

			' double null-terminated にする
			dirPath = dirPath + Chr$(0)

			Dim op As SHFILEOPSTRUCT
			op.hwnd = NULL
			op.wFunc = FO_DELETE
			op.pFrom = ToTCStr(dirPath)
			op.pTo = NULL
			op.fFlags = FOF_NOCONFIRMATION or FOF_NOERRORUI or FOF_SILENT

			If SHFileOperation(op) <> 0 Then
				Throw New IOException("DirectoryInfo.Delete: Failed to SHFileOperation.")
			End If
		Else
			' ディレクトリが空の場合は削除する
			This.Delete()
		End If
	End Sub

/*	Function GetAccessControl() As DirectorySecurity
	End Function*/

/*	Function GetAccessControl(includeSections As AccessControlSections) As DirectorySecurity
	End Function*/

	/*!
	@brief	ディレクトリの中にあるディレクトリを取得する
	@author	OverTaker
	@date	2007/11/11
	@return	ディレクトリの配列
	*/
	Function GetDirectories() As List<DirectoryInfo>
		Return GetDirectories("?*")
	End Function

	/*!
	@brief	ディレクトリの中にあるディレクトリを取得する
	@author	OverTaker
	@date	2007/11/11
	@param	サーチするディレクトリ名のパターン
	@return	パターンに適合したディレクトリの配列
	*/
	Function GetDirectories(searchPattern As String) As List<DirectoryInfo>
		Dim infos As List<FileSystemInfo>
		infos = GetFileSystemInfos(searchPattern)

		Dim dirs As List<DirectoryInfo>
		Dim i As Long
		For i = 0 To ELM(infos.Count)
			If (infos[i].Attributes and FileAttributes.Directory) = FileAttributes.Directory Then
				dirs.Add(infos[i] As DirectoryInfo)
			End If
		Next
		Return dirs
	End Function

	/*!
	@brief	ディレクトリの中にあるディレクトリを取得する
	@author	OverTaker
	@date	2007/11/11
	@param	サーチするディレクトリ名のパターン
	@param	サーチする範囲
	@return	サーチした範囲にあるパターンに適合したディレクトリの配列
	*/
	Function GetDirectories(searchPattern As String, searchOption As SearchOption) As List<DirectoryInfo>
		Select Case searchOption
			Case SearchOption.TopDirectoryOnly
				Return GetDirectories(searchPattern)
			Case SearchOption.AllDirectories
				Dim dirs As List<DirectoryInfo>
				dirs = GetDirectories(searchPattern)

				Dim subdirs As List<DirectoryInfo>
				Dim i As Long, j As Long
				For i = 0 To ELM(dirs.Count)
					subdirs = dirs[i].GetDirectories(searchPattern)
					For j = 0 To ELM(subdirs.Count)
						dirs.Add(subdirs[j])
					Next
				Next
				Return dirs
		End Select
	End Function

	/*!
	@brief	ディレクトリの中にあるファイルを取得する
	@author	OverTaker
	@date	2007/11/11
	@return	ファイルの配列
	*/
	Function GetFiles() As List<FileInfo>
		Return GetFiles("?*")
	End Function

	/*!
	@brief	ディレクトリの中にあるファイルを取得する
	@author	OverTaker
	@date	2007/11/11
	@param	サーチするファイル名のパターン
	@return	パターンに適合したファイルの配列
	*/
	Function GetFiles(searchPattern As String) As List<FileInfo>
		Dim infos As List<FileSystemInfo>
		infos = GetFileSystemInfos(searchPattern)

		Dim files As List<FileInfo>
		Dim i As Long
		For i = 0 To ELM(infos.Count)
			If (infos[i].Attributes and FileAttributes.Directory) <> FileAttributes.Directory Then
				files.Add(infos[i] As FileInfo)
			End If
		Next
		Return files
	End Function

	/*!
	@brief	ディレクトリの中にあるファイルを取得する
	@author	OverTaker
	@date	2007/11/11
	@param	サーチするファイル名のパターン
	@param	サーチする範囲
	@return	サーチした範囲にあるパターンに適合したディレクトリの配列
	*/
	Function GetFiles(searchPattern As String, searchOption As SearchOption) As List<FileInfo>
		Select Case searchOption
			Case SearchOption.TopDirectoryOnly
				Return GetFiles(searchPattern)
			Case SearchOption.AllDirectories
				Dim dirs As List<DirectoryInfo>
				dirs = GetDirectories("?*", SearchOption.AllDirectories)

				Dim files As List<FileInfo>
				files = GetFiles(searchPattern)
				Dim i As Long, j As Long, subfiles As List<FileInfo>
				For i = 0 To ELM(dirs.Count)
					subfiles = dirs[i].GetFiles(searchPattern)
					For j = 0 To ELM(subfiles.Count)
						files.Add(subfiles[j])
					Next
				Next
				Return files
		End Select
	End Function

	/*!
	@brief	ディレクトリの中にあるディレクトリやファイルを取得する
	@author	OverTaker
	@date	2007/11/11
	@return	ディレクトリやファイルの配列
	*/
	Function GetFileSystemInfos() As List<FileSystemInfo>
		Return GetFileSystemInfos("?*")
	End Function

	/*!
	@brief	ディレクトリの中にあるディレクトリやファイルを取得する
	@author	OverTaker
	@date	2007/11/11
	@param	サーチする名前のパターン
	@return	パターンに適合したディレクトリやファイルの配列
	*/
	Function GetFileSystemInfos(searchPattern As String) As List<FileSystemInfo>
		Dim find As HANDLE
		Dim findData As WIN32_FIND_DATA
		find = FindFirstFile(ToTCStr(Path.Combine(FullPath, searchPattern)), findData)
		If find = INVALID_HANDLE_VALUE Then
			Throw New IOException("DirectoryInfo.GetFileSystemInfos: Failed to FindFirstFile.")
			Return Nothing
		End If

		Dim files As List<FileSystemInfo>
		Do
			Dim s = New String(findData.cFileName As PCTSTR)
			If (findData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY Then
				files.Add(New DirectoryInfo(Path.Combine(FullPath, s)))
			Else
				files.Add(New FileInfo(Path.Combine(FullPath, s)))
			End If
		Loop While FindNextFile(find, findData)
		FindClose(find)

		files.Remove(New DirectoryInfo(Path.Combine(FullPath, ".")))
		files.Remove(New DirectoryInfo(Path.Combine(FullPath, "..")))

		If GetLastError() = ERROR_NO_MORE_FILES Then
			Return files
		Else
			Throw New IOException("DirectoryInfo.GetFileSystemInfos: Failed to FindNextFile.")
			Return Nothing
		End If
	End Function

	/*!
	@brief	ディレクトリを移動する
	@author	OverTaker
	@date	2007/11/11
	@param	移動先
	*/
	Sub MoveTo(destDirName As String)
		If MoveFile(ToTCStr(FullPath), ToTCStr(destDirName)) = FALSE Then
			Throw New IOException("DirectoryInfo.MoveTo: Failed to MoveFile.")
		End If
	End Sub

/*	Sub SetAccessControl(directorySecurity As DirectorySecurity)
	End Sub*/

End Class

End Namespace
End Namespace
