using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text.Json.Serialization; namespace Adaptation.FileHandlers.json.WorkItems; internal class Record { #nullable enable [JsonConstructor] public Record(WorkItem workItem, WorkItem? parent, Record[] children, Record[] related, Record[] successors) { WorkItem = workItem; Parent = parent; Children = children; Related = related; Successors = successors; } [JsonPropertyName("WorkItem")] public WorkItem WorkItem { get; set; } [JsonPropertyName("Parent")] public WorkItem? Parent { get; set; } [JsonPropertyName("Children")] public Record[] Children { get; set; } [JsonPropertyName("Related")] public Record[] Related { get; set; } [JsonPropertyName("Successors")] public Record[] Successors { get; set; } internal static Record GetWithoutNesting(Record record, string? violation) { Record result; WorkItem workItem = new(record.WorkItem.ActivatedDate, record.WorkItem.AreaPath, record.WorkItem.AssignedTo, record.WorkItem.BusinessValue, record.WorkItem.ChangedDate, record.WorkItem.ClosedDate, record.WorkItem.CommentCount, record.WorkItem.CreatedDate, record.WorkItem.Description, record.WorkItem.Effort, record.WorkItem.Id, record.WorkItem.IterationPath, record.WorkItem.Parent, record.WorkItem.Priority, record.WorkItem.Relations, record.WorkItem.Requester, record.WorkItem.ResolvedDate, record.WorkItem.Revision, record.WorkItem.RiskReductionMinusOpportunityEnablement, record.WorkItem.StartDate, record.WorkItem.State, record.WorkItem.Tags, record.WorkItem.TargetDate, record.WorkItem.TimeCriticality, record.WorkItem.Title, record.WorkItem.Violation is null ? violation : record.WorkItem.Violation, record.WorkItem.WeightedShortestJobFirst, record.WorkItem.WorkItemType); result = new(workItem, record.Parent, Array.Empty(), Array.Empty(), Array.Empty()); return result; } private static Record Get(Record record, bool keepRelations) { Record result; WorkItem? parentWorkItem = keepRelations ? record.Parent : WorkItem.GetWithOutRelations(record.Parent); WorkItem? workItem = keepRelations ? record.WorkItem : WorkItem.GetWithOutRelations(record.WorkItem) ?? throw new Exception(); List childRecords = new(); List relatedRecords = new(); List successorRecords = new(); foreach (Record r in record.Children) childRecords.Add(Get(r, keepRelations)); foreach (Record r in record.Related) relatedRecords.Add(Get(r, keepRelations)); foreach (Record r in record.Successors) successorRecords.Add(Get(r, keepRelations)); result = new(workItem, parentWorkItem, childRecords.ToArray(), relatedRecords.ToArray(), successorRecords.ToArray()); return result; } internal static Record Get(WorkItem workItem, WorkItem? parent, ReadOnlyCollection children, ReadOnlyCollection related, ReadOnlyCollection successors, bool keepRelations) { Record result; Record record = new(workItem, parent, children.ToArray(), related.ToArray(), successors.ToArray()); result = Get(record, keepRelations); return result; } private static int? GetIdFromUrl(string relationName, Relation relation) { int? result; string[] segments = relation?.Attributes is null || relation.Attributes.Name != relationName ? Array.Empty() : relation.URL.Split('/'); if (segments.Length < 2) result = null; else { if (!int.TryParse(segments[segments.Length - 1], out int id)) result = null; else result = id; } return result; } internal static ReadOnlyCollection GetKeyValuePairs(ReadOnlyDictionary keyValuePairs, WorkItem workItem, string relationName, List nests, bool keepRelations) { List results = new(); int? childId; Record record; nests.Add(true); WorkItem? childWorkItem; WorkItem? parentWorkItem; List collection = new(); ReadOnlyCollection childRecords; ReadOnlyCollection relatedRecords; ReadOnlyCollection successorRecords; if (workItem.Relations is not null && workItem.Relations.Length > 0) { collection.Clear(); foreach (Relation relation in workItem.Relations) { childId = GetIdFromUrl(relationName, relation); if (childId is not null && workItem.Parent is not null && relation?.URL is not null && relation.URL.Contains(workItem.Parent.Value.ToString())) continue; if (childId is null || !keyValuePairs.TryGetValue(childId.Value, out childWorkItem)) continue; collection.Add(childWorkItem); } collection = (from l in collection orderby l.State != "Closed", l.Id select l).ToList(); foreach (WorkItem w in collection) { if (nests.Count > 99) break; if (w.Parent is null) parentWorkItem = null; else _ = keyValuePairs.TryGetValue(w.Parent.Value, out parentWorkItem); childRecords = GetKeyValuePairs(keyValuePairs, w, "Child", nests, keepRelations); // Forward // records = GetKeyValuePairs(keyValuePairs, w, "Predecessor", nests); // Reverse // successorRecords = GetKeyValuePairs(keyValuePairs, w, "Successor", nests); // Forward // if (successorRecords.Count > 0) // { // if (successorRecords.Count > 0) // { } // } successorRecords = new(Array.Empty()); relatedRecords = GetKeyValuePairs(keyValuePairs, w, "Related", nests, keepRelations); // Related record = Get(w, parentWorkItem, childRecords, relatedRecords, successorRecords, keepRelations); results.Add(record); } } return new(results); } } [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(Record))] internal partial class RecordSourceGenerationContext : JsonSerializerContext { }