using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text.Json.Serialization; namespace FileExposer.Models; public record Review(Segment[]? AreEqual, Segment[]? LeftSideIsNewer, Segment[]? LeftSideOnly, Segment[]? NotEqualBut, Record[]? Records, Segment[]? RightSideIsNewer, Segment[]? RightSideOnly) { internal static Review Get(RelativePath relativePath, ReadOnlyCollection records) { Review result; ReadOnlyCollection areEqual = GetAreEqual(relativePath, records); ReadOnlyCollection notEqualBut = GetNotEqualBut(relativePath, records); ReadOnlyCollection leftSideOnly = GetLeftSideOnly(relativePath, records); ReadOnlyCollection rightSideOnly = GetRightSideOnly(relativePath, records); ReadOnlyCollection leftSideIsNewer = GetLeftSideIsNewer(relativePath, records); ReadOnlyCollection rightSideIsNewer = GetRightSideIsNewer(relativePath, records); result = new(AreEqual: [.. areEqual], LeftSideIsNewer: [.. leftSideIsNewer], LeftSideOnly: [.. leftSideOnly], NotEqualBut: [.. notEqualBut], Records: null, RightSideIsNewer: [.. rightSideIsNewer], RightSideOnly: [.. rightSideOnly]); return result; } private static ReadOnlyCollection GetAreEqual(RelativePath relativePath, ReadOnlyCollection records) { List results = []; Record? record; Segment segment; double totalSeconds; string? checkDirectory = null; ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(relativePath); foreach (Record r in records) { if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) { checkDirectory = r.RelativePath; continue; } if (r.RelativePath == relativePath.Path) continue; if (!keyValuePairs.TryGetValue(r.RelativePath, out record)) continue; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; if (record.Size != r.Size || totalSeconds is > 2 or < -2) continue; segment = new(Left: r, LeftDirectory: checkDirectory, Right: record, RightDirectory: relativePath.Path); results.Add(segment); } return results.AsReadOnly(); } private static ReadOnlyDictionary GetKeyValuePairs(RelativePath relativePath) => GetKeyValuePairs(relativePath.Records.AsReadOnly()); private static ReadOnlyDictionary GetKeyValuePairs(ReadOnlyCollection records) { Dictionary results = []; foreach (Record record in records) results.Add(record.RelativePath, record); return new(results); } private static ReadOnlyCollection GetNotEqualBut(RelativePath relativePath, ReadOnlyCollection records) { List results = []; Record? record; Segment segment; double totalSeconds; string? checkDirectory = null; ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(relativePath); foreach (Record r in records) { if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) { checkDirectory = r.RelativePath; continue; } if (r.RelativePath == relativePath.Path) continue; if (!keyValuePairs.TryGetValue(r.RelativePath, out record)) continue; if (record.Size == r.Size) continue; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; if (totalSeconds is >= 2 or <= -2) continue; segment = new(Left: r, LeftDirectory: checkDirectory, Right: record, RightDirectory: relativePath.Path); results.Add(segment); } return results.AsReadOnly(); } private static ReadOnlyCollection GetLeftSideOnly(RelativePath relativePath, ReadOnlyCollection records) { List results = []; Record? record; Segment segment; string? checkDirectory = null; ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(relativePath); foreach (Record r in records) { if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) { checkDirectory = r.RelativePath; continue; } if (r.RelativePath == relativePath.Path) continue; if (keyValuePairs.TryGetValue(r.RelativePath, out record)) continue; segment = new(Left: r, LeftDirectory: checkDirectory, Right: record, RightDirectory: relativePath.Path); results.Add(segment); } return results.AsReadOnly(); } private static ReadOnlyCollection GetRightSideOnly(RelativePath relativePath, ReadOnlyCollection records) { List results = []; Record? record; Segment segment; string? checkDirectory = null; ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(records); foreach (Record r in relativePath.Records) { if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) { checkDirectory = r.RelativePath; continue; } if (r.RelativePath == relativePath.Path) continue; if (keyValuePairs.TryGetValue(r.RelativePath, out record)) continue; segment = new(Left: record, LeftDirectory: null, Right: r, RightDirectory: relativePath.Path); results.Add(segment); } return results.AsReadOnly(); } private static ReadOnlyCollection GetLeftSideIsNewer(RelativePath relativePath, ReadOnlyCollection records) { List results = []; Record? record; Segment segment; double totalSeconds; string? checkDirectory = null; ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(relativePath); foreach (Record r in records) { if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) { checkDirectory = r.RelativePath; continue; } if (r.RelativePath == relativePath.Path) continue; if (!keyValuePairs.TryGetValue(r.RelativePath, out record)) continue; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; if (totalSeconds is > -2) continue; segment = new(Left: r, LeftDirectory: checkDirectory, Right: record, RightDirectory: relativePath.Path); results.Add(segment); } return results.AsReadOnly(); } private static ReadOnlyCollection GetRightSideIsNewer(RelativePath relativePath, ReadOnlyCollection records) { List results = []; Record? record; Segment segment; double totalSeconds; string? checkDirectory = null; ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(records); foreach (Record r in relativePath.Records) { if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) { checkDirectory = r.RelativePath; continue; } if (r.RelativePath == relativePath.Path) continue; if (!keyValuePairs.TryGetValue(r.RelativePath, out record)) continue; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; if (totalSeconds is > -2) continue; segment = new(Left: record, LeftDirectory: null, Right: r, RightDirectory: relativePath.Path); results.Add(segment); } return results.AsReadOnly(); } } [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(Review))] public partial class ReviewSourceGenerationContext : JsonSerializerContext { }