inital
This commit is contained in:
353
FasdCockpitCommunicationDemo/TicketOverviewDataStore.cs
Normal file
353
FasdCockpitCommunicationDemo/TicketOverviewDataStore.cs
Normal file
@@ -0,0 +1,353 @@
|
||||
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 Classification { 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<DemoTicketJournalEntry> Journal { get; set; } = new List<DemoTicketJournalEntry>();
|
||||
}
|
||||
|
||||
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<DemoTicketTemplate> Templates { get; set; } = new List<DemoTicketTemplate>();
|
||||
public List<DemoTicketRecord> Tickets { get; set; } = new List<DemoTicketRecord>();
|
||||
}
|
||||
|
||||
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<string, int> SeedNumbers = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["TCK"] = 766,
|
||||
["INC"] = 475
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, int> SeedWidths = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["TCK"] = DefaultNumberWidth,
|
||||
["INC"] = DefaultNumberWidth
|
||||
};
|
||||
|
||||
private static List<DemoTicketTemplate> _templateCache = new List<DemoTicketTemplate>();
|
||||
private static List<DemoTicketRecord> _runtimeTickets = new List<DemoTicketRecord>();
|
||||
private static readonly Dictionary<string, int> _nextNumbers = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
private static readonly Dictionary<string, int> _numberWidths = new Dictionary<string, int>(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<DemoTicketData>(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,
|
||||
Classification = source.Classification,
|
||||
Description = source.Description,
|
||||
DescriptionHtml = source.DescriptionHtml,
|
||||
Priority = source.Priority,
|
||||
Solution = source.Solution,
|
||||
SolutionHtml = source.SolutionHtml,
|
||||
Journal = source.Journal?.Select(CloneJournalEntry).ToList() ?? new List<DemoTicketJournalEntry>()
|
||||
};
|
||||
}
|
||||
|
||||
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<DemoTicketTemplate>();
|
||||
_runtimeTickets = data.Tickets?.Select(CloneRecord).Where(r => r != null).ToList() ?? new List<DemoTicketRecord>();
|
||||
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<DemoTicketRecord> LoadTickets()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
EnsureLoaded();
|
||||
return _runtimeTickets.Select(CloneRecord).Where(r => r != null).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<DemoTicketTemplate> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user