PowerShellUtils/Commands/Bfs/BfsController.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Enumeration;
using System.Linq;
using System.Threading;
using PowerShellStandardModule1.Commands.PrintTree;
using PowerShellStandardModule1.Lib;
 
namespace PowerShellStandardModule1.Commands.Bfs;
 
using DirectoryChildGetter = Func<FileSystemInfo, IEnumerable<FileSystemInfo>>;
 
public class BfsController(
    DirectoryInfo startingDirectory,
    string pattern = "*",
    bool ignoreCase = true,
    int limit = int.MaxValue,
    int take = int.MaxValue,
    int height = int.MaxValue,
    bool file = false)
{
    public readonly int Limit = Math.Max(0, limit);
 
    public readonly int Height = Math.Max(0, height);
 
    private readonly DirectoryChildGetter _childGetter =
        file
            ? FsUtil.GetChildren
            : DirectoryUtil.GetChildren;
 
 
    public FileSystemInfoTreeNodeEnumerable Invoke(CancellationToken? token = null)
    {
        var cancelToken = token ?? CancellationToken.None;
        Validate();
 
        var impl = new BfsExecutor<FileSystemInfo>
        {
            ChildProvider = _childGetter,
            ShouldBreak = ShouldBreak
        };
 
        var res = impl.Invoke(startingDirectory);
 
        if (pattern != "*")
        {
            res = res.Where(x => IsMatch(x.Value.Name));
        }
 
        return res.Take(take);
 
 
        bool ShouldBreak(FileSystemInfoTreeNode x)
        {
            cancelToken.ThrowIfCancellationRequested();
            return x.Height > Height || x.Count > Limit;
        }
    }
 
 
    private void Validate()
    {
        if (!startingDirectory.Exists)
        {
            throw new DirectoryNotFoundException($"Directory not found: {startingDirectory}");
        }
    }
 
    public bool IsMatch(string name) => FileSystemName.MatchesSimpleExpression(pattern, name, ignoreCase);
}