using adas_core.Application.Services.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.MongoModels; using adas_core.Domain.Models.Pumps; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MongoDB.Bson; namespace adas_core.Application.Customizations.HRYC; public class CalculatedObservations : ICalculatedObservations { private readonly IOptions _apiSettings; private readonly List _codesForInvasiveVentilation = []; private readonly IConfigObservationService _configObservationService; //private readonly Lazy _boxService; private readonly List _highFrequencyVentilation = []; private readonly Lazy _lightBeaconService; private readonly ILogger _logger; private readonly List _nonInvasiveVentilation = []; private readonly Lazy _observationService; private readonly Lazy _patientService; public CalculatedObservations(IServiceProvider serviceProvider) { _observationService = serviceProvider.GetRequiredService>(); //observationService; _patientService = serviceProvider.GetRequiredService>(); _apiSettings = serviceProvider.GetRequiredService>(); //apiSettings; //_boxService = serviceProvider.GetRequiredService>(); _logger = serviceProvider.GetRequiredService>(); _lightBeaconService = serviceProvider.GetRequiredService>(); _configObservationService = serviceProvider.GetRequiredService(); //configObservationService; var highFrenquencyVentilation = _apiSettings.Value.HighFrequencyVentilation ?? null; highFrenquencyVentilation?.ForEach(x => _highFrequencyVentilation.Add(x.Trim())); var nonInvasiveVentilation = _apiSettings.Value.NonInvasiveVentilation ?? null; nonInvasiveVentilation?.ForEach(x => _nonInvasiveVentilation.Add(x.Trim())); var codesForInvasiveVentilation = //TODO comprobar si se refiere a InvasiveVentilation _apiSettings.Value.InvasiveVentilation ?? null; codesForInvasiveVentilation?.ForEach(x => _codesForInvasiveVentilation.Add(x.Trim())); } public async Task Map(T obs, bool onlyByName) where T : BasePatientObservation { _logger.LogTrace("Mapping {name} observation {obs}", obs.Name, obs); switch (obs.Name) { case "Resp_Mode": _logger.LogTrace("Mapping Resp mode observation {obs}", obs); await CalculateVentilationMode(obs); break; case "Diuresis": case "Weight_Current": if (obs.Name == "Weight_Current") await CalculateWeight_DiffObservation(obs); await CalculateDiureis_WeightObservation(obs); break; case "AllergiesObs": await CalculateAllergiesObservation(obs); break; case "DrainagesObs": await CalculateDrainagesObservation(obs); break; case "PEEP": case "Pleateu_Pressure": await CalculateDelta_PressureObservation(obs); break; case "Daily_Balance": await CalculateDaily_BalanceObservation(obs); break; case "Hydric_Balance": await CalculateHydricBalanceCalculated(obs); obs = (T)await CalculateHydricBalance(obs); break; case "Hour_Balance": obs = (T)await CalculateHourBalance(obs); break; case "FR": await CalculateRespRate(obs); await CalculateIrox(obs); break; case "Vent_Rate": await CalculateRespRate(obs); break; case "SpO2": case "FiO2": await CalculateIrox(obs); break; case "NEWS": await CalculateNews(obs); break; } return obs; } public Task Map(PatientTreatment treatment) { throw new NotImplementedException(); } public async Task Map(PumpObservation pumpObservation) { return await Task.FromResult(pumpObservation); } public Task CalculateMedicineObservation(List activeMedicines, ObjectId patientId) { return Task.CompletedTask; } public Task CalculateActiveBolus(ObjectId patientId) { return Task.CompletedTask; } public Task> GetActiveTreatmentsByPatient(ObjectId id) { return Task.FromResult(new List().AsEnumerable()); } public Task Map(PatientDiagnosis diagnosis) { return Task.FromResult(diagnosis); } public async Task FixTimeInconsistencyWithLast(PatientObservation newObservation) { if (string.IsNullOrEmpty(newObservation.Name)) { _logger.LogError( "Error FixTimeInconsistencyWithLast newObservation name ia null or empty. Observation: {newObservation}", newObservation); return newObservation; } var lastObservations = await _observationService.Value.FindLastObservations(newObservation.PatientId, 1, [newObservation.Name]); var lastObservation = lastObservations.FirstOrDefault(); if (lastObservation != null && DateTime.Compare( new DateTime(lastObservation.Time.Year, lastObservation.Time.Month, lastObservation.Time.Day, lastObservation.Time.Hour, lastObservation.Time.Minute, lastObservation.Time.Second), new DateTime(newObservation.Time.Year, newObservation.Time.Month, newObservation.Time.Day, newObservation.Time.Hour, newObservation.Time.Minute, newObservation.Time.Second) ) >= 0) newObservation.Time = lastObservation.Time.AddSeconds(1); return newObservation; } public async Task> PreMapList(List listToInsert) { var ventRate = listToInsert.FirstOrDefault(obs => obs.Name == "MDC_VENT_RESP_RATE"); var respRate = listToInsert.FirstOrDefault(obs => obs.Name == "MDC_RESP_RATE"); // Check if obs for Vent_Rate and FR is on the list to insert if (ventRate == null || respRate == null) return listToInsert; var ventRateValue = double.TryParse(ventRate.Value.ToString(), out var v1) ? v1 : 0; // ventRate is on the list to insert but its value is 0 if (ventRateValue == 0) { _logger.LogDebug("Find ventRate on PreMap request not processed because its value is 0"); return listToInsert; } var respRateValue = double.TryParse(ventRate.Value.ToString(), out var v2) ? v2 : 0; // respRate is on the list to insert but its value is 0 if (respRateValue == 0) { _logger.LogDebug("Find respRate on PreMap request not processed because its value is 0"); return listToInsert; } // Exists both obs and have value != 0 // In that case we need to calculate Resp_Rate_Calculated just with the value of Vent_Rate try { _logger.LogDebug( "Find on PreMap Vent_Rate and FR in the same request process Vent_Rate first to calculate Resp_Rate_Calculated"); await _observationService.Value.InsertObservation(ventRate); listToInsert.Remove(ventRate); } catch (Exception e) { _logger.LogError("Error while PreMap on insert obs: {ventRate} exception: {e}", ventRate, e); } return listToInsert; } public Task MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert) { return Task.FromResult(obs); } public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code) { throw new NotImplementedException(); } /// /// IF news greater or equal than 5 and less than 7 is warning beacon and if greater or equal than 7 alert /// /// private async Task CalculateNews(BasePatientObservation obs) { var pobs = (PatientObservation)obs; var parsed = int.TryParse(pobs.Value.ToString(), out var valueParsed); var patient = await _patientService.Value.FindById(obs.PatientId); if (patient == null) return; //var beaconConfig = await _boxService.Value.GetBeaconConfig(new PatientLocation(patient.PointOfCare, patient.Bed)); //power off beacon //recuperar la beacon del paciente y encenderla apagarla si el valor es > 5&6 o 7 alert if ((parsed && valueParsed < 5) || !parsed) //await _balizaService.Value.PowerOffLed(beaconCnf); //await _observationService.Value.SendObsBroadcast(obs); await SendAlarm(obs, AlarmEnum.Name.NewsOff); else switch (valueParsed) { case >= 5 and < 7: _logger.LogDebug("beacon yellow alert by NEWS for patient: {patientid}", obs.PatientId); await SendAlarm(obs, AlarmEnum.Name.NewsWarning); //await _balizaService.Value.SendBeaconColor(patient, LightBeaconColor.YELLOW); break; case >= 7: _logger.LogDebug("beacon red alert by NEWS for patient: {patientid}", obs.PatientId); await SendAlarm(obs, AlarmEnum.Name.NewsAlert); //await _balizaService.Value.SendBeaconColor(patient, LightBeaconColor.RED); break; } //if (obsAlarm == null) return; } private async Task SendAlarm(BasePatientObservation obs, AlarmEnum.Name name) { var pobs = (PatientObservation)obs; PatientObservation nObs = new() { CodingSystem = "ADAS_ALARM", Code = name.ToString(), Name = $"Alarm_{name}", PatientId = pobs.PatientId, Time = pobs.Time }; try { //ConfigObservations var configObs = await _configObservationService.Get(new PatientObservation { Name = nObs.Name, PatientId = obs.PatientId } ); if (configObs == null) { _logger.LogError("Config observation is null on send alarm NEWS for {nObs}", nObs); return; } if (configObs is { Alarm.Enabled: true }) { nObs.Alarm = configObs.Alarm; if (configObs.Alarm.Beacon is { Enabled: true }) { var patient = await _patientService.Value.FindById(obs.PatientId); if (patient != null) { _logger.LogDebug( "PatientId: {nObsPatientId}. Send Beacon alarmName {configObsAlarmBeaconBeaconColorValue}", nObs.PatientId, configObs.Alarm.Beacon.BeaconColor); nObs.Value = configObs.Alarm.Beacon.BeaconColor.ToString(); SendBeaconCode(configObs.Alarm.Beacon.BeaconColor, patient); } } } _logger.LogDebug( "Insert obs alarm for news at: {DateTimeNow} patientId: {nObsPatientId} color value: {nObsValue}", DateTime.Now, nObs.PatientId, nObs.Value); await _observationService.Value.InsertObservation(nObs); } catch (Exception ex) { _logger.LogError("Exception sending alarm: {exMessage}", ex.Message); } } private void SendBeaconCode(AlarmEnum.BeaconColor color, Patient patient) { if (!patient.PointOfCareId.HasValue) { _logger.LogError("Error sending beacon color on calculateObservations poc id on patient is null {Patient}", patient.ToString()); return; } switch (color) { case AlarmEnum.BeaconColor.Blue: _lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Blue); break; case AlarmEnum.BeaconColor.Yellow: _lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Yellow); break; case AlarmEnum.BeaconColor.Red: _lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Red); break; case AlarmEnum.BeaconColor.None: _lightBeaconService.Value.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Off); break; } } //(SpO2/FiO2)/FR IROX formula. Only calculate when all observations are in last 10 minutes. private async Task CalculateIrox(BasePatientObservation obs) { try { var pob = (PatientObservation)obs; var obsToCalc = new List { pob }; switch (pob.Name) { case "SpO2": var fio2Frvalues = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["FiO2", "FR"]); if (fio2Frvalues.Count > 0) obsToCalc.AddRange(fio2Frvalues); break; case "FiO2": var spo2Frvalues = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["SpO2", "FR"]); if (spo2Frvalues.Count > 0) obsToCalc.AddRange(spo2Frvalues); break; case "FR": var fio2Spo2Values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["FiO2", "SpO2"]); if (fio2Spo2Values.Count > 0) obsToCalc.AddRange(fio2Spo2Values); break; } if (!obsToCalc.All(o => o.Time.CompareTo(DateTime.UtcNow.AddMinutes(10)) <= 0)) return; var fio2 = obsToCalc.FirstOrDefault(o => o.Name == "FiO2"); var fr = obsToCalc.FirstOrDefault(o => o.Name == "FR"); var spo2 = obsToCalc.FirstOrDefault(o => o.Name == "SpO2"); if (fio2 == null || fr == null || spo2 == null) return; if (!double.TryParse(spo2.Value.ToString(), out var nSpo2) || !double.TryParse(fio2.Value.ToString(), out var nFio2) || !double.TryParse(fr.Value.ToString(), out var nFr)) { _logger.LogWarning("Error parsing values. fio2: {fio2}, fr: {fr}, spo2: {spo2}", fio2, fr, spo2); return; } var spo2Value = nSpo2; var fio2Value = nFio2; var frValue = nFr; if (spo2Value == 0 || fio2Value == 0 || frValue == 0) return; var value = nSpo2 / nFio2 / nFr; var irox = new PatientObservation { Name = "IROX", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time, Value = value }; await _observationService.Value.InsertObservation(irox); } catch (Exception e) { _logger.LogError("Exception calculating IROX, error: {eMessage}", e.Message); } } /* * RespRate solo se tiene que poner cuando no hay ningún ventRate en los últimos min y veinte segundos y el último no es un 0. */ //static readonly SemaphoreSlim semaphoreCalculateRespRate = new(1, 1); private async Task CalculateRespRate(BasePatientObservation obs) { var pobs = (PatientObservation)obs; _logger.LogDebug("CalculateRespRate {obsPatientid} wait {obsName} {obsTime} {pobsValue}", obs.PatientId, obs.Name, obs.Time, pobs.Value); if (Convert.ToDouble(pobs.Value) == 0) return; if (Convert.ToDouble(pobs.Value) == 0) return; var insert = true; if (obs.Name == "FR") { // Insertamos si no existe una obs Vent_Rate o si es existe tiene más de X" y su valor es > 0 var lastVentRate = (await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["Vent_Rate"])) .FirstOrDefault(); if (lastVentRate == null || (double.TryParse(lastVentRate.Value.ToString(), out var v) ? v : 0) == 0) { _logger.LogDebug("CalculateRespRate {id} lastVentRate: null", obs.PatientId); } else { var diff = DateTime.UtcNow.Subtract(lastVentRate.Time.ToUniversalTime()); insert = lastVentRate.Time.ToUniversalTime().AddMinutes(_apiSettings.Value.CalculateRespRateVentExpires) < DateTime.UtcNow; _logger.LogDebug( "CalculateRespRate {patientid} lastVentRate: {value} - {time} passed {diff} {insert}", obs.PatientId, lastVentRate.Value, lastVentRate.Time, diff, insert ? "Inserted" : "Not inserted"); } } if (insert) { _logger.LogDebug( "CalculateRespRate {patientid} Insert Resp_Rate_Calculated with {name} - {time} value {value}", obs.PatientId, obs.Name, obs.Time, pobs.Value); var calculatedRespRate = new PatientObservation { Id = new ObjectId(), Name = "Resp_Rate_Calculated", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Name == "FR" ? obs.Time : obs.Time.AddSeconds(1), Value = pobs.Value, ParentData = new ParentDataClass { Name = obs.Name } }; await _observationService.Value.InsertObservation(calculatedRespRate); } else { _logger.LogDebug( "CalculateRespRate {patientid} Insert Resp_Rate_Calculated with {name} - {time} value {value}", obs.PatientId, obs.Name, obs.Time, pobs.Value); } _logger.LogDebug("CalculateRespRate {patientid} release {name} {time} {value}", obs.PatientId, obs.Name, obs.Time, pobs.Value); } private async Task CalculateHydricBalance(BasePatientObservation obs) { var pobs = (PatientObservation)obs; var lastHydricBalanceFromHour = await _observationService.Value.FindLastBeforeDate(pobs.PatientId, pobs.Time.AddMinutes(59), "Hydric_Balance"); if (lastHydricBalanceFromHour != null && DateTime.Compare(new DateTime(lastHydricBalanceFromHour.Time.Year, lastHydricBalanceFromHour.Time.Month, lastHydricBalanceFromHour.Time.Day, lastHydricBalanceFromHour.Time.Hour, 0, 0) , new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0) pobs.Time = lastHydricBalanceFromHour.Time.AddSeconds(1); return obs; } private async Task CalculateHourBalance(BasePatientObservation obs) { var pobs = (PatientObservation)obs; var lastHourBalanceFromHour = await _observationService.Value.FindLastBeforeDate(pobs.PatientId, pobs.Time.AddMinutes(59), "Hour_Balance"); if (lastHourBalanceFromHour != null && DateTime.Compare(new DateTime(lastHourBalanceFromHour.Time.Year, lastHourBalanceFromHour.Time.Month, lastHourBalanceFromHour.Time.Day, lastHourBalanceFromHour.Time.Hour, 0, 0) , new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0) pobs.Time = lastHourBalanceFromHour.Time.AddSeconds(1); return obs; } private async Task CalculateHydricBalanceCalculated(BasePatientObservation obs) { //Hydric_Balance_Calculated //No guardamos como calculadas nunca horas futuras. En el obx siempre vienen con la hora y los minutos a 00 var pobs = (PatientObservation)obs; var nowUniversalTime = DateTime.Now.ToUniversalTime(); //La hora de la observación es mayor que la actual. No generamos la calculada if (DateTime.Compare(new DateTime(obs.Time.Year, obs.Time.Month, obs.Time.Day, obs.Time.Hour, 0, 0), new DateTime(nowUniversalTime.Year, nowUniversalTime.Month, nowUniversalTime.Day, nowUniversalTime.Hour, 0, 0)) > 0 ) { _logger.LogDebug( "HYDRIC BALANCE: La hora de la observación es mayor que la actual. No generamos la calculada {obs}", obs); return; } //Para la calculada. Si la última que tenemos es de la hora actual y lo que viene es de una hora anterior no entra como calculada. var lastHydricBalanceList = await _observationService.Value.FindLastObservations(obs.PatientId, 1, ["Hydric_Balance_Calculated"]); var lastHydricBalance = lastHydricBalanceList.FirstOrDefault(); if (lastHydricBalance != null && lastHydricBalance.Time.Hour == DateTime.UtcNow.Hour && obs.Time.Hour != DateTime.UtcNow.Hour) { _logger.LogDebug( "HYDRIC BALANCE: ultima que tenemos es de la hora actual y lo que viene es de una hora anterior no entra como calculada {obs}", obs); return; } //Si el último hydric balance es de una hora posterior a la observación que acaba de llegar no entra como calculada. if (lastHydricBalance != null && DateTime.Compare(new DateTime(lastHydricBalance.Time.Year, lastHydricBalance.Time.Month, lastHydricBalance.Time.Day, lastHydricBalance.Time.Hour, 0, 0) , new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 1 ) { _logger.LogDebug( "HYDRIC BALANCE: Si el ultimo hydric balance es de una hora posterior a la observación que acaba de llegar no entra como calculada. {obs}", obs); return; } var calculatedHydricBalance = new PatientObservation { Name = "Hydric_Balance_Calculated", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time.AddSeconds(1), //To discriminate updates. Value = pobs.Value, Units = obs.Units }; if (lastHydricBalance != null && DateTime.Compare( new DateTime(lastHydricBalance.Time.Year, lastHydricBalance.Time.Month, lastHydricBalance.Time.Day, lastHydricBalance.Time.Hour, 0, 0) , new DateTime(pobs.Time.Year, pobs.Time.Month, pobs.Time.Day, pobs.Time.Hour, 0, 0)) == 0) calculatedHydricBalance.Time = lastHydricBalance.Time.AddSeconds(1); await _observationService.Value.InsertObservation(calculatedHydricBalance); } private async Task CalculateVentilationMode(BasePatientObservation obs) { _logger.LogDebug("CalculateVentilationMode {obs}", obs); var pobs = (PatientObservation)obs; var respTypeObs = new PatientObservation { Name = "Resp_Type", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time }; //https://epigram.teamwork.com/#/tasks/34765750 if (obs.Code != null && _codesForInvasiveVentilation.Contains(obs.Code)) { //añadir que sea solo cuando el valor es invasiva respTypeObs.Value = nameof(RespirationType.Invasive); respTypeObs.Time = obs.Time.AddSeconds(1); await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs); } else { var strValue = pobs.Value.ToString(); if (strValue == null) return; //si es en espera tendrá que insertar que es en espera if (!"EnESPERA".Equals(strValue)) { respTypeObs.Value = _highFrequencyVentilation.Contains(strValue) ? nameof(RespirationType.HighFrequencyVentilation) : _nonInvasiveVentilation.Contains(strValue) ? respTypeObs.Value = nameof(RespirationType.NonInvasive) : nameof(RespirationType.Invasive); await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs); } } } private async Task CalculateWeight_DiffObservation(BasePatientObservation obs) { var toSearchList = new List(); toSearchList.AddRange(new List { "Weight_Current" }); var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList); var pWeight = values.FirstOrDefault(o => o.Name == "Weight_Current"); var newWeightObs = (PatientObservation)obs; if (pWeight?.Value != null && double.TryParse(pWeight.Value.ToString(), out var weight) && double.TryParse(newWeightObs.Value.ToString(), out var newWeight)) { var weightDiffValue = Math.Round(newWeight - weight, 2); var weightDiff = new PatientObservation { Name = "Weight_Diff", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time, Value = weightDiffValue, Units = obs.Units }; await _observationService.Value.InsertObservation(weightDiff); } } private async Task CalculateDiureis_WeightObservation(BasePatientObservation obs) { var toSearchList = new List(); PatientObservation? diuresisObs; PatientObservation? weightObs; toSearchList.AddRange(new List { "Diuresis", "Weight_Current" }); var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList); if (obs.Name == "Diuresis") { diuresisObs = (PatientObservation)obs; weightObs = values.FirstOrDefault(o => o.Name == "Weight_Current"); } else { weightObs = (PatientObservation)obs; diuresisObs = values.FirstOrDefault(o => o.Name == "Diuresis"); if (diuresisObs == null || CheckExpired(diuresisObs)) return; } if (weightObs?.Value != null) if (double.TryParse(weightObs.Value.ToString(), out var nWeight) && nWeight != 0 && double.TryParse(diuresisObs.Value.ToString(), out var diuresis)) { var diruesisWeightValue = Math.Round(diuresis / nWeight, 2); var diruesisWeight = new PatientObservation { Name = "Diuresis_Weight", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time, Value = diruesisWeightValue, Units = "ml/kg" }; await _observationService.Value.InsertObservation(diruesisWeight); } } private async Task CalculateAllergiesObservation(BasePatientObservation obs) { try { var pobs = (PatientObservation)obs; var allergiesObs = new PatientObservation { Name = "Allergies", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time, MessageTime = pobs.MessageTime }; var patientAllergiesValues = new List((IEnumerable)pobs.Value); var allergiesValues = patientAllergiesValues.GroupBy(o => o.Type) .Select(x => new PatientAllergiesValue { Type = x.Key, Value = string.Join(", ", x.Select(v => v.Value)), Notes = string.Join(", ", x.Select(n => n.Notes)) }).ToList(); var farmacosType = false; var farmacosValues = new List(); var values = new List(); foreach (var allergies in allergiesValues) { if (allergies.Value == null) continue; var type = allergies.Type?.Replace("Alergia a ", "").Replace("Alergia ", "").ToUpper(); if (type != null) switch (type) { case "FÁRMACOS": farmacosType = true; farmacosValues.Add(allergies.Value.ToUpper()); break; default: values.Add(type); break; } } if (farmacosType) { values.Add($"FÁRMACOS ({string.Join(", ", farmacosValues)})"); allergiesObs.Status = StatusEnum.Type.Alert; } allergiesObs.Value = string.Join(", ", values); await _observationService.Value.InsertObservation(allergiesObs); } catch (InvalidCastException) { _logger.LogError("CalculateAllergiesObservation {obs}", obs); } } private async Task CalculateDrainagesObservation(BasePatientObservation obs) { var pobs = (PatientObservation)obs; var patientDraingesValue = (PatientDrainagesValue)pobs.Value; if (patientDraingesValue.Type == "Drenaje ventricular") { var dve = new PatientObservation { Name = "DVE", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time, Units = obs.Units }; var drainageHeight = new PatientObservation { Name = "Drainage_Height", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = obs.Time }; if (patientDraingesValue.Volume != null) { dve.Value = patientDraingesValue.Volume; await _observationService.Value.InsertObservation(dve); } if (patientDraingesValue.Height != null) { drainageHeight.Value = patientDraingesValue.Height; await _observationService.Value.InsertObservation(drainageHeight); } } } private async Task CalculateDelta_PressureObservation(BasePatientObservation obs) { var toSearchList = new List(); PatientObservation? peep; PatientObservation? pleateuPressure; toSearchList.AddRange(new List { "PEEP", "Pleateu_Pressure" }); var values = await _observationService.Value.FindLastObservations(obs.PatientId, 1, toSearchList); var time = obs.Time; double pleateuPressureValue = 0; if (obs.Name == "PEEP") { peep = (PatientObservation)obs; pleateuPressure = values.FirstOrDefault(o => o.Name == "Pleateu_Pressure"); if (pleateuPressure?.Time != null && time.CompareTo(pleateuPressure.Time) > 0) time = pleateuPressure.Time; } else { pleateuPressure = (PatientObservation)obs; peep = values.FirstOrDefault(o => o.Name == "PEEP"); if (peep?.Time != null && time.CompareTo(peep.Time) > 0) time = peep.Time; } if (peep?.Value != null && pleateuPressure?.Value != null) { var peepSuccess = double.TryParse(peep.Value.ToString(), out var peepValue); if (!peepSuccess) peepValue = 0; if (!peepSuccess) pleateuPressureValue = 0; var deltaPressure = Math.Round(pleateuPressureValue - peepValue, 2); var deltaPressureObs = new PatientObservation { Name = "Delta_Pressure", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = time, Value = deltaPressure }; await _observationService.Value.InsertObservation(deltaPressureObs); } } private async Task CalculateDaily_BalanceObservation(BasePatientObservation obs) { if (obs.Time.ToLocalTime().Hour == 8) { var dailyBalanceCalculated = new PatientObservation { Name = "Daily_Balance_Calculated", CodingSystem = "ADAS", PatientId = obs.PatientId, Time = DateTime.Now, Units = obs.Units, Value = ((PatientObservation)obs).Value }; await _observationService.Value.InsertObservation(dailyBalanceCalculated); } } private static bool CheckExpired(PatientObservation obs) { if (obs.Expires == null) return false; var timeExpire = obs.Time.ToLocalTime().AddSeconds(Convert.ToDouble(obs.Expires)); return DateTime.Now.CompareTo(timeExpire) > 0; } }