001package org.hl7.fhir.r5.utils;
002
003/*
004  Copyright (c) 2011+, HL7, Inc.
005  All rights reserved.
006  
007  Redistribution and use in source and binary forms, with or without modification, 
008  are permitted provided that the following conditions are met:
009    
010   * Redistributions of source code must retain the above copyright notice, this 
011     list of conditions and the following disclaimer.
012   * Redistributions in binary form must reproduce the above copyright notice, 
013     this list of conditions and the following disclaimer in the documentation 
014     and/or other materials provided with the distribution.
015   * Neither the name of HL7 nor the names of its contributors may be used to 
016     endorse or promote products derived from this software without specific 
017     prior written permission.
018  
019  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
020  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
021  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
022  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
023  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
024  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
025  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
026  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
027  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
028  POSSIBILITY OF SUCH DAMAGE.
029  
030 */
031
032
033
034/*
035Copyright (c) 2011+, HL7, Inc
036All rights reserved.
037
038Redistribution and use in source and binary forms, with or without modification, 
039are permitted provided that the following conditions are met:
040
041 * Redistributions of source code must retain the above copyright notice, this 
042   list of conditions and the following disclaimer.
043 * Redistributions in binary form must reproduce the above copyright notice, 
044   this list of conditions and the following disclaimer in the documentation 
045   and/or other materials provided with the distribution.
046 * Neither the name of HL7 nor the names of its contributors may be used to 
047   endorse or promote products derived from this software without specific 
048   prior written permission.
049
050THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
051ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
052WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
053IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
054INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
055NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
056PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
057WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
058ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
059POSSIBILITY OF SUCH DAMAGE.
060
061 */
062
063import java.util.ArrayList;
064import java.util.HashMap;
065import java.util.Iterator;
066import java.util.List;
067import java.util.Map;
068
069import org.apache.commons.lang3.StringUtils;
070import org.fhir.ucum.Utilities;
071import org.hl7.fhir.exceptions.FHIRException;
072import org.hl7.fhir.r5.model.Base;
073import org.hl7.fhir.r5.model.BooleanType;
074import org.hl7.fhir.r5.model.CanonicalResource;
075import org.hl7.fhir.r5.model.CanonicalType;
076import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
077import org.hl7.fhir.r5.model.CodeType;
078import org.hl7.fhir.r5.model.CodeableConcept;
079import org.hl7.fhir.r5.model.Coding;
080import org.hl7.fhir.r5.model.DataType;
081import org.hl7.fhir.r5.model.DecimalType;
082import org.hl7.fhir.r5.model.DomainResource;
083import org.hl7.fhir.r5.model.Element;
084import org.hl7.fhir.r5.model.ElementDefinition;
085import org.hl7.fhir.r5.model.Extension;
086import org.hl7.fhir.r5.model.ExtensionHelper;
087import org.hl7.fhir.r5.model.Factory;
088import org.hl7.fhir.r5.model.Identifier;
089import org.hl7.fhir.r5.model.Integer64Type;
090import org.hl7.fhir.r5.model.IntegerType;
091import org.hl7.fhir.r5.model.MarkdownType;
092import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
093import org.hl7.fhir.r5.model.PrimitiveType;
094import org.hl7.fhir.r5.model.Property;
095import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent;
096import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemType;
097import org.hl7.fhir.r5.model.StringType;
098import org.hl7.fhir.r5.model.UriType;
099import org.hl7.fhir.r5.model.UrlType;
100import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
101import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
102import org.hl7.fhir.utilities.StandardsStatus;
103import org.hl7.fhir.utilities.validation.ValidationMessage;
104import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
105import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
106import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
107
108
109public class ToolingExtensions {
110
111  // validated
112//  private static final String EXT_OID = "http://hl7.org/fhir/StructureDefinition/valueset-oid";
113//  public static final String EXT_DEPRECATED = "http://hl7.org/fhir/StructureDefinition/codesystem-deprecated";
114  public static final String EXT_DEFINITION = "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition";
115  public static final String EXT_CS_COMMENT = "http://hl7.org/fhir/StructureDefinition/codesystem-concept-comments";
116  public static final String EXT_VS_COMMENT = "http://hl7.org/fhir/StructureDefinition/valueset-concept-comments";
117  public static final String EXT_CS_KEYWORD = "http://hl7.org/fhir/StructureDefinition/codesystem-keyWord";
118  public static final String EXT_VS_KEYWORD = "http://hl7.org/fhir/StructureDefinition/valueset-keyWord";
119  private static final String EXT_IDENTIFIER = "http://hl7.org/fhir/StructureDefinition/identifier";
120  public static final String EXT_TRANSLATION = "http://hl7.org/fhir/StructureDefinition/translation";
121  public static final String EXT_ISSUE_SOURCE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source";
122  public static final String EXT_ISSUE_LINE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-line";
123  public static final String EXT_ISSUE_COL = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-col";
124  public static final String EXT_DISPLAY_HINT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-display-hint"; 
125  public static final String EXT_REPLACED_BY = "http://hl7.org/fhir/StructureDefinition/valueset-replacedby";
126  public static final String EXT_REGEX = "http://hl7.org/fhir/StructureDefinition/regex"; 
127  public static final String EXT_CONTROL = "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl"; 
128  public static final String EXT_MINOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs"; 
129  public static final String EXT_MAXOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-maxOccurs";
130  public static final String EXT_ALLOWEDRESOURCE = "http://hl7.org/fhir/StructureDefinition/questionnaire-allowedResource";
131  public static final String EXT_REFERENCEFILTER = "http://hl7.org/fhir/StructureDefinition/questionnaire-referenceFilter";
132  public static final String EXT_CODE_GENERATION_PARENT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-codegen-super";
133  public static final String EXT_HIERARCHY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-hierarchy";
134  public static final String EXT_BEST_PRACTICE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice";
135  public static final String EXT_BEST_PRACTICE_EXPLANATION = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice-explanation";
136  // unregistered?
137  public static final String EXT_MAPPING_PREFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-prefix";
138  public static final String EXT_MAPPING_SUFFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-suffix";
139
140//  public static final String EXT_FLYOVER = "http://hl7.org/fhir/Profile/questionnaire-extensions#flyover";
141  public static final String EXT_QTYPE = "http://hl7.org/fhir/StructureDefinition/questionnnaire-baseType";
142//  private static final String EXT_QREF = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
143//  private static final String EXTENSION_FILTER_ONLY = "http://www.healthintersections.com.au/fhir/Profile/metadata#expandNeedsFilter";
144//  private static final String EXT_TYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type";
145//  private static final String EXT_REFERENCE = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
146  private static final String EXT_FHIRTYPE = "http://hl7.org/fhir/StructureDefinition/questionnaire-fhirType";
147  private static final String EXT_ALLOWABLE_UNITS = "http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits";
148  public static final String EXT_CIMI_REFERENCE = "http://hl7.org/fhir/StructureDefinition/cimi-reference";
149  public static final String EXT_UNCLOSED = "http://hl7.org/fhir/StructureDefinition/valueset-unclosed";
150  public static final String EXT_FMM_LEVEL = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm";
151  public static final String EXT_FMM_SUPPORT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm-support";
152  public static final String EXT_FMM_DERIVED = "http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom";
153  public static final String EXT_SEC_CAT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-security-category";
154  public static final String EXT_RESOURCE_CATEGORY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-category";
155  public static final String EXT_RESOURCE_INTERFACE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-interface";
156  public static final String EXT_TABLE_NAME = "http://hl7.org/fhir/StructureDefinition/structuredefinition-table-name";
157  public static final String EXT_OO_FILE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-file";
158  public static final String EXT_WORKGROUP = "http://hl7.org/fhir/StructureDefinition/structuredefinition-wg";
159  public static final String EXT_STANDARDS_STATUS = "http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status";
160  public static final String EXT_NORMATIVE_VERSION = "http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version";
161  public static final String EXT_IGP_BASE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-base";
162  public static final String EXT_IGP_DEFNS = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-defns";
163  public static final String EXT_IGP_FORMAT = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-format";
164  public static final String EXT_IGP_SOURCE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-source";
165  public static final String EXT_IGP_VERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-version";
166  public static final String EXT_IGP_RESOURCES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-resource";
167  public static final String EXT_IGP_PAGES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-pages";
168  public static final String EXT_IGP_SPREADSHEET = "http://hl7.org/fhir/StructureDefinition/igpublisher-spreadsheet";
169  public static final String EXT_IGP_MAPPING_CSV = "http://hl7.org/fhir/StructureDefinition/igpublisher-mapping-csv";
170  public static final String EXT_IGP_BUNDLE = "http://hl7.org/fhir/StructureDefinition/igpublisher-bundle";
171  public static final String EXT_IGP_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/resource-information";
172  public static final String EXT_IGP_CONTAINED_RESOURCE_INFO = "http://hl7.org/fhir/tools/StructureDefinition/contained-resource-information";
173  public static final String EXT_IGP_LOADVERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-loadversion";
174  public static final String EXT_MAX_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet";
175  public static final String EXT_MIN_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-minValueSet";
176  public static final String EXT_PROFILE_ELEMENT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-profile-element";
177  public static final String EXT_LIST_PACKAGE = "http://hl7.org/fhir/StructureDefinition/list-packageId";
178  public static final String EXT_MAPPING_NAME = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-source-name";
179  public static final String EXT_MAPPING_TYPE = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-source-type";
180  public static final String EXT_MAPPING_CARD = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-source-cardinality";
181  public static final String EXT_MAPPING_TGTTYPE = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-target-type";
182  public static final String EXT_MAPPING_TGTCARD = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-target-cardinality";
183  public static final String EXT_PRIVATE_BASE = "http://hl7.org/fhir/tools/";
184  public static final String EXT_ALLOWED_TYPE =  "http://hl7.org/fhir/StructureDefinition/operationdefinition-allowed-type";
185  public static final String EXT_FHIR_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type";
186  public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";
187  public static final String EXT_RENDERED_VALUE = "http://hl7.org/fhir/StructureDefinition/rendered-value";
188  public static final String EXT_OLD_CONCEPTMAP_EQUIVALENCE = "http://hl7.org/fhir/1.0/StructureDefinition/extension-ConceptMap.element.target.equivalence";
189  public static final String EXT_EXP_TOOCOSTLY = "http://hl7.org/fhir/StructureDefinition/valueset-toocostly";
190  public static final String EXT_MUST_SUPPORT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support";
191  public static final String EXT_TRANSLATABLE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-translatable";
192  public static final String EXT_PATTERN = "http://hl7.org/fhir/StructureDefinition/elementdefinition-pattern";
193  public static final String EXT_BINDING_METHOD = "http://hl7.org/fhir/StructureDefinition/elementdefinition-binding-method";
194  public static final String EXT_XML_NAMESPACE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace";
195  public static final String EXT_XML_NAME = "http://hl7.org/fhir/StructureDefinition/elementdefinition-xml-name";
196  public static final String EXT_BINDING_STYLE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-binding-style";
197  public static final String EXT_BINARY_FORMAT = "http://hl7.org/fhir/StructureDefinition/implementationguide-resource-format";
198  public static final String EXT_TARGET_ID = "http://hl7.org/fhir/StructureDefinition/targetElement";
199  public static final String EXT_TARGET_PATH = "http://hl7.org/fhir/StructureDefinition/targetPath";
200  public static final String EXT_VALUESET_SYSTEM = "http://hl7.org/fhir/StructureDefinition/valueset-system";
201  public static final String EXT_EXPAND_RULES = "http://hl7.org/fhir/StructureDefinition/valueset-expand-rules";
202  public static final String EXT_EXPAND_GROUP = "http://hl7.org/fhir/StructureDefinition/valueset-expand-group";
203  public static final String EXT_BINDING_ADDITIONAL = "http://hl7.org/fhir/tools/StructureDefinition/additional-binding";
204  
205  // specific extension helpers
206
207  public static Extension makeIssueSource(Source source) {
208    Extension ex = new Extension();
209    // todo: write this up and get it published with the pack (and handle the redirect?)
210    ex.setUrl(ToolingExtensions.EXT_ISSUE_SOURCE);
211    CodeType c = new CodeType();
212    c.setValue(source.toString());
213    ex.setValue(c);
214    return ex;
215  }
216
217  public static boolean hasExtension(DomainResource de, String url) {
218    return getExtension(de, url) != null;
219  }
220
221  public static boolean hasExtension(Element e, String url) {
222    return getExtension(e, url) != null;
223  }
224
225//  public static void addStringExtension(DomainResource dr, String url, String content) {
226//    if (!StringUtils.isBlank(content)) {
227//      Extension ex = getExtension(dr, url);
228//      if (ex != null)
229//        ex.setValue(new StringType(content));
230//      else
231//        dr.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
232//    }
233//  }
234
235  public static void addMarkdownExtension(DomainResource dr, String url, String content) {
236    if (!StringUtils.isBlank(content)) {
237      Extension ex = getExtension(dr, url);
238      if (ex != null)
239        ex.setValue(new StringType(content));
240      else
241        dr.getExtension().add(Factory.newExtension(url, new MarkdownType(content), true));   
242    }
243  }
244
245  public static void addStringExtension(Element e, String url, String content) {
246    if (!StringUtils.isBlank(content)) {
247      Extension ex = getExtension(e, url);
248      if (ex != null)
249        ex.setValue(new StringType(content));
250      else
251        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
252    }
253  }
254
255  public static void addCodeExtension(Element e, String url, String content) {
256    if (!StringUtils.isBlank(content)) {
257      Extension ex = getExtension(e, url);
258      if (ex != null)
259        ex.setValue(new CodeType(content));
260      else
261        e.getExtension().add(Factory.newExtension(url, new CodeType(content), true));   
262    }
263  }
264
265  public static void addStringExtension(DomainResource e, String url, String content) {
266    if (!StringUtils.isBlank(content)) {
267      Extension ex = getExtension(e, url);
268      if (ex != null)
269        ex.setValue(new StringType(content));
270      else
271        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
272    }
273  }
274
275
276  public static void addBooleanExtension(Element e, String url, boolean content) {
277    Extension ex = getExtension(e, url);
278    if (ex != null)
279      ex.setValue(new BooleanType(content));
280    else
281      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
282  }
283
284  public static void addBooleanExtension(DomainResource e, String url, boolean content) {
285    Extension ex = getExtension(e, url);
286    if (ex != null)
287      ex.setValue(new BooleanType(content));
288    else
289      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
290  }
291
292  public static void addIntegerExtension(DomainResource dr, String url, int value) {
293    Extension ex = getExtension(dr, url);
294    if (ex != null)
295      ex.setValue(new IntegerType(value));
296    else
297      dr.getExtension().add(Factory.newExtension(url, new IntegerType(value), true));   
298  }
299
300  public static void addCodeExtension(DomainResource dr, String url, String value) {
301    Extension ex = getExtension(dr, url);
302    if (ex != null)
303      ex.setValue(new CodeType(value));
304    else
305      dr.getExtension().add(Factory.newExtension(url, new CodeType(value), true));   
306  }
307
308  public static void addVSComment(ConceptSetComponent nc, String comment) {
309    if (!StringUtils.isBlank(comment))
310      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
311  }
312  public static void addVSComment(ConceptReferenceComponent nc, String comment) {
313    if (!StringUtils.isBlank(comment))
314      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
315  }
316
317  public static void addCSComment(ConceptDefinitionComponent nc, String comment) {
318    if (!StringUtils.isBlank(comment))
319      nc.getExtension().add(Factory.newExtension(EXT_CS_COMMENT, Factory.newString_(comment), true));   
320  }
321
322//  public static void markDeprecated(Element nc) {
323//    setDeprecated(nc);   
324//  }
325//
326
327  public static void addDefinition(Element nc, String definition) {
328    if (!StringUtils.isBlank(definition))
329      nc.getExtension().add(Factory.newExtension(EXT_DEFINITION, Factory.newString_(definition), true));   
330  }
331
332  public static void addDisplayHint(Element def, String hint) {
333    if (!StringUtils.isBlank(hint))
334      def.getExtension().add(Factory.newExtension(EXT_DISPLAY_HINT, Factory.newString_(hint), true));   
335  }
336
337  public static String getDisplayHint(Element def) {
338    return readStringExtension(def, EXT_DISPLAY_HINT);    
339  }
340
341  public static String readStringExtension(Element c, String uri) {
342    Extension ex = ExtensionHelper.getExtension(c, uri);
343    if (ex == null)
344      return null;
345    if (ex.getValue() instanceof UriType)
346      return ((UriType) ex.getValue()).getValue();
347    if (ex.getValue() instanceof CanonicalType)
348      return ((CanonicalType) ex.getValue()).getValue();
349    if (ex.getValue() instanceof CodeType)
350      return ((CodeType) ex.getValue()).getValue();
351    if (ex.getValue() instanceof IntegerType)
352      return ((IntegerType) ex.getValue()).asStringValue();
353    if (ex.getValue() instanceof Integer64Type)
354      return ((Integer64Type) ex.getValue()).asStringValue();
355    if (ex.getValue() instanceof DecimalType)
356      return ((DecimalType) ex.getValue()).asStringValue();
357    if ((ex.getValue() instanceof MarkdownType))
358      return ((MarkdownType) ex.getValue()).getValue();
359    if ((ex.getValue() instanceof PrimitiveType))
360      return ((PrimitiveType) ex.getValue()).primitiveValue();
361    if (!(ex.getValue() instanceof StringType))
362      return null;
363    return ((StringType) ex.getValue()).getValue();
364  }
365
366  public static String readStringExtension(DomainResource c, String uri) {
367    Extension ex = getExtension(c, uri);
368    if (ex == null)
369      return null;
370    if ((ex.getValue() instanceof StringType))
371      return ((StringType) ex.getValue()).getValue();
372    if ((ex.getValue() instanceof UriType))
373      return ((UriType) ex.getValue()).getValue();
374    if (ex.getValue() instanceof CodeType)
375      return ((CodeType) ex.getValue()).getValue();
376    if (ex.getValue() instanceof IntegerType)
377      return ((IntegerType) ex.getValue()).asStringValue();
378    if (ex.getValue() instanceof Integer64Type)
379      return ((Integer64Type) ex.getValue()).asStringValue();
380    if (ex.getValue() instanceof DecimalType)
381      return ((DecimalType) ex.getValue()).asStringValue();
382    if ((ex.getValue() instanceof MarkdownType))
383      return ((MarkdownType) ex.getValue()).getValue();
384    return null;
385  }
386
387  @SuppressWarnings("unchecked")
388  public static PrimitiveType<DataType> readPrimitiveExtension(DomainResource c, String uri) {
389    Extension ex = getExtension(c, uri);
390    if (ex == null)
391      return null;
392    return (PrimitiveType<DataType>) ex.getValue();
393  }
394
395  public static boolean findStringExtension(Element c, String uri) {
396    Extension ex = ExtensionHelper.getExtension(c, uri);
397    if (ex == null)
398      return false;
399    if (!(ex.getValue() instanceof StringType))
400      return false;
401    return !StringUtils.isBlank(((StringType) ex.getValue()).getValue());
402  }
403
404  public static Boolean readBooleanExtension(Element c, String uri) {
405    Extension ex = ExtensionHelper.getExtension(c, uri);
406    if (ex == null)
407      return null;
408    if (!(ex.getValue() instanceof BooleanType))
409      return null;
410    return ((BooleanType) ex.getValue()).getValue();
411  }
412
413  public static boolean findBooleanExtension(Element c, String uri) {
414    Extension ex = ExtensionHelper.getExtension(c, uri);
415    if (ex == null)
416      return false;
417    if (!(ex.getValue() instanceof BooleanType))
418      return false;
419    return true;
420  }
421
422  public static Boolean readBooleanExtension(DomainResource c, String uri) {
423    Extension ex = ExtensionHelper.getExtension(c, uri);
424    if (ex == null)
425      return null;
426    if (!(ex.getValue() instanceof BooleanType))
427      return null;
428    return ((BooleanType) ex.getValue()).getValue();
429  }
430
431  public static boolean readBoolExtension(DomainResource c, String uri) {
432    Extension ex = ExtensionHelper.getExtension(c, uri);
433    if (ex == null)
434      return false;
435    if (!(ex.getValue() instanceof BooleanType))
436      return false;
437    return ((BooleanType) ex.getValue()).getValue();
438  }
439
440  public static boolean readBoolExtension(Element e, String uri) {
441    Extension ex = ExtensionHelper.getExtension(e, uri);
442    if (ex == null)
443      return false;
444    if (!(ex.getValue() instanceof BooleanType))
445      return false;
446    return ((BooleanType) ex.getValue()).getValue();
447  }
448
449  public static boolean findBooleanExtension(DomainResource c, String uri) {
450    Extension ex = ExtensionHelper.getExtension(c, uri);
451    if (ex == null)
452      return false;
453    if (!(ex.getValue() instanceof BooleanType))
454      return false;
455    return true;
456  }
457
458  public static String getCSComment(ConceptDefinitionComponent c) {
459    return readStringExtension(c, EXT_CS_COMMENT);    
460  }
461//
462//  public static Boolean getDeprecated(Element c) {
463//    return readBooleanExtension(c, EXT_DEPRECATED);    
464//  }
465
466  public static boolean hasCSComment(ConceptDefinitionComponent c) {
467    return findStringExtension(c, EXT_CS_COMMENT);    
468  }
469
470//  public static boolean hasDeprecated(Element c) {
471//    return findBooleanExtension(c, EXT_DEPRECATED);    
472//  }
473
474  public static void addFlyOver(QuestionnaireItemComponent item, String text, String linkId){
475    if (!StringUtils.isBlank(text)) {
476        QuestionnaireItemComponent display = item.addItem();
477        display.setType(QuestionnaireItemType.DISPLAY);
478        display.setText(text);
479        display.setLinkId(linkId);
480        display.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept("flyover", "http://hl7.org/fhir/questionnaire-item-control", "Fly-over"), true));
481    }
482  }
483
484  public static void addMin(QuestionnaireItemComponent item, int min) {
485    item.getExtension().add(Factory.newExtension(EXT_MINOCCURS, Factory.newInteger(min), true));
486  }
487  
488  public static void addMax(QuestionnaireItemComponent item, int max) {
489    item.getExtension().add(Factory.newExtension(EXT_MAXOCCURS, Factory.newInteger(max), true));
490  }
491  
492  public static void addFhirType(QuestionnaireItemComponent group, String value) {
493    group.getExtension().add(Factory.newExtension(EXT_FHIRTYPE, Factory.newString_(value), true));       
494  }
495
496  public static void addControl(QuestionnaireItemComponent group, String value) {
497    group.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept(value, "http://hl7.org/fhir/questionnaire-item-control", value), true));
498  }
499
500  public static void addAllowedResource(QuestionnaireItemComponent group, String value) {
501    group.getExtension().add(Factory.newExtension(EXT_ALLOWEDRESOURCE, Factory.newCode(value), true));       
502  }
503
504  public static void addReferenceFilter(QuestionnaireItemComponent group, String value) {
505    group.getExtension().add(Factory.newExtension(EXT_REFERENCEFILTER, Factory.newString_(value), true));       
506  }
507
508  public static void addIdentifier(Element element, Identifier value) {
509    element.getExtension().add(Factory.newExtension(EXT_IDENTIFIER, value, true));       
510  }
511
512  /**
513   * @param name the identity of the extension of interest
514   * @return The extension, if on this element, else null
515   */
516  public static Extension getExtension(DomainResource resource, String name) {
517    if (resource == null || name == null)
518      return null;
519    if (!resource.hasExtension())
520      return null;
521    for (Extension e : resource.getExtension()) {
522      if (name.equals(e.getUrl()))
523        return e;
524    }
525    return null;
526  }
527
528  public static Extension getExtension(Element el, String name) {
529    if (name == null)
530      return null;
531    if (!el.hasExtension())
532      return null;
533    for (Extension e : el.getExtension()) {
534      if (name.equals(e.getUrl()))
535        return e;
536    }
537    return null;
538  }
539
540  public static void setStringExtension(DomainResource resource, String uri, String value) {
541    if (Utilities.noString(value))
542      return;
543        Extension ext = getExtension(resource, uri);
544    if (ext != null)
545      ext.setValue(new StringType(value));
546    else
547      resource.getExtension().add(new Extension(uri).setValue(new StringType(value)));
548  }
549
550  public static void setStringExtension(Element resource, String uri, String value) {
551    if (Utilities.noString(value))
552      return;
553        Extension ext = getExtension(resource, uri);
554    if (ext != null)
555      ext.setValue(new StringType(value));
556    else
557      resource.getExtension().add(new Extension(uri).setValue(new StringType(value)));
558  }
559
560  public static void setCodeExtension(DomainResource resource, String uri, String value) {
561    if (Utilities.noString(value))
562      return;
563    
564    Extension ext = getExtension(resource, uri);
565    if (ext != null)
566      ext.setValue(new CodeType(value));
567    else
568      resource.getExtension().add(new Extension(uri).setValue(new CodeType(value)));
569  }
570
571  public static void setCodeExtension(Element element, String uri, String value) {
572    if (Utilities.noString(value))
573      return;
574    
575    Extension ext = getExtension(element, uri);
576    if (ext != null)
577      ext.setValue(new CodeType(value));
578    else
579      element.getExtension().add(new Extension(uri).setValue(new CodeType(value)));
580  }
581
582  public static void setIntegerExtension(DomainResource resource, String uri, int value) {
583    Extension ext = getExtension(resource, uri);
584    if (ext != null)
585      ext.setValue(new IntegerType(value));
586    else
587      resource.getExtension().add(new Extension(uri).setValue(new IntegerType(value)));
588  }
589
590//  public static String getOID(CodeSystem define) {
591//    return readStringExtension(define, EXT_OID);    
592//  }
593//
594//  public static String getOID(ValueSet vs) {
595//    return readStringExtension(vs, EXT_OID);    
596//  }
597//
598//  public static void setOID(CodeSystem define, String oid) throws FHIRFormatError, URISyntaxException {
599//    if (!oid.startsWith("urn:oid:"))
600//      throw new FHIRFormatError("Error in OID format");
601//    if (oid.startsWith("urn:oid:urn:oid:"))
602//      throw new FHIRFormatError("Error in OID format");
603//    if (!hasExtension(define, EXT_OID))
604//    define.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
605//    else if (!oid.equals(readStringExtension(define, EXT_OID)))
606//      throw new Error("Attempt to assign multiple OIDs to a code system");
607//  }
608//  public static void setOID(ValueSet vs, String oid) throws FHIRFormatError, URISyntaxException {
609//    if (!oid.startsWith("urn:oid:"))
610//      throw new FHIRFormatError("Error in OID format");
611//    if (oid.startsWith("urn:oid:urn:oid:"))
612//      throw new FHIRFormatError("Error in OID format");
613//    if (!hasExtension(vs, EXT_OID))
614//    vs.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
615//    else if (!oid.equals(readStringExtension(vs, EXT_OID)))
616//      throw new Error("Attempt to assign multiple OIDs to value set "+vs.getName()+" ("+vs.getUrl()+"). Has "+readStringExtension(vs, EXT_OID)+", trying to add "+oid);
617//  }
618
619  public static boolean hasLanguageTranslation(Element element, String lang) {
620    for (Extension e : element.getExtension()) {
621      if (e.getUrl().equals(EXT_TRANSLATION)) {
622        Extension e1 = ExtensionHelper.getExtension(e, "lang");
623
624        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang))
625          return true;
626      }
627    }
628    return false;
629  }
630
631  public static String getLanguageTranslation(Element element, String lang) {
632    for (Extension e : element.getExtension()) {
633      if (e.getUrl().equals(EXT_TRANSLATION)) {
634        Extension e1 = ExtensionHelper.getExtension(e, "lang");
635
636        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang)) {
637          e1 = ExtensionHelper.getExtension(e, "content");
638          return ((StringType) e.getValue()).getValue();
639        }
640      }
641    }
642    return null;
643  }
644
645  public static void addLanguageTranslation(Element element, String lang, String value) {
646    if (Utilities.noString(lang) || Utilities.noString(value))
647      return;
648    
649    Extension extension = new Extension().setUrl(EXT_TRANSLATION);
650    extension.addExtension().setUrl("lang").setValue(new CodeType(lang));
651    extension.addExtension().setUrl("content").setValue(new StringType(value));
652    element.getExtension().add(extension);
653  }
654
655  public static DataType getAllowedUnits(ElementDefinition eld) {
656    for (Extension e : eld.getExtension()) 
657      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) 
658        return e.getValue();
659    return null;
660  }
661
662  public static void setAllowableUnits(ElementDefinition eld, CodeableConcept cc) {
663    for (Extension e : eld.getExtension()) 
664      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) {
665        e.setValue(cc);
666        return;
667      }
668    eld.getExtension().add(new Extension().setUrl(EXT_ALLOWABLE_UNITS).setValue(cc));
669  }
670
671  public static List<Extension> getExtensions(Element element, String url) {
672    List<Extension> results = new ArrayList<Extension>();
673    for (Extension ex : element.getExtension())
674      if (ex.getUrl().equals(url))
675        results.add(ex);
676    return results;
677  }
678
679  public static List<Extension> getExtensions(DomainResource resource, String url) {
680    List<Extension> results = new ArrayList<Extension>();
681    for (Extension ex : resource.getExtension())
682      if (ex.getUrl().equals(url))
683        results.add(ex);
684    return results;
685  }
686
687//  public static void addDEReference(DataElement de, String value) {
688//    for (Extension e : de.getExtension()) 
689//      if (e.getUrl().equals(EXT_CIMI_REFERENCE)) {
690//        e.setValue(new UriType(value));
691//        return;
692//      }
693//    de.getExtension().add(new Extension().setUrl(EXT_CIMI_REFERENCE).setValue(new UriType(value)));
694//  }
695
696//  public static void setDeprecated(Element nc) {
697//    for (Extension e : nc.getExtension()) 
698//      if (e.getUrl().equals(EXT_DEPRECATED)) {
699//        e.setValue(new BooleanType(true));
700//        return;
701//      }
702//    nc.getExtension().add(new Extension().setUrl(EXT_DEPRECATED).setValue(new BooleanType(true)));    
703//  }
704
705  public static void setExtension(Element focus, String url, Coding c) {
706    for (Extension e : focus.getExtension()) 
707      if (e.getUrl().equals(url)) {
708        e.setValue(c);
709        return;
710      }
711    focus.getExtension().add(new Extension().setUrl(url).setValue(c));    
712  }
713
714  public static void removeExtension(DomainResource focus, String url) {
715    Iterator<Extension> i = focus.getExtension().iterator();
716    while (i.hasNext()) {
717      Extension e = i.next(); // must be called before you can call i.remove()
718      if (e.getUrl().equals(url)) {
719        i.remove();
720      }
721    }
722  }
723  
724  public static void removeExtension(Element focus, String url) {
725    Iterator<Extension> i = focus.getExtension().iterator();
726    while (i.hasNext()) {
727      Extension e = i.next(); // must be called before you can call i.remove()
728      if (e.getUrl().equals(url)) {
729        i.remove();
730      }
731    }
732  }
733
734  public static int readIntegerExtension(DomainResource dr, String uri, int defaultValue) {
735    Extension ex = ExtensionHelper.getExtension(dr, uri);
736    if (ex == null)
737      return defaultValue;
738    if (ex.getValue() instanceof IntegerType)
739      return ((IntegerType) ex.getValue()).getValue();
740    throw new Error("Unable to read extension "+uri+" as an integer");
741  }
742
743  public static int readIntegerExtension(Element e, String uri, int defaultValue) {
744    Extension ex = ExtensionHelper.getExtension(e, uri);
745    if (ex == null)
746      return defaultValue;
747    if (ex.getValue() instanceof IntegerType)
748      return ((IntegerType) ex.getValue()).getValue();
749    throw new Error("Unable to read extension "+uri+" as an integer");
750  }
751
752  public static Map<String, String> getLanguageTranslations(Element e) {
753    Map<String, String> res = new HashMap<String, String>();
754    for (Extension ext : e.getExtension()) {
755      if (ext.getUrl().equals(EXT_TRANSLATION)) {
756        String lang = readStringExtension(ext, "lang");
757        String value = readStringExtension(ext, "content");
758        res.put(lang,  value);
759      }
760    }
761    return res;
762  }
763
764  public static StandardsStatus getStandardsStatus(DomainResource dr) throws FHIRException {
765    return StandardsStatus.fromCode(ToolingExtensions.readStringExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS));
766  }
767
768  public static void setStandardsStatus(DomainResource dr, StandardsStatus status, String normativeVersion) {
769    if (status == null)
770      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
771    else
772      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS, status.toCode());
773    if (normativeVersion == null)
774      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION);
775    else
776      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION, normativeVersion);
777  }
778
779  public static void setStandardsStatus(Element dr, StandardsStatus status, String normativeVersion) {
780    if (status == null)
781      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
782    else
783      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS, status.toCode());
784    if (normativeVersion == null)
785      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION);
786    else
787      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION, normativeVersion);
788  }
789
790  public static ValidationMessage readValidationMessage(OperationOutcomeIssueComponent issue, Source source) {
791    ValidationMessage vm = new ValidationMessage();
792    vm.setSource(source);
793    vm.setLevel(mapSeverity(issue.getSeverity()));
794    vm.setType(mapType(issue.getCode()));
795    if (issue.hasExtension(ToolingExtensions.EXT_ISSUE_LINE))
796      vm.setLine(ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_LINE, 0));
797    if (issue.hasExtension(ToolingExtensions.EXT_ISSUE_COL))
798      vm.setCol(ToolingExtensions.readIntegerExtension(issue, ToolingExtensions.EXT_ISSUE_COL, 0));
799    if (issue.hasExpression())
800      vm.setLocation(issue.getExpression().get(0).asStringValue());
801    vm.setMessage(issue.getDetails().getText());
802    if (issue.hasExtension("http://hl7.org/fhir/StructureDefinition/rendering-xhtml"))
803      vm.setHtml(ToolingExtensions.readStringExtension(issue, "http://hl7.org/fhir/StructureDefinition/rendering-xhtml"));
804    return vm;
805  }
806
807  private static IssueType mapType(org.hl7.fhir.r5.model.OperationOutcome.IssueType code) {
808    switch (code) {
809    case BUSINESSRULE: return IssueType.BUSINESSRULE;
810    case CODEINVALID: return IssueType.CODEINVALID;
811    case CONFLICT: return IssueType.CONFLICT;
812    case DELETED: return IssueType.DELETED;
813    case DUPLICATE: return IssueType.DUPLICATE;
814    case EXCEPTION: return IssueType.EXCEPTION;
815    case EXPIRED: return IssueType.EXPIRED;
816    case EXTENSION: return IssueType.EXTENSION;
817    case FORBIDDEN: return IssueType.FORBIDDEN;
818    case INCOMPLETE: return IssueType.INCOMPLETE;
819    case INFORMATIONAL: return IssueType.INFORMATIONAL;
820    case INVALID: return IssueType.INVALID;
821    case INVARIANT: return IssueType.INVARIANT;
822    case LOCKERROR: return IssueType.LOCKERROR;
823    case LOGIN: return IssueType.LOGIN;
824    case MULTIPLEMATCHES: return IssueType.MULTIPLEMATCHES;
825    case NOSTORE: return IssueType.NOSTORE;
826    case NOTFOUND: return IssueType.NOTFOUND;
827    case NOTSUPPORTED: return IssueType.NOTSUPPORTED;
828    case NULL: return IssueType.NULL;
829    case PROCESSING: return IssueType.PROCESSING;
830    case REQUIRED: return IssueType.REQUIRED;
831    case SECURITY: return IssueType.SECURITY;
832    case STRUCTURE: return IssueType.STRUCTURE;
833    case SUPPRESSED: return IssueType.SUPPRESSED;
834    case THROTTLED: return IssueType.THROTTLED;
835    case TIMEOUT: return IssueType.TIMEOUT;
836    case TOOCOSTLY: return IssueType.TOOCOSTLY;
837    case TOOLONG: return IssueType.TOOLONG;
838    case TRANSIENT: return IssueType.TRANSIENT;
839    case UNKNOWN: return IssueType.UNKNOWN;
840    case VALUE: return IssueType.VALUE;
841    default: return null;
842    }
843  }
844
845  private static IssueSeverity mapSeverity(org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity severity) {
846    switch (severity) {
847    case ERROR: return IssueSeverity.ERROR;
848    case FATAL: return IssueSeverity.FATAL;
849    case INFORMATION: return IssueSeverity.INFORMATION;
850    case WARNING: return IssueSeverity.WARNING;
851    default: return null;
852    }
853  }
854
855  public static String getPresentation(PrimitiveType<?> type) {
856    if (type.hasExtension(EXT_RENDERED_VALUE))
857      return readStringExtension(type, EXT_RENDERED_VALUE);
858    return type.primitiveValue();
859  }
860  
861  public static String getPresentation(Element holder, PrimitiveType<?> type) {
862    if (holder.hasExtension(EXT_RENDERED_VALUE))
863      return readStringExtension(holder, EXT_RENDERED_VALUE);
864    if (type.hasExtension(EXT_RENDERED_VALUE))
865      return readStringExtension(type, EXT_RENDERED_VALUE);
866    return type.primitiveValue();
867  }
868  
869//  public static boolean hasOID(ValueSet vs) {
870//    return hasExtension(vs, EXT_OID);
871//  }
872//  
873//  public static boolean hasOID(CodeSystem cs) {
874//    return hasExtension(cs, EXT_OID);
875//  }
876//  
877  public static void addUrlExtension(Element e, String url, String content) {
878    if (!StringUtils.isBlank(content)) {
879      Extension ex = getExtension(e, url);
880      if (ex != null)
881        ex.setValue(new UrlType(content));
882      else
883        e.getExtension().add(Factory.newExtension(url, new UrlType(content), true));   
884    }
885  }
886
887  public static void addUrlExtension(DomainResource dr, String url, String value) {
888    Extension ex = getExtension(dr, url);
889    if (ex != null)
890      ex.setValue(new UrlType(value));
891    else
892      dr.getExtension().add(Factory.newExtension(url, new UrlType(value), true));   
893  }
894
895  public static void addUriExtension(Element e, String url, String content) {
896    if (!StringUtils.isBlank(content)) {
897      Extension ex = getExtension(e, url);
898      if (ex != null)
899        ex.setValue(new UriType(content));
900      else
901        e.getExtension().add(Factory.newExtension(url, new UriType(content), true));   
902    }
903  }
904
905  public static void addUriExtension(DomainResource dr, String url, String value) {
906    Extension ex = getExtension(dr, url);
907    if (ex != null)
908      ex.setValue(new UriType(value));
909    else
910      dr.getExtension().add(Factory.newExtension(url, new UriType(value), true));   
911  }
912
913  public static boolean usesExtension(String url, Base base) {
914    if ("Extension".equals(base.fhirType())) {
915      Property p = base.getNamedProperty("url");
916      for (Base b : p.getValues()) {
917        if (url.equals(b.primitiveValue())) {
918          return true;
919        }
920      }
921    }
922    
923    for (Property p : base.children() ) {
924      for (Base v : p.getValues()) {
925        if (usesExtension(url, v)) {
926          return true;
927        }
928      }
929    }
930    return false;
931  }
932
933  
934}