package se.cambio.cds.controller.cds; import org.apache.log4j.Logger; import se.cambio.cds.controller.CDSSessionManager; import se.cambio.cds.controller.guide.GuideManager; import se.cambio.cds.model.facade.execution.vo.GeneratedArchetypeReference; import se.cambio.cds.model.facade.execution.vo.GeneratedElementInstance; import se.cambio.cds.model.facade.execution.vo.PredicateGeneratedElementInstance; import se.cambio.cds.model.facade.execution.vo.PredicateGeneratedElementInstanceBuilder; import se.cambio.cds.model.instance.ArchetypeReference; import se.cambio.cds.model.instance.ElementInstance; import se.cambio.cds.util.*; import se.cambio.openehr.util.OpenEHRConstUI; import se.cambio.openehr.util.exceptions.InternalErrorException; import se.cambio.openehr.util.exceptions.PatientNotFoundException; import java.util.*; public class CDSManager { public static Collection<ElementInstance> getElementInstances( String ehrId, Collection<String> guideIds, Collection<ArchetypeReference> data, GuideManager guideManager, Calendar date) throws PatientNotFoundException, InternalErrorException{ ElementInstanceCollection eic = new ElementInstanceCollection(); if (data != null){ eic.addAll(data, guideManager); } GeneratedElementInstanceCollection completeEIC = guideManager.getElementInstanceCollection(guideIds); //Search for EHR elements //Query EHR for elements if (ehrId != null){ Collection<ArchetypeReference> ars = getEHRArchetypeReferences(completeEIC); Map<String, Collection<ElementInstance>> elementInstanceMap = CDSSessionManager.getEHRFacadeDelegate().queryEHRElements(Collections.singleton(ehrId), ars, date); Collection<ElementInstance> elementInstances = elementInstanceMap.get(ehrId); if (elementInstances!=null){ Set<ArchetypeReference> archetypeReferences = new HashSet<ArchetypeReference>(); for (ElementInstance elementInstance: elementInstances){ archetypeReferences.add(elementInstance.getArchetypeReference()); } eic.addAll(archetypeReferences, null); } } return getElementInstances(eic, completeEIC, guideManager, date); } public static Map<String,Collection<ElementInstance>> getElementInstancesForPopulation( Collection <String> ehrIds, Collection<String> guideIds, GuideManager guideManager, Calendar date) throws PatientNotFoundException, InternalErrorException{ GeneratedElementInstanceCollection completeEIC = guideManager.getElementInstanceCollection(guideIds); Collection<ArchetypeReference> ars = getEHRArchetypeReferences(completeEIC); Map<String,Collection<ElementInstance>> ehrMap = CDSSessionManager.getEHRFacadeDelegate().queryEHRElements(ehrIds, ars, date); Map<String,Collection<ElementInstance>> cdsEIMap = new HashMap<String, Collection<ElementInstance>>(); for (String ehrId : ehrIds) { ElementInstanceCollection eic = new ElementInstanceCollection(); //TODO If the data existed in ehrData, it should not query for it again to EHR if (!ars.isEmpty()){ Collection<ElementInstance> eis = ehrMap.get(ehrId); if (eis!=null){ eic.addAll(eis); } } cdsEIMap.put(ehrId, getElementInstances(eic, completeEIC, guideManager, date)); } return cdsEIMap; } public static Collection<ArchetypeReference> getEHRArchetypeReferences(GeneratedElementInstanceCollection geic){ Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>(); ars.addAll(geic.getAllArchetypeReferencesByDomain(Domains.EHR_ID)); ars.addAll(geic.getAllArchetypeReferencesByDomain(ElementInstanceCollection.EMPTY_CODE)); return getCompressedQueryArchetypeReferences(ars); } public static Collection<ArchetypeReference> getEHRArchetypeReferencesWithEventTimeElements(GeneratedElementInstanceCollection eic){ Collection<ArchetypeReference> ars = getEHRArchetypeReferences(eic); addEventTimeElements(ars); //We add all the event time elements if they are not defined return ars; } private static Collection<ElementInstance> getElementInstances(ElementInstanceCollection eic, GeneratedElementInstanceCollection completeEIC, GuideManager guideManager, Calendar date) throws InternalErrorException{ //Check for missing elements checkForMissingElements(eic, completeEIC, guideManager, date); return eic.getAllElementInstances(); } public static void checkForMissingElements( ElementInstanceCollection ehrEIC, ElementInstanceCollection generatedEIC, GuideManager guideManager, Calendar date){ checkForWholeMissingElements(ehrEIC, generatedEIC, guideManager, date); checkForMissingPathsInEHR(ehrEIC, generatedEIC, date); } private static void checkForWholeMissingElements( ElementInstanceCollection eic, ElementInstanceCollection generatedEIC, GuideManager guideManager, Calendar date){ //Check for guide elements, if not present, create archetype reference List<ArchetypeReference> guideArchetypeReferences = new ArrayList<ArchetypeReference>(generatedEIC.getAllArchetypeReferences()); Collections.sort(guideArchetypeReferences, new ARNonEmptyPredicateComparator()); for (ArchetypeReference archetypeReference : guideArchetypeReferences) { GeneratedArchetypeReference gar = (GeneratedArchetypeReference)archetypeReference; boolean matches = eic.matches(gar, guideManager.getAllGuidesMap(), date); if (!matches){ eic.add(archetypeReference, guideManager, date); } } } private static void checkForMissingPathsInEHR( ElementInstanceCollection ehrEIC, ElementInstanceCollection generatedEIC, Calendar date){ //Add missing elements (as null) to the ehr data Map<String, ArchetypeReference> compressedARsMap = getCompressedQueryArchetypeReferencesMap(generatedEIC.getAllArchetypeReferences()); for(ArchetypeReference ar: ehrEIC.getAllArchetypeReferences()){ ArchetypeReference compressedAR = compressedARsMap.get(ar.getIdArchetype()); if (compressedAR!=null){ for (String elementId: compressedAR.getElementInstancesMap().keySet()){ if (!ar.getElementInstancesMap().containsKey(elementId)){ new ElementInstance(elementId, null, ar, null, OpenEHRConstUI.NULL_FLAVOUR_CODE_NO_INFO); } } } } } private static Collection<ArchetypeReference> getCompressedQueryArchetypeReferences(Collection<ArchetypeReference> generatedArchetypeReferences){ return new ArrayList<ArchetypeReference>(getCompressedQueryArchetypeReferencesMap(generatedArchetypeReferences).values()); } private static Map<String, ArchetypeReference> getCompressedQueryArchetypeReferencesMap(Collection<ArchetypeReference> generatedArchetypeReferences){ final Map<String, ArchetypeReference> archetypeReferencesMap = new HashMap<String, ArchetypeReference>(); //Compress Archetype References with same archetype id for (ArchetypeReference arNew : generatedArchetypeReferences) { GeneratedArchetypeReference gar = (GeneratedArchetypeReference)arNew; ArchetypeReference arPrev = archetypeReferencesMap.get(arNew.getIdArchetype()); if (arPrev!=null){ compressQueryArchetypeReference(arPrev, arNew); }else{ arNew = getCleanArchetypeReferenceWithElements(gar); archetypeReferencesMap.put(arNew.getIdArchetype(), arNew); } } return archetypeReferencesMap; } private static void compressQueryArchetypeReference(ArchetypeReference arPrev, ArchetypeReference arNew){ for (ElementInstance newEI : arNew.getElementInstancesMap().values()) { ElementInstance eiAux = arPrev.getElementInstancesMap().get(newEI.getId()); if (eiAux==null){ //Missing elements cloneElementInstanceWithGTCodes(newEI, arPrev, false); }else{ if (newEI instanceof PredicateGeneratedElementInstance){ PredicateGeneratedElementInstance pgeiNew = (PredicateGeneratedElementInstance)newEI; ElementInstance prevEI = arPrev.getElementInstancesMap().get(pgeiNew.getId()); if (prevEI instanceof PredicateGeneratedElementInstance){ PredicateGeneratedElementInstance pgeiPrev = (PredicateGeneratedElementInstance)prevEI; if (!pgeiNew.getOperatorKind().equals(pgeiPrev.getOperatorKind()) || DVUtil.compareDVs(pgeiNew.getDataValue(), pgeiPrev.getDataValue())!=0){ //TODO Find a predicate (if possible) that includes both //Incompatible predicates found, we remove data value and operation new PredicateGeneratedElementInstanceBuilder() .setId(pgeiPrev.getId()) .setArchetypeReference(pgeiPrev.getArchetypeReference()) .setNullFlavour(OpenEHRConstUI.NULL_FLAVOUR_CODE_NO_INFO) .createPredicateGeneratedElementInstance(); } } } if (eiAux instanceof GeneratedElementInstance && newEI instanceof GeneratedElementInstance){ //Add new rule references GeneratedElementInstance gei = (GeneratedElementInstance) eiAux; GeneratedElementInstance gei2 = (GeneratedElementInstance) newEI; gei.getRuleReferences().addAll(gei2.getRuleReferences()); } } } } private static GeneratedArchetypeReference getCleanArchetypeReferenceWithElements(GeneratedArchetypeReference ar){ GeneratedArchetypeReference arNew = ar.clone(); for (ElementInstance ei : ar.getElementInstancesMap().values()) { cloneElementInstanceWithGTCodes(ei, arNew, true); } return arNew; } private static ElementInstance cloneElementInstanceWithGTCodes(ElementInstance ei, ArchetypeReference ar, boolean useGTCodes){ ei = ei.clone(); ei.setArchetypeReference(ar); if (!useGTCodes && ei instanceof GeneratedElementInstance){ ((GeneratedElementInstance)ei).getRuleReferences().clear(); } return ei; } private static class ARNonEmptyPredicateComparator implements Comparator<ArchetypeReference>{ public int compare(ArchetypeReference o1, ArchetypeReference o2) { int count1 = getNumPredicates(o1); int count2 = getNumPredicates(o2); return count1-count2; } private int getNumPredicates(ArchetypeReference archetypeReference){ int count = 0; for (ElementInstance elementInstance: archetypeReference.getElementInstancesMap().values()){ if (elementInstance instanceof PredicateGeneratedElementInstance && elementInstance.getDataValue()!=null){ count++; } } return count; } } private static void addEventTimeElements(Collection<ArchetypeReference> queryARs){ for(ArchetypeReference archetypeReference: queryARs){ String eventTimePath = DateTimeARFinder.getEventTimePath(archetypeReference.getIdArchetype()); if (eventTimePath!=null){ String eventTimeElementId = archetypeReference.getIdArchetype()+eventTimePath; if (!archetypeReference.getElementInstancesMap().containsKey(eventTimeElementId)){ Logger.getLogger(CDSManager.class).info("Adding event path '"+eventTimeElementId+"' for archetype '"+archetypeReference.getIdArchetype()+"'!"); new GeneratedElementInstance(eventTimeElementId, null, archetypeReference, null, OpenEHRConstUI.NULL_FLAVOUR_CODE_NO_INFO); } }else{ Logger.getLogger(CDSManager.class).warn("Could not find event path for archetype '"+archetypeReference.getIdArchetype()+"'!"); } } } } /* * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 2.0 (the 'License'); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an 'AS IS' basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * * The Initial Developers of the Original Code are Iago Corbal and Rong Chen. * Portions created by the Initial Developer are Copyright (C) 2012-2013 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Software distributed under the License is distributed on an 'AS IS' basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * ***** END LICENSE BLOCK ***** */