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