using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Newtonsoft.Json; namespace FasdCockpitCommunicationDemo { public class DemoTicketJournalEntry { public string Header { get; set; } public string Description { get; set; } public string DescriptionHtml { get; set; } public bool IsVisibleForUser { get; set; } public DateTime CreationDate { get; set; } } public class DemoTicketDetail { public string AffectedUser { get; set; } public string Asset { get; set; } public string Category { get; set; } public string Description { get; set; } public string DescriptionHtml { get; set; } public int? Priority { get; set; } public string Solution { get; set; } public string SolutionHtml { get; set; } public List Journal { get; set; } = new List(); } public class DemoTicketTemplate { public string TileKey { get; set; } = "TicketsNew"; public bool UseRoleScope { get; set; } public Guid? UserId { get; set; } public string DisplayNamePrefix { get; set; } = "TCK"; public string Summary { get; set; } public string StatusId { get; set; } = "New"; public string UserDisplayName { get; set; } public string UserAccount { get; set; } public string UserDomain { get; set; } public DemoTicketDetail Detail { get; set; } = new DemoTicketDetail(); } public class DemoTicketRecord { public Guid TicketId { get; set; } public Guid UserId { get; set; } public string TileKey { get; set; } public bool UseRoleScope { get; set; } public string DisplayName { get; set; } public string Summary { get; set; } public string StatusId { get; set; } public string UserDisplayName { get; set; } public string UserAccount { get; set; } public string UserDomain { get; set; } public DateTime CreatedAt { get; set; } public DemoTicketDetail Detail { get; set; } = new DemoTicketDetail(); } public class DemoTicketData { public List Templates { get; set; } = new List(); public List Tickets { get; set; } = new List(); } public static class TicketOverviewDataStore { private const string FileName = "TicketOverviewGeneratedTickets.json"; private static readonly object SyncRoot = new object(); private const int DefaultNumberWidth = 5; private static readonly Dictionary SeedNumbers = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["TCK"] = 766, ["INC"] = 475 }; private static readonly Dictionary SeedWidths = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["TCK"] = DefaultNumberWidth, ["INC"] = DefaultNumberWidth }; private static List _templateCache = new List(); private static List _runtimeTickets = new List(); private static readonly Dictionary _nextNumbers = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary _numberWidths = new Dictionary(StringComparer.OrdinalIgnoreCase); private static bool _isLoaded; private static string ResolveDirectory() { var assembly = typeof(TicketOverviewDataStore).GetTypeInfo().Assembly; var baseDirectory = Path.GetDirectoryName(assembly.Location); return Path.Combine(baseDirectory ?? string.Empty, "MockupTicketOverview"); } private static string ResolveFilePath() { var directory = ResolveDirectory(); return Path.Combine(directory, FileName); } private static DemoTicketData ReadDataUnsafe() { try { var filePath = ResolveFilePath(); if (!File.Exists(filePath)) return new DemoTicketData(); var json = File.ReadAllText(filePath); if (string.IsNullOrWhiteSpace(json)) return new DemoTicketData(); var data = JsonConvert.DeserializeObject(json); return data ?? new DemoTicketData(); } catch { return new DemoTicketData(); } } private static DemoTicketJournalEntry CloneJournalEntry(DemoTicketJournalEntry source) { if (source == null) return new DemoTicketJournalEntry(); return new DemoTicketJournalEntry { Header = source.Header, Description = source.Description, DescriptionHtml = source.DescriptionHtml, IsVisibleForUser = source.IsVisibleForUser, CreationDate = source.CreationDate }; } private static DemoTicketDetail CloneDetail(DemoTicketDetail source) { if (source == null) return new DemoTicketDetail(); return new DemoTicketDetail { AffectedUser = source.AffectedUser, Asset = source.Asset, Category = source.Category, Description = source.Description, DescriptionHtml = source.DescriptionHtml, Priority = source.Priority, Solution = source.Solution, SolutionHtml = source.SolutionHtml, Journal = source.Journal?.Select(CloneJournalEntry).ToList() ?? new List() }; } private static DemoTicketTemplate CloneTemplate(DemoTicketTemplate source) { if (source == null) return new DemoTicketTemplate(); return new DemoTicketTemplate { TileKey = source.TileKey, UseRoleScope = source.UseRoleScope, UserId = source.UserId, DisplayNamePrefix = source.DisplayNamePrefix, Summary = source.Summary, StatusId = source.StatusId, UserDisplayName = source.UserDisplayName, UserAccount = source.UserAccount, UserDomain = source.UserDomain, Detail = CloneDetail(source.Detail) }; } private static DemoTicketRecord CloneRecord(DemoTicketRecord source) { if (source == null) return null; return new DemoTicketRecord { TicketId = source.TicketId, UserId = source.UserId, TileKey = source.TileKey, UseRoleScope = source.UseRoleScope, DisplayName = source.DisplayName, Summary = source.Summary, StatusId = source.StatusId, UserDisplayName = source.UserDisplayName, UserAccount = source.UserAccount, UserDomain = source.UserDomain, CreatedAt = source.CreatedAt, Detail = CloneDetail(source.Detail) }; } private static void EnsureLoaded() { if (_isLoaded) return; var data = ReadDataUnsafe(); _templateCache = data.Templates?.Select(CloneTemplate).ToList() ?? new List(); _runtimeTickets = data.Tickets?.Select(CloneRecord).Where(r => r != null).ToList() ?? new List(); ResetNumberCounters(); _isLoaded = true; } private static void ResetNumberCounters() { _nextNumbers.Clear(); _numberWidths.Clear(); foreach (var kvp in SeedNumbers) { _nextNumbers[kvp.Key] = kvp.Value; _numberWidths[kvp.Key] = SeedWidths.TryGetValue(kvp.Key, out var width) ? Math.Max(width, DefaultNumberWidth) : DefaultNumberWidth; } foreach (var ticket in _runtimeTickets) { UpdateNumberCounterFromDisplayName(ticket?.DisplayName); } } private static void UpdateNumberCounterFromDisplayName(string displayName) { if (string.IsNullOrWhiteSpace(displayName)) return; int i = 0; while (i < displayName.Length && char.IsLetter(displayName[i])) i++; if (i == 0) return; var prefix = displayName.Substring(0, i).ToUpperInvariant(); int j = i; while (j < displayName.Length && char.IsDigit(displayName[j])) j++; if (j == i) return; var numericSegment = displayName.Substring(i, j - i); if (!int.TryParse(numericSegment, out var number)) return; var width = Math.Max(DefaultNumberWidth, numericSegment.Length); if (!_nextNumbers.TryGetValue(prefix, out var current)) current = SeedNumbers.TryGetValue(prefix, out var seedValue) ? seedValue : 1; if (number >= current) _nextNumbers[prefix] = number + 1; if (_numberWidths.TryGetValue(prefix, out var currentWidth)) _numberWidths[prefix] = Math.Max(currentWidth, width); else _numberWidths[prefix] = width; } private static string ReserveDisplayName(string prefix) { prefix = string.IsNullOrWhiteSpace(prefix) ? "TCK" : prefix.ToUpperInvariant(); if (!_nextNumbers.TryGetValue(prefix, out var next)) next = SeedNumbers.TryGetValue(prefix, out var seedValue) ? seedValue : 1; var width = _numberWidths.TryGetValue(prefix, out var storedWidth) ? Math.Max(storedWidth, DefaultNumberWidth) : DefaultNumberWidth; var nextString = next.ToString(); if (nextString.Length > width) width = nextString.Length; var displayName = $"{prefix}{nextString.PadLeft(width, '0')}"; _nextNumbers[prefix] = next + 1; _numberWidths[prefix] = width; return displayName; } public static DemoTicketData LoadData() { lock (SyncRoot) { EnsureLoaded(); return new DemoTicketData { Templates = _templateCache.Select(CloneTemplate).ToList(), Tickets = _runtimeTickets.Select(CloneRecord).Where(r => r != null).ToList() }; } } public static List LoadTickets() { lock (SyncRoot) { EnsureLoaded(); return _runtimeTickets.Select(CloneRecord).Where(r => r != null).ToList(); } } public static List LoadTemplates() { lock (SyncRoot) { EnsureLoaded(); return _templateCache.Select(CloneTemplate).ToList(); } } public static bool AppendTicket(DemoTicketRecord record) { if (record == null) return false; lock (SyncRoot) { EnsureLoaded(); if (_runtimeTickets.Any(t => t.TicketId == record.TicketId)) return false; var clone = CloneRecord(record); if (clone == null) return false; _runtimeTickets.Add(clone); UpdateNumberCounterFromDisplayName(clone.DisplayName); return true; } } public static string GetNextDisplayName(string prefix) { lock (SyncRoot) { EnsureLoaded(); return ReserveDisplayName(prefix); } } } }