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