/// <summary>
        /// Enumerate the sub directories of this directory.
        /// </summary>
        /// <param name="searchPattern">The search string. The default pattern is "*", which returns all directories.</param>
        /// <param name="searchOption">One of the enumeration values that specifies whether the search operation should include only the current directory or all subdirectories. The default value is TopDirectoryOnly.</param>
        /// <exception cref="T:System.Net.WebException"></exception>
        /// <exception cref="T:Amazon.S3.AmazonS3Exception"></exception>
        /// <returns>An enumerable collection of directories that matches searchPattern and searchOption.</returns>
        public IEnumerable <S3DirectoryInfo> EnumerateDirectories(string searchPattern, SearchOption searchOption)
        {
            IEnumerable <S3DirectoryInfo> folders = null;

            if (String.IsNullOrEmpty(bucket))
            {
                var request = new ListBucketsRequest();
                ((Amazon.Runtime.Internal.IAmazonWebServiceRequest)request).AddBeforeRequestHandler(S3Helper.FileIORequestEventHandler);
                Task <ListBucketsResponse> t = s3Client.ListBucketsAsync(request);
                t.Wait();
                folders = t.Result.Buckets.ConvertAll(s3Bucket => new S3DirectoryInfo(s3Client, s3Bucket.BucketName, ""));
            }
            else
            {
                var request = new ListObjectsRequest
                {
                    BucketName = bucket,
                    Delimiter  = "/",
                    Prefix     = S3Helper.EncodeKey(key)
                };
                ((Amazon.Runtime.Internal.IAmazonWebServiceRequest)request).AddBeforeRequestHandler(S3Helper.FileIORequestEventHandler);
                folders = new EnumerableConverter <string, S3DirectoryInfo>
                              ((IEnumerable <string>)(PaginatedResourceFactory.Create <string, ListObjectsRequest, ListObjectsResponse>(new PaginatedResourceInfo()
                                                                                                                                        .WithClient(s3Client)
                                                                                                                                        .WithMethodName("ListObjects")
                                                                                                                                        .WithRequest(request)
                                                                                                                                        .WithItemListPropertyPath("CommonPrefixes")
                                                                                                                                        .WithTokenRequestPropertyPath("Marker")
                                                                                                                                        .WithTokenResponsePropertyPath("NextMarker"))),
                              prefix => new S3DirectoryInfo(s3Client, bucket, S3Helper.DecodeKey(prefix)));
            }

            //handle if recursion is set
            if (searchOption == SearchOption.AllDirectories)
            {
                IEnumerable <S3DirectoryInfo> foldersToAdd = new List <S3DirectoryInfo>();
                foreach (S3DirectoryInfo dir in folders)
                {
                    foldersToAdd = foldersToAdd.Concat(dir.EnumerateDirectories(searchPattern, searchOption));
                }
                folders = folders.Concat(foldersToAdd);
            }

            //filter based on search pattern
            var regEx = WildcardToRegex(searchPattern);

            folders = folders.Where(s3dirInfo => Regex.IsMatch(s3dirInfo.Name, regEx, RegexOptions.IgnoreCase));
            return(folders);
        }
        /// <summary>
        /// Enumerate the files of this directory.
        /// </summary>
        /// <param name="searchPattern">The search string. The default pattern is "*", which returns all files.</param>
        /// <param name="searchOption">One of the enumeration values that specifies whether the search operation should include only the current directory or all subdirectories. The default value is TopDirectoryOnly.</param>
        /// <exception cref="T:System.Net.WebException"></exception>
        /// <exception cref="T:Amazon.S3.AmazonS3Exception"></exception>
        /// <returns>An enumerable collection of files that matches searchPattern and searchOption.</returns>
        public IEnumerable <S3FileInfo> EnumerateFiles(string searchPattern, SearchOption searchOption)
        {
            IEnumerable <S3FileInfo> files = null;

            if (String.IsNullOrEmpty(bucket))
            {
                files = new List <S3FileInfo>();
            }
            else
            {
                var request = new ListObjectsRequest
                {
                    BucketName = bucket,
                    Delimiter  = "/",
                    Prefix     = S3Helper.EncodeKey(key)
                };
                ((Amazon.Runtime.Internal.IAmazonWebServiceRequest)request).AddBeforeRequestHandler(S3Helper.FileIORequestEventHandler);
                PaginatedResourceInfo pagingInfo = new PaginatedResourceInfo().WithClient(s3Client)
                                                   .WithMethodName("ListObjects")
                                                   .WithRequest(request)
                                                   .WithItemListPropertyPath("S3Objects")
                                                   .WithTokenRequestPropertyPath("Marker")
                                                   .WithTokenResponsePropertyPath("NextMarker");

                files = new EnumerableConverter <S3Object, S3FileInfo>
                            (((IEnumerable <S3Object>)(PaginatedResourceFactory.Create <S3Object, ListObjectsRequest, ListObjectsResponse>(pagingInfo)))
                            .Where(s3Object => !String.Equals(S3Helper.DecodeKey(s3Object.Key), key, StringComparison.Ordinal) && !s3Object.Key.EndsWith("\\", StringComparison.Ordinal)),
                            s3Object => new S3FileInfo(s3Client, bucket, S3Helper.DecodeKey(s3Object.Key)));
            }

            //handle if recursion is set
            if (searchOption == SearchOption.AllDirectories)
            {
                IEnumerable <S3DirectoryInfo> foldersToSearch = EnumerateDirectories();
                foreach (S3DirectoryInfo dir in foldersToSearch)
                {
                    files = files.Concat(dir.EnumerateFiles(searchPattern, searchOption));
                }
            }

            //filter based on search pattern
            var regEx = WildcardToRegex(searchPattern);

            files = files.Where(s3fileInfo => Regex.IsMatch(s3fileInfo.Name, regEx, RegexOptions.IgnoreCase));
            return(files);
        }