using Explorer.Contracts; using Explorer.Domain; using Explorer.Domain.Abstractions; namespace Explorer.FileOperations; public sealed class FileOperationService { private readonly ITransferHost _queue; private readonly IShellFileOperations _shell; private readonly IFileSystemEnumerator _enumerator; public FileOperationService(ITransferHost queue, IShellFileOperations shell, IFileSystemEnumerator enumerator) { _queue = queue; _shell = shell; _enumerator = enumerator; } public void Open(IReadOnlyList paths) { foreach (var path in paths) { _shell.Open(path); } } public Task CopyAsync(IReadOnlyList sources, string destinationDirectory, CancellationToken cancellationToken = default) => _queue.EnqueueCopyAsync(sources, destinationDirectory, cancellationToken); public Task MoveAsync(IReadOnlyList sources, string destinationDirectory, CancellationToken cancellationToken = default) => _queue.EnqueueMoveAsync(sources, destinationDirectory, cancellationToken); public Task DeleteAsync(IReadOnlyList paths, bool permanent = false, CancellationToken cancellationToken = default) => _queue.EnqueueDeleteAsync(paths, permanent, cancellationToken); public Task CreateShortcutsAsync(IReadOnlyList sources, string destinationDirectory, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); foreach (var source in sources) { var dest = UniqueShortcutPath(destinationDirectory, PathRules.GetFileName(source)); if (!_shell.CreateShortcut(source, dest, out var error) && error is not null) { throw new IOException(error); } } return Task.CompletedTask; } private static string UniqueShortcutPath(string directory, string sourceName) { var stem = sourceName + " - Shortcut"; var dest = Path.Combine(directory, stem + ".lnk"); var i = 2; while (File.Exists(PathRules.ToExtended(dest)) || Directory.Exists(PathRules.ToExtended(dest))) { dest = Path.Combine(directory, $"{stem} ({i++}).lnk"); } return dest; } public Task EnqueueRenameAsync(string path, string newName, CancellationToken cancellationToken = default) => _queue.EnqueueRenameAsync(path, newName, cancellationToken); public async Task EnqueueRenameAsync(IReadOnlyList<(string Path, string NewName)> items, CancellationToken cancellationToken = default) { foreach (var (path, newName) in items) { await _queue.EnqueueRenameAsync(path, newName, cancellationToken).ConfigureAwait(false); } } public Task EmptyRecycleBinAsync(CancellationToken cancellationToken = default) => _queue.EnqueueEmptyRecycleBinAsync(cancellationToken); public Task ExtractAsync(string archivePath, string destinationDirectory, CancellationToken cancellationToken = default) => _queue.EnqueueExtractAsync(archivePath, destinationDirectory, cancellationToken); public Task CompressAsync(IReadOnlyList sources, string archivePath, CancellationToken cancellationToken = default) => _queue.EnqueueCompressAsync(sources, archivePath, cancellationToken); public Task AddToArchiveAsync(string archivePath, IReadOnlyList sources, CancellationToken cancellationToken = default) => _queue.EnqueueAddToArchiveAsync(archivePath, sources, cancellationToken); public Task VerifyArchiveAsync(string archivePath, CancellationToken cancellationToken = default) => _queue.EnqueueVerifyArchiveAsync(archivePath, cancellationToken); public Task ConvertAsync(string sourcePath, string destinationPath, ConversionKind kind, CancellationToken cancellationToken = default) => _queue.EnqueueConvertAsync(sourcePath, destinationPath, kind, cancellationToken); public async Task ConvertAsync(IReadOnlyList operations, CancellationToken cancellationToken = default) { foreach (var op in operations.Where(o => o.Op == TransferOp.Convert && o.DestinationPath is not null)) { var kind = Enum.TryParse(op.NewName, true, out var parsed) ? parsed : ConversionFormats.Infer(op.SourcePath, op.DestinationPath!); await _queue.EnqueueConvertAsync(op.SourcePath, op.DestinationPath!, kind, cancellationToken).ConfigureAwait(false); } } public static string UniqueArchivePath(string directory, string stem, string extension) { extension = extension.Trim().TrimStart('.'); var dest = Path.Combine(directory, stem + "." + extension); var i = 2; while (File.Exists(PathRules.ToExtended(dest)) || Directory.Exists(PathRules.ToExtended(dest))) { dest = Path.Combine(directory, $"{stem} ({i++}).{extension}"); } return dest; } public void Rename(string path, string newName) { var parent = PathRules.Parent(path); var dest = Path.Combine(parent, newName); var src = PathRules.ToExtended(path); var dst = PathRules.ToExtended(dest); if (Directory.Exists(src)) { Directory.Move(src, dst); } else { File.Move(src, dst); } } public string NewFolder(string parent) { var baseName = "New folder"; var name = baseName; var i = 2; var dest = Path.Combine(parent, name); while (Directory.Exists(PathRules.ToExtended(dest)) || File.Exists(PathRules.ToExtended(dest))) { name = $"{baseName} ({i++})"; dest = Path.Combine(parent, name); } Directory.CreateDirectory(PathRules.ToExtended(dest)); return dest; } public FileSystemItem? GetItem(string path) => _enumerator.GetItem(path); }