Testing und interfaces
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using C4IT.FASD.Cockpit.Communication;
|
||||
#if isDemo
|
||||
using FasdCockpitCommunicationDemo;
|
||||
#endif
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.Models
|
||||
{
|
||||
internal interface ITicketOverviewCommunication
|
||||
{
|
||||
bool IsDemo();
|
||||
|
||||
Task<Dictionary<string, int>> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope);
|
||||
|
||||
#if isDemo
|
||||
void RegisterGeneratedTicket(DemoTicketRecord record);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal interface ITicketOverviewCommunicationSource
|
||||
{
|
||||
ITicketOverviewCommunication Resolve();
|
||||
}
|
||||
|
||||
internal sealed class TicketOverviewCommunicationSource : ITicketOverviewCommunicationSource
|
||||
{
|
||||
public ITicketOverviewCommunication Resolve()
|
||||
{
|
||||
var communication = cFasdCockpitCommunicationBase.Instance;
|
||||
return communication == null ? null : new TicketOverviewCommunicationAdapter(communication);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TicketOverviewCommunicationAdapter : ITicketOverviewCommunication
|
||||
{
|
||||
private readonly cFasdCockpitCommunicationBase _communication;
|
||||
|
||||
internal TicketOverviewCommunicationAdapter(cFasdCockpitCommunicationBase communication)
|
||||
{
|
||||
_communication = communication ?? throw new ArgumentNullException(nameof(communication));
|
||||
}
|
||||
|
||||
public bool IsDemo()
|
||||
{
|
||||
return _communication.IsDemo();
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, int>> GetTicketOverviewCounts(string[] overviewKeys, bool useRoleScope)
|
||||
{
|
||||
var rawCounts = await _communication.GetTicketOverviewCounts(overviewKeys, useRoleScope).ConfigureAwait(false);
|
||||
return rawCounts == null
|
||||
? new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
: new Dictionary<string, int>(rawCounts, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
#if isDemo
|
||||
public void RegisterGeneratedTicket(DemoTicketRecord record)
|
||||
{
|
||||
var demoCommunication = _communication as cFasdCockpitCommunicationDemo;
|
||||
demoCommunication?.RegisterGeneratedTicket(record);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.Models
|
||||
{
|
||||
internal static class TicketOverviewCountProcessor
|
||||
{
|
||||
internal static ScopeCountProcessingResult Calculate(
|
||||
IReadOnlyDictionary<string, TileCounts> currentCounts,
|
||||
IEnumerable<string> overviewKeys,
|
||||
TileScope scope,
|
||||
IDictionary<string, int> incomingCounts,
|
||||
bool hasInitializedScope)
|
||||
{
|
||||
if (overviewKeys == null)
|
||||
throw new ArgumentNullException(nameof(overviewKeys));
|
||||
|
||||
var updatedCounts = new Dictionary<string, TileCounts>(StringComparer.OrdinalIgnoreCase);
|
||||
if (currentCounts != null)
|
||||
{
|
||||
foreach (var kvp in currentCounts)
|
||||
{
|
||||
updatedCounts[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
|
||||
var changes = new List<TileCountChange>();
|
||||
foreach (var key in overviewKeys)
|
||||
{
|
||||
var previous = currentCounts != null && currentCounts.TryGetValue(key, out var counts)
|
||||
? counts
|
||||
: TileCounts.Empty;
|
||||
var incoming = incomingCounts != null && incomingCounts.TryGetValue(key, out var value)
|
||||
? value
|
||||
: 0;
|
||||
|
||||
TileCounts updated;
|
||||
int oldValue;
|
||||
|
||||
if (scope == TileScope.Role)
|
||||
{
|
||||
updated = new TileCounts(previous.Personal, incoming);
|
||||
oldValue = previous.Role;
|
||||
}
|
||||
else
|
||||
{
|
||||
updated = new TileCounts(incoming, previous.Role);
|
||||
oldValue = previous.Personal;
|
||||
}
|
||||
|
||||
updatedCounts[key] = updated;
|
||||
|
||||
if (hasInitializedScope && oldValue != incoming)
|
||||
changes.Add(new TileCountChange(key, scope, oldValue, incoming));
|
||||
}
|
||||
|
||||
return new ScopeCountProcessingResult(updatedCounts, changes, !hasInitializedScope);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class ScopeCountProcessingResult
|
||||
{
|
||||
internal ScopeCountProcessingResult(
|
||||
IReadOnlyDictionary<string, TileCounts> updatedCounts,
|
||||
IReadOnlyList<TileCountChange> changes,
|
||||
bool isInitialization)
|
||||
{
|
||||
UpdatedCounts = updatedCounts ?? throw new ArgumentNullException(nameof(updatedCounts));
|
||||
Changes = changes ?? Array.Empty<TileCountChange>();
|
||||
IsInitialization = isInitialization;
|
||||
}
|
||||
|
||||
internal IReadOnlyDictionary<string, TileCounts> UpdatedCounts { get; }
|
||||
|
||||
internal IReadOnlyList<TileCountChange> Changes { get; }
|
||||
|
||||
internal bool IsInitialization { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.Models
|
||||
{
|
||||
internal interface ITicketOverviewTimer
|
||||
{
|
||||
TimeSpan Interval { get; set; }
|
||||
|
||||
bool IsEnabled { get; }
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
}
|
||||
|
||||
internal interface ITicketOverviewDispatcher
|
||||
{
|
||||
Task InvokeAsync(Action action);
|
||||
|
||||
Task InvokeAsync(Func<Task> action);
|
||||
|
||||
ITicketOverviewTimer CreateTimer(TimeSpan interval, Action tick);
|
||||
}
|
||||
|
||||
internal sealed class TicketOverviewDispatcher : ITicketOverviewDispatcher
|
||||
{
|
||||
private readonly Dispatcher _dispatcher;
|
||||
|
||||
internal TicketOverviewDispatcher(Dispatcher dispatcher)
|
||||
{
|
||||
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
|
||||
}
|
||||
|
||||
public Task InvokeAsync(Action action)
|
||||
{
|
||||
return _dispatcher.InvokeAsync(action, DispatcherPriority.Background).Task;
|
||||
}
|
||||
|
||||
public Task InvokeAsync(Func<Task> action)
|
||||
{
|
||||
return _dispatcher.InvokeAsync(action, DispatcherPriority.Background).Task.Unwrap();
|
||||
}
|
||||
|
||||
public ITicketOverviewTimer CreateTimer(TimeSpan interval, Action tick)
|
||||
{
|
||||
var timer = new DispatcherTimer(interval, DispatcherPriority.Background, (sender, args) => tick?.Invoke(), _dispatcher)
|
||||
{
|
||||
IsEnabled = false
|
||||
};
|
||||
return new TicketOverviewTimer(timer);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TicketOverviewTimer : ITicketOverviewTimer
|
||||
{
|
||||
private readonly DispatcherTimer _timer;
|
||||
|
||||
internal TicketOverviewTimer(DispatcherTimer timer)
|
||||
{
|
||||
_timer = timer ?? throw new ArgumentNullException(nameof(timer));
|
||||
}
|
||||
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get => _timer.Interval;
|
||||
set => _timer.Interval = value;
|
||||
}
|
||||
|
||||
public bool IsEnabled => _timer.IsEnabled;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_timer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using C4IT.FASD.Base;
|
||||
|
||||
namespace FasdDesktopUi.Basics.Services.Models
|
||||
{
|
||||
internal interface ITicketOverviewSettingsProvider
|
||||
{
|
||||
int GetPollingMinutes(TileScope scope);
|
||||
}
|
||||
|
||||
internal sealed class TicketOverviewSettingsProvider : ITicketOverviewSettingsProvider
|
||||
{
|
||||
public int GetPollingMinutes(TileScope scope)
|
||||
{
|
||||
int minutes = scope == TileScope.Role
|
||||
? cF4sdTicketConfig.DefaultOverviewPollingRole
|
||||
: cF4sdTicketConfig.DefaultOverviewPollingPersonal;
|
||||
|
||||
try
|
||||
{
|
||||
var ticketConfig = cFasdCockpitConfig.Instance?.Global?.TicketConfiguration;
|
||||
if (ticketConfig != null)
|
||||
{
|
||||
minutes = scope == TileScope.Role
|
||||
? ticketConfig.OverviewPollingRole
|
||||
: ticketConfig.OverviewPollingPersonal;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[TicketOverview] Settings fallback to defaults: {ex.Message}");
|
||||
}
|
||||
|
||||
if (minutes < 1)
|
||||
{
|
||||
minutes = 1;
|
||||
}
|
||||
|
||||
return minutes;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user