001package org.hl7.fhir.r4.terminologies;
002
003import org.hl7.fhir.exceptions.FHIRException;
004import org.hl7.fhir.exceptions.PathEngineException;
005import org.hl7.fhir.r4.context.IWorkerContext;
006import org.hl7.fhir.r4.elementmodel.Element;
007import org.hl7.fhir.r4.elementmodel.ObjectConverter;
008import org.hl7.fhir.r4.model.*;
009import org.hl7.fhir.r4.fhirpath.FHIRPathEngine;
010import org.hl7.fhir.r4.fhirpath.ExpressionNode;
011import org.hl7.fhir.r4.fhirpath.TypeDetails;
012import org.hl7.fhir.r4.fhirpath.FHIRPathFunctionDefinition;
013import org.hl7.fhir.r4.fhirpath.FHIRPathUtilityClasses;
014import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
015import org.hl7.fhir.utilities.FhirPublication;
016import org.hl7.fhir.utilities.i18n.I18nConstants;
017import org.hl7.fhir.utilities.validation.ValidationOptions;
018
019import java.util.ArrayList;
020import java.util.List;
021
022public class TerminologyFunctions {
023
024
025  public static abstract class TerminologyFunctionBase extends FHIRPathFunctionDefinition {
026
027    protected FHIRException makeExceptionPlural(FHIRPathEngine engine, Integer num, String constName, Object... args) {
028      String fmt = engine.getWorker().formatMessagePlural(num, constName, args);
029      return new PathEngineException(fmt, constName);
030    }
031
032
033    protected FHIRException makeException(FHIRPathEngine engine, ExpressionNode holder, String constName, Object... args) {
034      String fmt = engine.getWorker().formatMessage(constName, args);
035      return new PathEngineException(fmt, constName);
036    }
037  }
038
039
040  public static class TerminologiesObject extends Base {
041    @Override
042    public String fhirType() {
043      return "TerminologyServices";
044    }
045
046    @Override
047    protected void listChildren(List<Property> result) {
048
049    }
050
051    @Override
052    public String getIdBase() {
053      return null;
054    }
055
056    @Override
057    public void setIdBase(String value) {
058    }
059
060    @Override
061    public Base copy() {
062      return this;
063    }
064
065  }
066
067  public static class ExpandFunction extends TerminologyFunctionBase {
068
069    @Override
070    public String name() {
071      return "expand";
072    }
073
074    @Override
075    public FHIRPathUtilityClasses.FunctionDetails details() {
076      return new FHIRPathUtilityClasses.FunctionDetails("Perform a value set expansion", 1, 2);
077    }
078
079    @Override
080    public TypeDetails check(FHIRPathEngine engine, Object appContext, TypeDetails focus, List<TypeDetails> parameters) {
081      return new TypeDetails(ExpressionNode.CollectionStatus.SINGLETON, "Resource");
082    }
083
084    @Override
085    public List<Base> execute(FHIRPathEngine engine, Object appContext, List<Base> focus, List<List<Base>> parameters) {
086      if (focus.size() == 0) {
087        return new ArrayList<Base>();
088      }
089      if (focus.size() != 1) {
090        throw makeExceptionPlural(engine, focus.size(), I18nConstants.FHIRPATH_FOCUS, "expand", focus.size());
091      }
092      Base base = focus.get(0);
093      List<Base> result = new ArrayList<Base>();
094      if (base.fhirType().equals("TerminologyServices") && parameters.size() > 0) {
095        List<Base> param1 = parameters.get(0);
096        if (param1.size() != 1) {
097          throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "valueSet", focus.size());
098        }
099        ValueSet vs = null;
100        if (param1.get(0).isPrimitive()) {
101          vs = engine.getWorker().fetchResource(ValueSet.class, param1.get(0).primitiveValue());
102        } else {
103          // nothing
104        }
105        if (vs != null) {
106          ValueSetExpansionOutcome exp = engine.getWorker().expandVS(vs, true, false);
107          if (exp.isOk() && exp.getValueset() != null) {
108            result.add(exp.getValueset());
109          }
110        } else {
111          throw new Error("Not supported yet");
112        }
113      }
114      return result;
115    }
116  }
117
118  public static class ValidateVSFunction extends TerminologyFunctionBase {
119
120    @Override
121    public String name() {
122      return "validateVS";
123    }
124
125    @Override
126    public FHIRPathUtilityClasses.FunctionDetails details() {
127      return new FHIRPathUtilityClasses.FunctionDetails("Validate a code against a ValueSet", 2, 3);
128    }
129
130    @Override
131    public TypeDetails check(FHIRPathEngine engine, Object appContext, TypeDetails focus, List<TypeDetails> parameters) {
132      return new TypeDetails(ExpressionNode.CollectionStatus.SINGLETON, "Parameters");
133    }
134
135    @Override
136    public List<Base> execute(FHIRPathEngine engine, Object appContext, List<Base> focus, List<List<Base>> parameters) {
137      if (focus.size() == 0) {
138        return new ArrayList<Base>();
139      }
140      if (focus.size() != 1) {
141        throw makeExceptionPlural(engine, focus.size(), I18nConstants.FHIRPATH_FOCUS, "expand", focus.size());
142      }
143      Base base = focus.get(0);
144      List<Base> result = new ArrayList<Base>();
145      if (base.fhirType().equals("TerminologyServices") && parameters.size() > 1) {
146        List<Base> param1 = parameters.get(0);
147        if (param1.size() != 1) {
148          throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "valueSet", focus.size());
149        }
150        ValueSet vs = null;
151        if (param1.get(0).isPrimitive()) {
152          vs = engine.getWorker().fetchResource(ValueSet.class, param1.get(0).primitiveValue());
153        } else {
154          // nothing
155        }
156        if (vs != null) {
157          List<Base> param2 = parameters.get(1);
158          if (param2.size() != 1) {
159            throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "coded", focus.size());
160          }
161          Base coded = param2.get(0);
162          if (coded.isPrimitive()) {
163            IWorkerContext.ValidationResult vr = engine.getWorker().validateCode(ValidationOptions.defaults(), coded.primitiveValue(), vs);
164            result.add(vr.getOrMakeParameters());
165          } else if ("Coding".equals(coded.fhirType())) {
166            Coding coding = coded instanceof Coding ? (Coding) coded : ObjectConverter.readAsCoding((Element) coded);
167            IWorkerContext.ValidationResult vr = engine.getWorker().validateCode(ValidationOptions.defaults(), coded.primitiveValue(), vs);
168            result.add(vr.getOrMakeParameters());
169          } else if ("CodeableConcept".equals(coded.fhirType())) {
170            CodeableConcept cc = coded instanceof CodeableConcept ? (CodeableConcept) coded : ObjectConverter.readAsCodeableConcept((Element) coded);
171            IWorkerContext.ValidationResult vr = engine.getWorker().validateCode(ValidationOptions.defaults(), coded.primitiveValue(), vs);
172            result.add(vr.getOrMakeParameters());
173          }
174        }
175      }
176      return result;
177    }
178  }
179
180
181  public static class TranslateFunction extends TerminologyFunctionBase {
182
183    @Override
184    public String name() {
185      return "translate";
186    }
187
188    @Override
189    public FHIRPathUtilityClasses.FunctionDetails details() {
190      return new FHIRPathUtilityClasses.FunctionDetails("Translate from terminology to another", 2, 3);
191    }
192
193    @Override
194    public TypeDetails check(FHIRPathEngine engine, Object appContext, TypeDetails focus, List<TypeDetails> parameters) {
195      return new TypeDetails(ExpressionNode.CollectionStatus.SINGLETON, "Parameters");
196    }
197
198    @Override
199    public List<Base> execute(FHIRPathEngine engine, Object appContext, List<Base> focus, List<List<Base>> parameters) {
200      if (focus.size() == 0) {
201        return new ArrayList<Base>();
202      }
203      if (focus.size() != 1) {
204        throw makeExceptionPlural(engine, focus.size(), I18nConstants.FHIRPATH_FOCUS, "expand", focus.size());
205      }
206      Base base = focus.get(0);
207      List<Base> result = new ArrayList<Base>();
208      if (base.fhirType().equals("TerminologyServices") && parameters.size() > 1) {
209        List<Base> param1 = parameters.get(0);
210        if (param1.size() != 1) {
211          throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "valueSet", focus.size());
212        }
213        ConceptMap cm = null;
214        if (param1.get(0).isPrimitive()) {
215          cm = engine.getWorker().fetchResource(ConceptMap.class, param1.get(0).primitiveValue());
216        } else {
217          // nothing
218        }
219        if (cm != null) {
220          List<Base> param2 = parameters.get(1);
221          if (param2.size() != 1) {
222            throw makeExceptionPlural(engine, param1.size(), I18nConstants.FHIRPATH_PARAMETER_CARD, "coded", focus.size());
223          }
224          Base coded = param2.get(0);
225          if (coded.isPrimitive()) {
226            Parameters p = new ConceptTranslationEngine(engine.getWorker()).translateCode(coded.primitiveValue(), cm);
227            result.add(p);
228          } else if ("Coding".equals(coded.fhirType())) {
229            Coding coding = coded instanceof Coding ? (Coding) coded : ObjectConverter.readAsCoding((Element) coded);
230            Parameters p = new ConceptTranslationEngine(engine.getWorker()).translateCoding(coding, cm);
231            result.add(p);
232          }
233        }
234      }
235      return result;
236    }
237  }
238
239}