Ejemplo n.º 1
0
        /// <summary>
        /// Create a care plan with the specified protocols only
        /// </summary>
        public CarePlan CreateCarePlan(Patient p, bool asEncounters, IDictionary <String, Object> parameters, params Guid[] protocols)
        {
            if (p == null)
            {
                return(null);
            }

            try
            {
                var parmDict = new ParameterDictionary <String, Object>();
                if (parameters != null)
                {
                    foreach (var itm in parameters)
                    {
                        parmDict.Add(itm.Key, itm.Value);
                    }
                }

                // Allow each protocol to initialize itself
                var execProtocols = this.Protocols.Where(o => protocols.Contains(o.Id)).OrderBy(o => o.Name).Distinct().ToList();

                Patient currentProcessing   = null;
                bool    isCurrentProcessing = false;
                if (p.Key.HasValue)
                {
                    isCurrentProcessing = this.m_patientPromise.TryGetValue(p.Key.Value, out currentProcessing);
                }
                if (p.Key.HasValue && !isCurrentProcessing)
                {
                    lock (this.m_patientPromise)
                        if (!this.m_patientPromise.TryGetValue(p.Key.Value, out currentProcessing))
                        {
                            currentProcessing = p.Copy() as Patient;

                            // Are the participations of the patient null?
                            if (p.Participations.Count == 0 && p.VersionKey.HasValue)
                            {
                                p.Participations = EntitySource.Current.Provider.Query <Act>(o => o.Participations.Where(g => g.ParticipationRole.Mnemonic == "RecordTarget").Any(g => g.PlayerEntityKey == currentProcessing.Key) &&
                                                                                             o.StatusConceptKey != StatusKeys.Nullified && o.StatusConceptKey != StatusKeys.Obsolete && o.StatusConceptKey != StatusKeys.Cancelled).OfType <Act>()
                                                   .Select(a =>
                                                           new ActParticipation()
                                {
                                    Act = a,
                                    ParticipationRole = new Concept()
                                    {
                                        Mnemonic = "RecordTarget"
                                    },
                                    PlayerEntity = currentProcessing
                                }).ToList();

                                //EntitySource.Current.Provider.Query<SubstanceAdministration>(o => o.Participations.Where(g => g.ParticipationRole.Mnemonic == "RecordTarget").Any(g => g.PlayerEntityKey == currentProcessing.Key)).OfType<Act>()
                                //    .Union(EntitySource.Current.Provider.Query<QuantityObservation>(o => o.Participations.Where(g => g.ParticipationRole.Mnemonic == "RecordTarget").Any(g => g.PlayerEntityKey == currentProcessing.Key))).OfType<Act>()
                                //    .Union(EntitySource.Current.Provider.Query<CodedObservation>(o => o.Participations.Where(g => g.ParticipationRole.Mnemonic == "RecordTarget").Any(g => g.PlayerEntityKey == currentProcessing.Key))).OfType<Act>()
                                //    .Union(EntitySource.Current.Provider.Query<TextObservation>(o => o.Participations.Where(g => g.ParticipationRole.Mnemonic == "RecordTarget").Any(g => g.PlayerEntityKey == currentProcessing.Key))).OfType<Act>()
                                //    .Union(EntitySource.Current.Provider.Query<PatientEncounter>(o => o.Participations.Where(g => g.ParticipationRole.Mnemonic == "RecordTarget").Any(g => g.PlayerEntityKey == currentProcessing.Key))).OfType<Act>()

                                (ApplicationServiceContext.Current.GetService(typeof(IDataCachingService)) as IDataCachingService)?.Add(p);
                            }
                            currentProcessing.Participations = new List <ActParticipation>(p.Participations);

                            // The record target here is also a record target for any /relationships
                            // TODO: I think this can be removed no?
                            //currentProcessing.Participations = currentProcessing.Participations.Union(currentProcessing.Participations.SelectMany(pt =>
                            //{
                            //    if (pt.Act == null)
                            //        pt.Act = EntitySource.Current.Get<Act>(pt.ActKey);
                            //    return pt.Act?.Relationships?.Select(r =>
                            //    {
                            //        var retVal = new ActParticipation(ActParticipationKey.RecordTarget, currentProcessing)
                            //        {
                            //            ActKey = r.TargetActKey,
                            //            ParticipationRole = new Model.DataTypes.Concept() { Mnemonic = "RecordTarget", Key = ActParticipationKey.RecordTarget }
                            //        };
                            //        if (r.TargetAct != null)
                            //            retVal.Act = r.TargetAct;
                            //        else
                            //        {
                            //            retVal.Act = currentProcessing.Participations.FirstOrDefault(o=>o.ActKey == r.TargetActKey)?.Act ?? EntitySource.Current.Get<Act>(r.TargetActKey);
                            //        }
                            //        return retVal;
                            //    }
                            //    );
                            //})).ToList();

                            // Add to the promised patient
                            this.m_patientPromise.Add(p.Key.Value, currentProcessing);
                        }
                }
                else if (!p.Key.HasValue) // Not persisted
                {
                    currentProcessing = p.Clone() as Patient;
                }

                // Initialize for protocol execution
                parmDict.Add("runProtocols", execProtocols.Distinct());
                if (!this.IgnoreViewModelInitializer)
                {
                    foreach (var o in this.Protocols.Distinct())
                    {
                        o.Initialize(currentProcessing, parmDict);
                    }
                }

                parmDict.Remove("runProtocols");

                List <Act> protocolActs = new List <Act>();
                lock (currentProcessing)
                {
                    var thdPatient = currentProcessing.Copy() as Patient;
                    thdPatient.Participations = new List <ActParticipation>(currentProcessing.Participations.ToList().Where(o => o.Act?.MoodConceptKey != ActMoodKeys.Propose && o.Act?.StatusConceptKey != StatusKeys.Nullified && o.Act?.StatusConceptKey != StatusKeys.Obsolete && o.Act?.StatusConceptKey != StatusKeys.Cancelled));

                    // Let's ensure that there are some properties loaded eh?
                    if (this.IgnoreViewModelInitializer)
                    {
                        foreach (var itm in thdPatient.LoadCollection <ActParticipation>("Participations"))
                        {
                            itm.LoadProperty <Act>("TargetAct").LoadProperty <Concept>("TypeConcept");
                            foreach (var itmPtcpt in itm.LoadProperty <Act>("TargetAct").LoadCollection <ActParticipation>("Participations"))
                            {
                                itmPtcpt.LoadProperty <Concept>("ParticipationRole");
                                itmPtcpt.LoadProperty <Entity>("PlayerEntity").LoadProperty <Concept>("TypeConcept");
                                itmPtcpt.LoadProperty <Entity>("PlayerEntity").LoadProperty <Concept>("MoodConcept");
                            }
                            ;
                        }
                    }
                    protocolActs = execProtocols.AsParallel().SelectMany(o => o.Calculate(thdPatient, parmDict)).OrderBy(o => o.StopTime - o.StartTime).ToList();
                }

                // Current processing
                if (asEncounters)
                {
                    List <PatientEncounter> encounters = new List <PatientEncounter>();
                    foreach (var act in new List <Act>(protocolActs).Where(o => o.StartTime.HasValue && o.StopTime.HasValue).OrderBy(o => o.StartTime).OrderBy(o => (o.StopTime ?? o.ActTime.AddDays(7)) - o.StartTime))
                    {
                        act.StopTime = act.StopTime ?? act.ActTime;
                        // Is there a candidate encounter which is bound by start/end
                        var candidate = encounters.FirstOrDefault(e => (act.StartTime ?? DateTimeOffset.MinValue) <= (e.StopTime ?? DateTimeOffset.MaxValue) &&
                                                                  (act.StopTime ?? DateTimeOffset.MaxValue) >= (e.StartTime ?? DateTimeOffset.MinValue) &&
                                                                  !e.Relationships.Any(r => r.TargetAct?.Protocols.Intersect(act.Protocols, new ProtocolComparer()).Count() == r.TargetAct?.Protocols.Count())
                                                                  );

                        // Create candidate
                        if (candidate == null)
                        {
                            candidate = this.CreateEncounter(act, currentProcessing);
                            encounters.Add(candidate);
                            protocolActs.Add(candidate);
                        }
                        else
                        {
                            TimeSpan[] overlap =
                            {
                                (candidate.StopTime ?? DateTimeOffset.MaxValue) - (candidate.StartTime ?? DateTimeOffset.MinValue),
                                (candidate.StopTime ?? DateTimeOffset.MaxValue) - (act.StartTime ?? DateTimeOffset.MinValue),
                                (act.StopTime ?? DateTimeOffset.MaxValue) - (candidate.StartTime ?? DateTimeOffset.MinValue),
                                (act.StopTime ?? DateTimeOffset.MaxValue) - (act.StartTime ?? DateTimeOffset.MinValue)
                            };
                            // find the minimum overlap
                            var minOverlap = overlap.Min();
                            var overlapMin = Array.IndexOf(overlap, minOverlap);
                            // Adjust the dates based on the start / stop time
                            if (overlapMin % 2 == 1)
                            {
                                candidate.StartTime = act.StartTime;
                            }
                            if (overlapMin > 1)
                            {
                                candidate.StopTime = act.StopTime;
                            }
                            candidate.ActTime = candidate.StartTime ?? candidate.ActTime;
                        }

                        // Add the protocol act
                        candidate.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.HasComponent, act));

                        // Remove so we don't have duplicates
                        protocolActs.Remove(act);
                        currentProcessing.Participations.RemoveAll(o => o.Act == act);
                    }

                    // for those acts which do not have a stop time, schedule them in the first appointment available
                    foreach (var act in new List <Act>(protocolActs).Where(o => !o.StopTime.HasValue))
                    {
                        var candidate = encounters.OrderBy(o => o.StartTime).FirstOrDefault(e => e.StartTime >= act.StartTime);
                        if (candidate == null)
                        {
                            candidate = this.CreateEncounter(act, currentProcessing);
                            encounters.Add(candidate);
                            protocolActs.Add(candidate);
                        }
                        // Add the protocol act
                        candidate.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.HasComponent, act));

                        // Remove so we don't have duplicates
                        protocolActs.Remove(act);
                        currentProcessing.Participations.RemoveAll(o => o.Act == act);
                    }
                }

                // TODO: Configure for days of week
                foreach (var itm in protocolActs)
                {
                    while (itm.ActTime.DayOfWeek == DayOfWeek.Sunday || itm.ActTime.DayOfWeek == DayOfWeek.Saturday)
                    {
                        itm.ActTime = itm.ActTime.AddDays(1);
                    }
                }

                return(new CarePlan(p, protocolActs.ToList())
                {
                    CreatedByKey = Guid.Parse("fadca076-3690-4a6e-af9e-f1cd68e8c7e8")
                });
            }
            catch (Exception e)
            {
                this.m_tracer.TraceError("Error creating care plan: {0}", e);
                throw;
            }
            finally
            {
                lock (m_patientPromise)
                    if (p.Key.HasValue && this.m_patientPromise.ContainsKey(p.Key.Value))
                    {
                        m_patientPromise.Remove(p.Key.Value);
                    }
            }
        }