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