using System.IO;
namespace DeskCore;
/// Eine rückgängig machbare Aktion, bestehend aus mehreren Einzelschritten.
public class UndoEntry(string description)
{
public string Description { get; } = description;
private readonly List> _steps = [];
/// Elemente, die beim Löschen zwischengeparkt wurden – gehen später in den Papierkorb.
public List HeldPaths { get; } = [];
public bool IsEmpty => _steps.Count == 0;
/// Schritt zum Rückgängigmachen; gibt eine Fehlermeldung oder null zurück.
public void Add(Func undo) => _steps.Add(undo);
public void AddMove(string from, string to) => Add(() =>
{
if (!File.Exists(to) && !Directory.Exists(to)) return $"„{Path.GetFileName(to)}“ gibt es nicht mehr.";
var dir = Path.GetDirectoryName(from)!;
Directory.CreateDirectory(dir);
var back = File.Exists(from) || Directory.Exists(from) ? Storage.UniquePath(dir, Path.GetFileName(from)) : from;
Storage.MoveAny(to, back);
return null;
});
public void AddCopy(string original, string copy) => Add(() =>
{
if (!File.Exists(copy) && !Directory.Exists(copy)) return null;
// Original noch da → Kopie weg; sonst Kopie dorthin zurück, wo das Original lag
if (File.Exists(original) || Directory.Exists(original)) Storage.Recycle(copy);
else
{
Directory.CreateDirectory(Path.GetDirectoryName(original)!);
Storage.MoveAny(copy, original);
}
return null;
});
public void AddDelete(string original, string held)
{
HeldPaths.Add(held);
AddMove(original, held);
}
public List Run()
{
var errors = new List();
for (int i = _steps.Count - 1; i >= 0; i--)
{
try { if (_steps[i]() is { } err) errors.Add(err); }
catch (Exception ex) { errors.Add(ex.Message); }
}
HeldPaths.Clear(); // wurden zurückgeholt
return errors;
}
}
public class UndoManager
{
private const int Limit = 30;
private readonly LinkedList _stack = new();
public event Action? Changed;
public bool CanUndo => _stack.Count > 0;
public string? NextDescription => _stack.Last?.Value.Description;
public void Push(UndoEntry entry)
{
if (entry.IsEmpty) return;
_stack.AddLast(entry);
while (_stack.Count > Limit)
{
Flush(_stack.First!.Value);
_stack.RemoveFirst();
}
Changed?.Invoke();
}
public (string Description, List Errors)? Undo()
{
if (_stack.Last is not { } last) return null;
_stack.RemoveLast();
var errors = last.Value.Run();
Changed?.Invoke();
return (last.Value.Description, errors);
}
/// Beim Beenden: alles Zwischengeparkte in den Papierkorb.
public void FlushAll()
{
foreach (var e in _stack) Flush(e);
_stack.Clear();
Storage.FlushHolding();
}
private static void Flush(UndoEntry e)
{
foreach (var p in e.HeldPaths) Storage.Recycle(p);
e.HeldPaths.Clear();
}
}