127 lines
4.1 KiB
C#
127 lines
4.1 KiB
C#
public sealed class SimulationRunState
|
|
{
|
|
private readonly object _gate = new();
|
|
private DateTimeOffset? _completedAt;
|
|
|
|
public Guid RunId { get; init; }
|
|
public string ScenarioId { get; init; } = null!;
|
|
public string ScenarioName { get; init; } = null!;
|
|
public double Speed { get; init; }
|
|
public string StartedByUserId { get; init; } = null!;
|
|
public DateTimeOffset StartedAt { get; init; }
|
|
public double TotalOffsetMinutes { get; init; }
|
|
public string PatientDisplayName { get; init; } = null!;
|
|
|
|
public SimulationRunStatus Status { get; private set; } = SimulationRunStatus.Pending;
|
|
public Guid? PatientId { get; private set; }
|
|
public Guid? EncounterId { get; private set; }
|
|
public int ObservationsSent { get; private set; }
|
|
public int MedicationsSent { get; private set; }
|
|
public int OrdersPlaced { get; private set; }
|
|
public double LastOffsetMinutes { get; private set; }
|
|
public double ProgressPercent { get; private set; }
|
|
public string? FailureReason { get; private set; }
|
|
|
|
public double ElapsedRealSeconds
|
|
{
|
|
get
|
|
{
|
|
lock (_gate)
|
|
{
|
|
var end = _completedAt ?? DateTimeOffset.UtcNow;
|
|
return (end - StartedAt).TotalSeconds;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void MarkRunning()
|
|
{
|
|
lock (_gate) Status = SimulationRunStatus.Running;
|
|
}
|
|
|
|
public void SetIds(Guid? patientId, Guid? encounterId)
|
|
{
|
|
lock (_gate)
|
|
{
|
|
if (patientId.HasValue) PatientId = patientId;
|
|
if (encounterId.HasValue) EncounterId = encounterId;
|
|
}
|
|
}
|
|
|
|
public void UpdateOffset(double offsetMinutes)
|
|
{
|
|
lock (_gate)
|
|
{
|
|
LastOffsetMinutes = offsetMinutes;
|
|
ProgressPercent = TotalOffsetMinutes <= 0
|
|
? 100
|
|
: Math.Clamp(offsetMinutes / TotalOffsetMinutes * 100.0, 0, 100);
|
|
}
|
|
}
|
|
|
|
public void ApplyResultCounters(int observationsSent, int medicationsSent, int ordersPlaced)
|
|
{
|
|
lock (_gate)
|
|
{
|
|
ObservationsSent = observationsSent;
|
|
MedicationsSent = medicationsSent;
|
|
OrdersPlaced = ordersPlaced;
|
|
}
|
|
}
|
|
|
|
public void NoteEvent(string description)
|
|
{
|
|
lock (_gate)
|
|
{
|
|
if (description.StartsWith("MEDICATION", StringComparison.Ordinal))
|
|
MedicationsSent++;
|
|
else if (description.StartsWith("ORDER ", StringComparison.Ordinal))
|
|
OrdersPlaced++;
|
|
else if (!description.StartsWith("ORDER_RESULT", StringComparison.Ordinal)
|
|
&& !description.StartsWith("ACK ", StringComparison.Ordinal))
|
|
ObservationsSent++;
|
|
}
|
|
}
|
|
|
|
public void MarkTerminal(SimulationRunStatus status, string? failureReason = null)
|
|
{
|
|
lock (_gate)
|
|
{
|
|
Status = status;
|
|
FailureReason = failureReason;
|
|
_completedAt = DateTimeOffset.UtcNow;
|
|
if (status == SimulationRunStatus.Completed)
|
|
ProgressPercent = 100;
|
|
}
|
|
}
|
|
|
|
public SimulationRunState Snapshot()
|
|
{
|
|
lock (_gate)
|
|
{
|
|
var copy = new SimulationRunState
|
|
{
|
|
RunId = RunId,
|
|
ScenarioId = ScenarioId,
|
|
ScenarioName = ScenarioName,
|
|
Speed = Speed,
|
|
StartedByUserId = StartedByUserId,
|
|
StartedAt = StartedAt,
|
|
TotalOffsetMinutes = TotalOffsetMinutes,
|
|
PatientDisplayName = PatientDisplayName,
|
|
};
|
|
copy.Status = Status;
|
|
copy.PatientId = PatientId;
|
|
copy.EncounterId = EncounterId;
|
|
copy.ObservationsSent = ObservationsSent;
|
|
copy.MedicationsSent = MedicationsSent;
|
|
copy.OrdersPlaced = OrdersPlaced;
|
|
copy.LastOffsetMinutes = LastOffsetMinutes;
|
|
copy.ProgressPercent = ProgressPercent;
|
|
copy.FailureReason = FailureReason;
|
|
copy._completedAt = _completedAt;
|
|
return copy;
|
|
}
|
|
}
|
|
}
|