354 lines
12 KiB
C#
354 lines
12 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|