227 lines
12 KiB
C#
227 lines
12 KiB
C#
using adas_core.Application.Services.Interfaces;
|
|
using adas_core.Domain.Models;
|
|
using adas_core.Domain.Models.AppSettings;
|
|
using adas_core.Domain.Models.Pumps;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using MongoDB.Bson;
|
|
|
|
namespace adas_core.Application.Services;
|
|
|
|
/// <summary>
|
|
/// Implements the <see cref="ICalculatedObservationsService"/> contract, providing a service for working with calculated observations.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=955972a -->
|
|
public class CalculatedObservationsService : ICalculatedObservationsService
|
|
{
|
|
private static ICalculatedObservations? _service;
|
|
private readonly ILogger<CalculatedObservationsService>? _logger;
|
|
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CalculatedObservationsService"/>, resolving the internal <see cref="ICalculatedObservations"/> implementation from the configured customization or falling back to <see cref="DefaultCalculatedObservations"/>.
|
|
/// </summary>
|
|
/// <param name="apiSettings">The <see cref="IOptions{ApiSettings}"/> providing the customization name used to locate the calculation implementation type.</param>
|
|
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> supplied to the resolved customization type's constructor.</param>
|
|
/// <param name="logger">The <see cref="ILogger{CalculatedObservationsService}"/> used to log warnings when the customization cannot be resolved.</param>
|
|
/// <!-- aidoc:v1 sig=f22feaa body=18f989f -->
|
|
public CalculatedObservationsService(
|
|
IOptions<ApiSettings> apiSettings,
|
|
IServiceProvider serviceProvider,
|
|
ILogger<CalculatedObservationsService> logger)
|
|
{
|
|
_logger = logger;
|
|
|
|
var customize = apiSettings.Value.Customize;
|
|
if (customize == null)
|
|
{
|
|
_logger.LogWarning("Not customization specified");
|
|
_service = new DefaultCalculatedObservations();
|
|
return;
|
|
}
|
|
|
|
|
|
var calculatedObservations = "adas_core.Application.Customizations." + customize + ".CalculatedObservations";
|
|
|
|
if (string.IsNullOrEmpty(customize))
|
|
{
|
|
_service = new DefaultCalculatedObservations();
|
|
}
|
|
else
|
|
{
|
|
var type = Type.GetType(calculatedObservations);
|
|
if (type == null)
|
|
{
|
|
_logger.LogWarning(
|
|
$"Type {calculatedObservations} not found for specification. Using DefaultCalculatedObservations");
|
|
_service = new DefaultCalculatedObservations();
|
|
return;
|
|
}
|
|
|
|
var ctor = Type.GetType(calculatedObservations)?.GetConstructor([typeof(IServiceProvider)]);
|
|
if (ctor == null)
|
|
{
|
|
_logger.LogWarning(
|
|
$"Constructor not found for type {calculatedObservations} accepts one parameter with type IServiceProvider. Using DefaultCalculatedObservations");
|
|
_service = new DefaultCalculatedObservations();
|
|
return;
|
|
}
|
|
|
|
_service = (ICalculatedObservations)ctor.Invoke([serviceProvider]);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Maps a <see cref="PatientObservation"/> by delegating to the configured mapping service.
|
|
/// If no service is available, the original observation is returned unchanged; if the service produces no mapping, a debug message is logged and <c>null</c> is returned.
|
|
/// </summary>
|
|
/// <param name="obs">The patient observation to map.</param>
|
|
/// <param name="onlyByName">When <c>true</c>, restricts the mapping to lookups by name only.</param>
|
|
/// <returns>The mapped <see cref="PatientObservation"/>, or <c>null</c> when the service yields no result; the input <paramref name="obs"/> is returned unchanged when no mapping service is configured.</returns>
|
|
/// <!-- aidoc:v1 sig=4b4df54 body=a7f1fb2 -->
|
|
public virtual async Task<PatientObservation?> Map(PatientObservation obs, bool onlyByName = false)
|
|
{
|
|
if (_service == null) return obs;
|
|
var result = await _service.Map(obs, onlyByName);
|
|
if (result == null)
|
|
_logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored",
|
|
_service.GetType().FullName, obs);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps a <see cref="PatientObservationAlarm"/> using the configured mapping service. Falls back to returning the original alarm unchanged when no service is available, and logs a debug entry when the service produces a null result (i.e., the alarm is ignored).
|
|
/// </summary>
|
|
/// <param name="obs">The patient observation alarm to be mapped.</param>
|
|
/// <param name="onlyByName">When true, restricts the mapping to a name-based lookup only.</param>
|
|
/// <returns>The mapped <see cref="PatientObservationAlarm"/>, or <c>null</c> if the service mapped it to null, or the original <paramref name="obs"/> when no service is configured.</returns>
|
|
/// <!-- aidoc:v1 sig=550b0f3 body=a7f1fb2 -->
|
|
public virtual async Task<PatientObservationAlarm?> Map(PatientObservationAlarm obs, bool onlyByName = false)
|
|
{
|
|
if (_service == null) return obs;
|
|
var result = await _service.Map(obs, onlyByName);
|
|
if (result == null)
|
|
_logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored",
|
|
_service.GetType().FullName, obs);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps the supplied <see cref="PumpObservation"/> by delegating to the configured mapping service.
|
|
/// Returns <see langword="null"/> when the underlying service has not been initialized.
|
|
/// </summary>
|
|
/// <param name="obs">The pump observation to be mapped.</param>
|
|
/// <returns>A task that yields the mapped <see cref="PumpObservation"/>, or <see langword="null"/> if no mapping service is available.</returns>
|
|
/// <!-- aidoc:v1 sig=b69cb93 body=75e8a34 -->
|
|
public virtual async Task<PumpObservation?> Map(PumpObservation obs)
|
|
{
|
|
if (_service == null) return null;
|
|
var result = await _service.Map(obs);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps a <see cref="PatientRecordingAlert"/> using the configured mapping service. Falls back to returning the original alert when no service is configured, and logs a debug entry when the service produces no mapping.
|
|
/// </summary>
|
|
/// <param name="obs">The <see cref="PatientRecordingAlert"/> instance to be mapped.</param>
|
|
/// <returns>The mapped <see cref="PatientRecordingAlert"/>, the original <paramref name="obs"/> if no service is available, or <c>null</c> if the service returned no result.</returns>
|
|
/// <!-- aidoc:v1 sig=3678681 body=9648481 -->
|
|
public async Task<PatientRecordingAlert?> Map(PatientRecordingAlert obs)
|
|
{
|
|
if (_service == null) return obs;
|
|
var result = await _service.Map(obs);
|
|
if (result == null)
|
|
_logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored",
|
|
_service.GetType().FullName, obs);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously maps a <see cref="PatientTreatment"/> using the underlying service. If the service is unavailable (null), the original treatment is returned unchanged as a fallback.
|
|
/// </summary>
|
|
/// <param name="treatment">The patient treatment instance to be mapped or transformed.</param>
|
|
/// <returns>A task that represents the asynchronous mapping operation, containing the mapped <see cref="PatientTreatment"/> or <c>null</c> if the service returns no result.</returns>
|
|
/// <!-- aidoc:v1 sig=b468f2f body=1c73c0e -->
|
|
public async Task<PatientTreatment?> Map(PatientTreatment treatment)
|
|
{
|
|
if (_service == null) return treatment;
|
|
var result = await _service.Map(treatment);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps a <see cref="PatientDiagnosis"/> by delegating to the configured mapping service. If no service is available, the original <paramref name="diagnosis"/> is returned as a fallback.
|
|
/// </summary>
|
|
/// <param name="diagnosis">The patient diagnosis to be mapped.</param>
|
|
/// <returns>A task that yields the mapped <see cref="PatientDiagnosis"/>, or <c>null</c> if the underlying service returns no result.</returns>
|
|
/// <!-- aidoc:v1 sig=fd30fa4 body=5966a0e -->
|
|
public virtual async Task<PatientDiagnosis?> Map(PatientDiagnosis diagnosis)
|
|
{
|
|
if (_service == null) return diagnosis;
|
|
var result = await _service.Map(diagnosis);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously calculates medicine observations for a patient based on their active medicines.
|
|
/// Delegates the calculation to the underlying service if it has been initialized; otherwise, the call is silently skipped.
|
|
/// </summary>
|
|
/// <param name="activeMedicines">The list of medicines currently active for the patient.</param>
|
|
/// <param name="patientId">The unique identifier of the patient whose medicine observations are being calculated.</param>
|
|
/// <!-- aidoc:v1 sig=0dfd9f3 body=65bf3e9 -->
|
|
public virtual async Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
|
|
{
|
|
if (_service != null) await _service.CalculateMedicineObservation(activeMedicines, patientId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously calculates the active bolus dosage of opiates for the specified patient by delegating to the underlying service.
|
|
/// If the service dependency is not initialized, the call is skipped silently as a no-op fallback.
|
|
/// </summary>
|
|
/// <param name="patientId">The unique identifier of the patient for whom the active bolus opiates calculation is performed.</param>
|
|
/// <!-- aidoc:v1 sig=e30b38f body=a756e48 -->
|
|
public async Task CalculateBolusOpiates(ObjectId patientId)
|
|
{
|
|
if (_service != null) await _service.CalculateActiveBolus(patientId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the active treatments associated with the specified patient.
|
|
/// If the underlying service is not available, returns an empty list as a fallback instead of throwing.
|
|
/// </summary>
|
|
/// <param name="id">The unique identifier of the patient whose active treatments should be retrieved.</param>
|
|
/// <returns>A task that yields the collection of active <see cref="PatientTreatment"/> entries for the patient, or an empty list when the service is unavailable.</returns>
|
|
/// <!-- aidoc:v1 sig=4caccd9 body=3a62497 -->
|
|
public virtual async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
|
|
{
|
|
if (_service != null) return await _service.GetActiveTreatmentsByPatient(id);
|
|
return new List<PatientTreatment?>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps a list of patient observations by delegating to the configured service's pre-mapping logic when available; otherwise, returns an empty list.
|
|
/// </summary>
|
|
/// <param name="listToInsert">The list of patient observations to be mapped.</param>
|
|
/// <returns>A task containing the mapped list of patient observations, or an empty list if no service is configured.</returns>
|
|
/// <!-- aidoc:v1 sig=8d07ed3 body=5a2680c -->
|
|
public virtual async Task<List<PatientObservation>> MapList(List<PatientObservation> listToInsert)
|
|
{
|
|
if (_service != null) return await _service.PreMapList(listToInsert);
|
|
return [];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Maps a source alarm onto the given patient observation by delegating to the configured service when available; if no service is configured, returns the original observation unchanged.
|
|
/// </summary>
|
|
/// <param name="observation">The patient observation onto which the source alarm will be mapped.</param>
|
|
/// <param name="observationAlarm">The source alarm to be applied to the observation.</param>
|
|
/// <returns>The <see cref="PatientObservation"/> produced by the service mapping, or the original <paramref name="observation"/> when no service is configured.</returns>
|
|
/// <!-- aidoc:v1 sig=20c558b body=7b3984c -->
|
|
public virtual async Task<PatientObservation> MapSourceAlarm(PatientObservation observation,
|
|
PatientObservationAlarm observationAlarm)
|
|
{
|
|
if (_service != null) return await _service.MapSourceAlarm(observation, observationAlarm);
|
|
return observation;
|
|
}
|
|
} |