Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Threading

Namespace Nexamas.UI.FileSystem

    Friend NotInheritable Class LocalFileSystemProvider
        Implements IFileSystemProvider
        Implements IFileSystemCancellableProvider

        Public Function GetRoots() As List(Of FileSystemEntry) Implements IFileSystemProvider.GetRoots
            Return GetRoots(CancellationToken.None)
        End Function

        Public Function GetRoots(cancellationToken As CancellationToken) As List(Of FileSystemEntry) _
            Implements IFileSystemCancellableProvider.GetRoots

            Dim result As New List(Of FileSystemEntry)()

            Try
                cancellationToken.ThrowIfCancellationRequested()

                For Each d As DriveInfo In DriveInfo.GetDrives()
                    cancellationToken.ThrowIfCancellationRequested()

                    result.Add(New FileSystemEntry With {
                        .Name = d.Name,
                        .FullPath = d.Name,
                        .EntryType = FileSystemEntryType.Drive
                    })
                Next
            Catch masCanceled1 As OperationCanceledException
                Throw
            Catch masCaughtException1 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException1)
            End Try

            Return result
        End Function

        Public Function GetChildren(path As String) As List(Of FileSystemEntry) Implements IFileSystemProvider.GetChildren
            Return GetChildren(path, CancellationToken.None)
        End Function

        Public Function GetChildren(path As String, cancellationToken As CancellationToken) As List(Of FileSystemEntry) _
            Implements IFileSystemCancellableProvider.GetChildren

            Dim result As New List(Of FileSystemEntry)()

            If String.IsNullOrWhiteSpace(path) Then Return result

            Try
                cancellationToken.ThrowIfCancellationRequested()

                Dim di As New DirectoryInfo(path)
                If Not di.Exists Then Return result

                For Each dir As DirectoryInfo In di.EnumerateDirectories()
                    cancellationToken.ThrowIfCancellationRequested()

                    result.Add(New FileSystemEntry With {
                        .Name = dir.Name,
                        .FullPath = dir.FullName,
                        .EntryType = FileSystemEntryType.Folder,
                        .CreatedUtc = dir.CreationTimeUtc,
                        .ModifiedUtc = dir.LastWriteTimeUtc,
                        .IsHidden = ((dir.Attributes And FileAttributes.Hidden) = FileAttributes.Hidden),
                        .IsReadOnly = ((dir.Attributes And FileAttributes.ReadOnly) = FileAttributes.ReadOnly)
                    })
                Next

                For Each fi As FileInfo In di.EnumerateFiles()
                    cancellationToken.ThrowIfCancellationRequested()

                    result.Add(New FileSystemEntry With {
                        .Name = fi.Name,
                        .FullPath = fi.FullName,
                        .EntryType = FileSystemEntryType.FileItem,
                        .Extension = fi.Extension,
                        .SizeBytes = fi.Length,
                        .CreatedUtc = fi.CreationTimeUtc,
                        .ModifiedUtc = fi.LastWriteTimeUtc,
                        .IsHidden = ((fi.Attributes And FileAttributes.Hidden) = FileAttributes.Hidden),
                        .IsReadOnly = ((fi.Attributes And FileAttributes.ReadOnly) = FileAttributes.ReadOnly)
                    })
                Next
            Catch masCanceled2 As OperationCanceledException
                Throw
            Catch masCaughtException2 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException2)
            End Try

            Return result
        End Function

        Public Function DirectoryExists(path As String) As Boolean Implements IFileSystemProvider.DirectoryExists
            If String.IsNullOrWhiteSpace(path) Then Return False

            Try
                Return Directory.Exists(path)
            Catch masCaughtException3 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException3)
                Return False
            End Try
        End Function

        Public Function FileExists(path As String) As Boolean Implements IFileSystemProvider.FileExists
            If String.IsNullOrWhiteSpace(path) Then Return False

            Try
                Return File.Exists(path)
            Catch masCaughtException4 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException4)
                Return False
            End Try
        End Function

        Public Function GetParentPath(path As String) As String Implements IFileSystemProvider.GetParentPath
            If String.IsNullOrWhiteSpace(path) Then Return String.Empty

            Try
                Dim parentDir As DirectoryInfo = Directory.GetParent(path)
                If parentDir Is Nothing Then Return String.Empty
                Return parentDir.FullName
            Catch masCaughtException5 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException5)
                Return String.Empty
            End Try
        End Function

        Public Function CombinePath(basePath As String, childName As String) As String Implements IFileSystemProvider.CombinePath
            If String.IsNullOrWhiteSpace(basePath) Then Return childName
            If String.IsNullOrWhiteSpace(childName) Then Return basePath

            Try
                Return System.IO.Path.Combine(basePath, childName)
            Catch masCaughtException6 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException6)
                Return basePath
            End Try
        End Function

        Public Function NormalizePath(inputPath As String) As String Implements IFileSystemProvider.NormalizePath
            If String.IsNullOrWhiteSpace(inputPath) Then Return String.Empty

            Try
                Return System.IO.Path.GetFullPath(inputPath)
            Catch masCaughtException7 As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowFileSystemBoundary(masCaughtException7)
                Return inputPath
            End Try
        End Function

    End Class

End Namespace
