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