001package org.hl7.fhir.r4.utils;
002
003/*
004Copyright (c) 2011+, HL7, Inc
005All rights reserved.
006
007Redistribution and use in source and binary forms, with or without modification, 
008are 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
019THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
020ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
021WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
022IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
023INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
024NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
025PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
026WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
027ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
028POSSIBILITY OF SUCH DAMAGE.
029
030 */
031
032import java.util.ArrayList;
033import java.util.HashMap;
034import java.util.Iterator;
035import java.util.List;
036import java.util.Map;
037
038import org.apache.commons.lang3.StringUtils;
039import org.fhir.ucum.Utilities;
040import org.hl7.fhir.exceptions.FHIRException;
041import org.hl7.fhir.r4.model.BooleanType;
042import org.hl7.fhir.r4.model.CanonicalType;
043import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
044import org.hl7.fhir.r4.model.CodeType;
045import org.hl7.fhir.r4.model.CodeableConcept;
046import org.hl7.fhir.r4.model.Coding;
047import org.hl7.fhir.r4.model.DomainResource;
048import org.hl7.fhir.r4.model.Element;
049import org.hl7.fhir.r4.model.ElementDefinition;
050import org.hl7.fhir.r4.model.Extension;
051import org.hl7.fhir.r4.model.ExtensionHelper;
052import org.hl7.fhir.r4.model.Factory;
053import org.hl7.fhir.r4.model.Identifier;
054import org.hl7.fhir.r4.model.IntegerType;
055import org.hl7.fhir.r4.model.MarkdownType;
056import org.hl7.fhir.r4.model.PrimitiveType;
057import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent;
058import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
059import org.hl7.fhir.r4.model.SearchParameter;
060import org.hl7.fhir.r4.model.StringType;
061import org.hl7.fhir.r4.model.StructureDefinition;
062import org.hl7.fhir.r4.model.Type;
063import org.hl7.fhir.r4.model.UriType;
064import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceComponent;
065import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
066import org.hl7.fhir.utilities.StandardsStatus;
067import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
068
069
070public class ToolingExtensions {
071
072  // validated
073  public static final String EXT_SUBSUMES = "http://hl7.org/fhir/StructureDefinition/codesystem-subsumes"; 
074//  private static final String EXT_OID = "http://hl7.org/fhir/StructureDefinition/valueset-oid";
075//  public static final String EXT_DEPRECATED = "http://hl7.org/fhir/StructureDefinition/codesystem-deprecated";
076  public static final String EXT_DEFINITION = "http://hl7.org/fhir/StructureDefinition/valueset-definition";
077  public static final String EXT_CS_COMMENT = "http://hl7.org/fhir/StructureDefinition/codesystem-comments";
078  public static final String EXT_VS_COMMENT = "http://hl7.org/fhir/StructureDefinition/valueset-comments";
079  private static final String EXT_IDENTIFIER = "http://hl7.org/fhir/StructureDefinition/identifier";
080  public static final String EXT_TRANSLATION = "http://hl7.org/fhir/StructureDefinition/translation";
081  public static final String EXT_ISSUE_SOURCE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source";
082  public static final String EXT_DISPLAY_HINT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-display-hint"; 
083  public static final String EXT_REPLACED_BY = "http://hl7.org/fhir/StructureDefinition/valueset-replacedby";
084  public static final String EXT_JSON_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type"; 
085  public static final String EXT_RDF_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-rdf-type"; 
086  public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type"; 
087  public static final String EXT_REGEX = "http://hl7.org/fhir/StructureDefinition/regex"; 
088  public static final String EXT_CONTROL = "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl"; 
089  public static final String EXT_MINOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs"; 
090  public static final String EXT_MAXOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-maxOccurs";
091  public static final String EXT_ALLOWEDRESOURCE = "http://hl7.org/fhir/StructureDefinition/questionnaire-allowedResource";
092  public static final String EXT_REFERENCEFILTER = "http://hl7.org/fhir/StructureDefinition/questionnaire-referenceFilter";
093  public static final String EXT_CODE_GENERATION_PARENT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-codegen-super";
094  public static final String EXT_HIERARCHY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-hierarchy";
095  public static final String EXT_BEST_PRACTICE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice";
096  public static final String EXT_BEST_PRACTICE_EXPLANATION = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice-explanation";
097  // unregistered?
098  public static final String EXT_MAPPING_PREFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-prefix";
099  public static final String EXT_MAPPING_SUFFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-suffix";
100
101//  public static final String EXT_FLYOVER = "http://hl7.org/fhir/StructureDefinition/questionnaire-extensions#flyover";
102  public static final String EXT_QTYPE = "http://hl7.org/fhir/StructureDefinition/questionnnaire-baseType";
103//  private static final String EXT_QREF = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
104//  private static final String EXTENSION_FILTER_ONLY = "http://www.healthintersections.com.au/fhir/Profile/metadata#expandNeedsFilter";
105//  private static final String EXT_TYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type";
106//  private static final String EXT_REFERENCE = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
107  private static final String EXT_FHIRTYPE = "http://hl7.org/fhir/StructureDefinition/questionnaire-fhirType";
108  private static final String EXT_ALLOWABLE_UNITS = "http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits";
109  public static final String EXT_CIMI_REFERENCE = "http://hl7.org/fhir/StructureDefinition/cimi-reference";
110  public static final String EXT_UNCLOSED = "http://hl7.org/fhir/StructureDefinition/valueset-unclosed";
111  public static final String EXT_FMM_LEVEL = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm";
112  public static final String EXT_RESOURCE_CATEGORY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-category";
113  public static final String EXT_TABLE_NAME = "http://hl7.org/fhir/StructureDefinition/structuredefinition-table-name";
114  public static final String EXT_OO_FILE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-file";
115  public static final String EXT_WORKGROUP = "http://hl7.org/fhir/StructureDefinition/structuredefinition-wg";
116  public static final String EXT_STANDARDS_STATUS = "http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status";
117  public static final String EXT_IGP_BASE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-base";
118  public static final String EXT_IGP_DEFNS = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-defns";
119  public static final String EXT_IGP_FORMAT = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-format";
120  public static final String EXT_IGP_SOURCE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-source";
121  public static final String EXT_IGP_VERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-version";
122  public static final String EXT_IGP_RESOURCES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-resource";
123  public static final String EXT_IGP_PAGES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-pages";
124  public static final String EXT_IGP_SPREADSHEET = "http://hl7.org/fhir/StructureDefinition/igpublisher-spreadsheet";
125  public static final String EXT_IGP_BUNDLE = "http://hl7.org/fhir/StructureDefinition/igpublisher-bundle";
126
127
128  // specific extension helpers
129
130  public static Extension makeIssueSource(Source source) {
131    Extension ex = new Extension();
132    // todo: write this up and get it published with the pack (and handle the redirect?)
133    ex.setUrl(ToolingExtensions.EXT_ISSUE_SOURCE);
134    CodeType c = new CodeType();
135    c.setValue(source.toString());
136    ex.setValue(c);
137    return ex;
138  }
139
140  public static boolean hasExtension(DomainResource de, String url) {
141    return getExtension(de, url) != null;
142  }
143
144  public static boolean hasExtension(Element e, String url) {
145    return getExtension(e, url) != null;
146  }
147
148//  public static void addStringExtension(DomainResource dr, String url, String content) {
149//    if (!StringUtils.isBlank(content)) {
150//      Extension ex = getExtension(dr, url);
151//      if (ex != null)
152//        ex.setValue(new StringType(content));
153//      else
154//        dr.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
155//    }
156//  }
157
158  public static void addMarkdownExtension(DomainResource dr, String url, String content) {
159    if (!StringUtils.isBlank(content)) {
160      Extension ex = getExtension(dr, url);
161      if (ex != null)
162        ex.setValue(new StringType(content));
163      else
164        dr.getExtension().add(Factory.newExtension(url, new MarkdownType(content), true));   
165    }
166  }
167
168  public static void addStringExtension(Element e, String url, String content) {
169    if (!StringUtils.isBlank(content)) {
170      Extension ex = getExtension(e, url);
171      if (ex != null)
172        ex.setValue(new StringType(content));
173      else
174        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
175    }
176  }
177
178  public static void addStringExtension(DomainResource e, String url, String content) {
179    if (!StringUtils.isBlank(content)) {
180      Extension ex = getExtension(e, url);
181      if (ex != null)
182        ex.setValue(new StringType(content));
183      else
184        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
185    }
186  }
187
188  public static void addBooleanExtension(Element e, String url, boolean content) {
189    Extension ex = getExtension(e, url);
190    if (ex != null)
191      ex.setValue(new BooleanType(content));
192    else
193      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
194  }
195
196  public static void addBooleanExtension(DomainResource e, String url, boolean content) {
197    Extension ex = getExtension(e, url);
198    if (ex != null)
199      ex.setValue(new BooleanType(content));
200    else
201      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
202  }
203
204  public static void addIntegerExtension(DomainResource dr, String url, int value) {
205    Extension ex = getExtension(dr, url);
206    if (ex != null)
207      ex.setValue(new IntegerType(value));
208    else
209      dr.getExtension().add(Factory.newExtension(url, new IntegerType(value), true));   
210  }
211
212  public static void addVSComment(ConceptSetComponent nc, String comment) {
213    if (!StringUtils.isBlank(comment))
214      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
215  }
216  public static void addVSComment(ConceptReferenceComponent nc, String comment) {
217    if (!StringUtils.isBlank(comment))
218      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
219  }
220
221  public static void addCSComment(ConceptDefinitionComponent nc, String comment) {
222    if (!StringUtils.isBlank(comment))
223      nc.getExtension().add(Factory.newExtension(EXT_CS_COMMENT, Factory.newString_(comment), true));   
224  }
225
226//  public static void markDeprecated(Element nc) {
227//    setDeprecated(nc);   
228//  }
229//
230  public static void addSubsumes(ConceptDefinitionComponent nc, String code) {
231    nc.getExtension().add(Factory.newExtension(EXT_SUBSUMES, Factory.newCode(code), true));   
232  }
233
234  public static void addDefinition(Element nc, String definition) {
235    if (!StringUtils.isBlank(definition))
236      nc.getExtension().add(Factory.newExtension(EXT_DEFINITION, Factory.newString_(definition), true));   
237  }
238
239  public static void addDisplayHint(Element def, String hint) {
240    if (!StringUtils.isBlank(hint))
241      def.getExtension().add(Factory.newExtension(EXT_DISPLAY_HINT, Factory.newString_(hint), true));   
242  }
243
244  public static String getDisplayHint(Element def) {
245    return readStringExtension(def, EXT_DISPLAY_HINT);    
246  }
247
248  public static String readStringExtension(Element c, String uri) {
249    Extension ex = ExtensionHelper.getExtension(c, uri);
250    if (ex == null)
251      return null;
252    if (ex.getValue() instanceof UriType)
253      return ((UriType) ex.getValue()).getValue();
254    if (ex.getValue() instanceof CanonicalType)
255      return ((CanonicalType) ex.getValue()).getValue();
256    if (ex.getValue() instanceof CodeType)
257      return ((CodeType) ex.getValue()).getValue();
258    if (ex.getValue() instanceof IntegerType)
259      return ((IntegerType) ex.getValue()).asStringValue();
260    if ((ex.getValue() instanceof MarkdownType))
261      return ((MarkdownType) ex.getValue()).getValue();
262    if (!(ex.getValue() instanceof StringType))
263      return null;
264    return ((StringType) ex.getValue()).getValue();
265  }
266
267  public static String readStringExtension(DomainResource c, String uri) {
268    Extension ex = getExtension(c, uri);
269    if (ex == null)
270      return null;
271    if ((ex.getValue() instanceof StringType))
272      return ((StringType) ex.getValue()).getValue();
273    if ((ex.getValue() instanceof UriType))
274      return ((UriType) ex.getValue()).getValue();
275    if (ex.getValue() instanceof CodeType)
276      return ((CodeType) ex.getValue()).getValue();
277    if (ex.getValue() instanceof IntegerType)
278      return ((IntegerType) ex.getValue()).asStringValue();
279    if ((ex.getValue() instanceof MarkdownType))
280      return ((MarkdownType) ex.getValue()).getValue();
281    return null;
282  }
283
284  @SuppressWarnings("unchecked")
285  public static PrimitiveType<Type> readPrimitiveExtension(DomainResource c, String uri) {
286    Extension ex = getExtension(c, uri);
287    if (ex == null)
288      return null;
289    return (PrimitiveType<Type>) ex.getValue();
290  }
291
292  public static boolean findStringExtension(Element c, String uri) {
293    Extension ex = ExtensionHelper.getExtension(c, uri);
294    if (ex == null)
295      return false;
296    if (!(ex.getValue() instanceof StringType))
297      return false;
298    return !StringUtils.isBlank(((StringType) ex.getValue()).getValue());
299  }
300
301  public static Boolean readBooleanExtension(Element c, String uri) {
302    Extension ex = ExtensionHelper.getExtension(c, uri);
303    if (ex == null)
304      return null;
305    if (!(ex.getValue() instanceof BooleanType))
306      return null;
307    return ((BooleanType) ex.getValue()).getValue();
308  }
309
310  public static boolean findBooleanExtension(Element c, String uri) {
311    Extension ex = ExtensionHelper.getExtension(c, uri);
312    if (ex == null)
313      return false;
314    if (!(ex.getValue() instanceof BooleanType))
315      return false;
316    return true;
317  }
318
319  public static Boolean readBooleanExtension(DomainResource c, String uri) {
320    Extension ex = ExtensionHelper.getExtension(c, uri);
321    if (ex == null)
322      return null;
323    if (!(ex.getValue() instanceof BooleanType))
324      return null;
325    return ((BooleanType) ex.getValue()).getValue();
326  }
327
328  public static boolean readBoolExtension(DomainResource c, String uri) {
329    Extension ex = ExtensionHelper.getExtension(c, uri);
330    if (ex == null)
331      return false;
332    if (!(ex.getValue() instanceof BooleanType))
333      return false;
334    return ((BooleanType) ex.getValue()).getValue();
335  }
336
337  public static boolean findBooleanExtension(DomainResource c, String uri) {
338    Extension ex = ExtensionHelper.getExtension(c, uri);
339    if (ex == null)
340      return false;
341    if (!(ex.getValue() instanceof BooleanType))
342      return false;
343    return true;
344  }
345
346  public static String getCSComment(ConceptDefinitionComponent c) {
347    return readStringExtension(c, EXT_CS_COMMENT);    
348  }
349//
350//  public static Boolean getDeprecated(Element c) {
351//    return readBooleanExtension(c, EXT_DEPRECATED);    
352//  }
353
354  public static boolean hasCSComment(ConceptDefinitionComponent c) {
355    return findStringExtension(c, EXT_CS_COMMENT);    
356  }
357
358//  public static boolean hasDeprecated(Element c) {
359//    return findBooleanExtension(c, EXT_DEPRECATED);    
360//  }
361
362  public static List<CodeType> getSubsumes(ConceptDefinitionComponent c) {
363    List<CodeType> res = new ArrayList<CodeType>();
364
365    for (Extension e : c.getExtension()) {
366      if (EXT_SUBSUMES.equals(e.getUrl()))
367        res.add((CodeType) e.getValue());
368    }
369    return res;
370  }
371
372  public static void addFlyOver(QuestionnaireItemComponent item, String text){
373    if (!StringUtils.isBlank(text)) {
374        QuestionnaireItemComponent display = item.addItem();
375        display.setType(QuestionnaireItemType.DISPLAY);
376        display.setText(text);
377        display.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept("flyover", "http://hl7.org/fhir/questionnaire-item-control", "Fly-over"), true));
378    }
379  }
380
381  public static void addMin(QuestionnaireItemComponent item, int min) {
382    item.getExtension().add(Factory.newExtension(EXT_MINOCCURS, Factory.newInteger(min), true));
383  }
384  
385  public static void addMax(QuestionnaireItemComponent item, int max) {
386    item.getExtension().add(Factory.newExtension(EXT_MAXOCCURS, Factory.newInteger(max), true));
387  }
388  
389  public static void addFhirType(QuestionnaireItemComponent group, String value) {
390    group.getExtension().add(Factory.newExtension(EXT_FHIRTYPE, Factory.newString_(value), true));       
391  }
392
393  public static void addControl(QuestionnaireItemComponent group, String value) {
394    group.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept(value, "http://hl7.org/fhir/questionnaire-item-control", value), true));
395  }
396
397  public static void addAllowedResource(QuestionnaireItemComponent group, String value) {
398    group.getExtension().add(Factory.newExtension(EXT_ALLOWEDRESOURCE, Factory.newCode(value), true));       
399  }
400
401  public static void addReferenceFilter(QuestionnaireItemComponent group, String value) {
402    group.getExtension().add(Factory.newExtension(EXT_REFERENCEFILTER, Factory.newString_(value), true));       
403  }
404
405  public static void addIdentifier(Element element, Identifier value) {
406    element.getExtension().add(Factory.newExtension(EXT_IDENTIFIER, value, true));       
407  }
408
409  /**
410   * @param name the identity of the extension of interest
411   * @return The extension, if on this element, else null
412   */
413  public static Extension getExtension(DomainResource resource, String name) {
414    if (name == null)
415      return null;
416    if (!resource.hasExtension())
417      return null;
418    for (Extension e : resource.getExtension()) {
419      if (name.equals(e.getUrl()))
420        return e;
421    }
422    return null;
423  }
424
425  public static Extension getExtension(Element el, String name) {
426    if (name == null)
427      return null;
428    if (!el.hasExtension())
429      return null;
430    for (Extension e : el.getExtension()) {
431      if (name.equals(e.getUrl()))
432        return e;
433    }
434    return null;
435  }
436
437  public static void setStringExtension(DomainResource resource, String uri, String value) {
438    if (Utilities.noString(value))
439      return;
440        Extension ext = getExtension(resource, uri);
441    if (ext != null)
442      ext.setValue(new StringType(value));
443    else
444      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new StringType(value)));
445  }
446
447  public static void setCodeExtension(DomainResource resource, String uri, String value) {
448    if (Utilities.noString(value))
449      return;
450    
451    Extension ext = getExtension(resource, uri);
452    if (ext != null)
453      ext.setValue(new CodeType(value));
454    else
455      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new CodeType(value)));
456  }
457
458  public static void setIntegerExtension(DomainResource resource, String uri, int value) {
459    Extension ext = getExtension(resource, uri);
460    if (ext != null)
461      ext.setValue(new IntegerType(value));
462    else
463      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new IntegerType(value)));
464  }
465
466//  public static String getOID(CodeSystem define) {
467//    return readStringExtension(define, EXT_OID);    
468//  }
469//
470//  public static String getOID(ValueSet vs) {
471//    return readStringExtension(vs, EXT_OID);    
472//  }
473//
474//  public static void setOID(CodeSystem define, String oid) throws FHIRFormatError, URISyntaxException {
475//    if (!oid.startsWith("urn:oid:"))
476//      throw new FHIRFormatError("Error in OID format");
477//    if (oid.startsWith("urn:oid:urn:oid:"))
478//      throw new FHIRFormatError("Error in OID format");
479//    if (!hasExtension(define, EXT_OID))
480//    define.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
481//    else if (!oid.equals(readStringExtension(define, EXT_OID)))
482//      throw new Error("Attempt to assign multiple OIDs to a code system");
483//  }
484//  public static void setOID(ValueSet vs, String oid) throws FHIRFormatError, URISyntaxException {
485//    if (!oid.startsWith("urn:oid:"))
486//      throw new FHIRFormatError("Error in OID format");
487//    if (oid.startsWith("urn:oid:urn:oid:"))
488//      throw new FHIRFormatError("Error in OID format");
489//    if (!hasExtension(vs, EXT_OID))
490//    vs.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
491//    else if (!oid.equals(readStringExtension(vs, EXT_OID)))
492//      throw new Error("Attempt to assign multiple OIDs to value set "+vs.getName()+" ("+vs.getUrl()+"). Has "+readStringExtension(vs, EXT_OID)+", trying to add "+oid);
493//  }
494
495  public static boolean hasLanguageTranslation(Element element, String lang) {
496    for (Extension e : element.getExtension()) {
497      if (e.getUrl().equals(EXT_TRANSLATION)) {
498        Extension e1 = ExtensionHelper.getExtension(e, "lang");
499
500        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang))
501          return true;
502      }
503    }
504    return false;
505  }
506
507  public static String getLanguageTranslation(Element element, String lang) {
508    for (Extension e : element.getExtension()) {
509      if (e.getUrl().equals(EXT_TRANSLATION)) {
510        Extension e1 = ExtensionHelper.getExtension(e, "lang");
511
512        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang)) {
513          e1 = ExtensionHelper.getExtension(e, "content");
514          return ((StringType) e.getValue()).getValue();
515        }
516      }
517    }
518    return null;
519  }
520
521  public static void addLanguageTranslation(Element element, String lang, String value) {
522    if (Utilities.noString(lang) || Utilities.noString(value))
523      return;
524    
525    Extension extension = new Extension().setUrl(EXT_TRANSLATION);
526    extension.addExtension().setUrl("lang").setValue(new StringType(lang));
527    extension.addExtension().setUrl("content").setValue(new StringType(value));
528    element.getExtension().add(extension);
529  }
530
531  public static Type getAllowedUnits(ElementDefinition eld) {
532    for (Extension e : eld.getExtension()) 
533      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) 
534        return e.getValue();
535    return null;
536  }
537
538  public static void setAllowableUnits(ElementDefinition eld, CodeableConcept cc) {
539    for (Extension e : eld.getExtension()) 
540      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) {
541        e.setValue(cc);
542        return;
543      }
544    eld.getExtension().add(new Extension().setUrl(EXT_ALLOWABLE_UNITS).setValue(cc));
545  }
546
547  public static List<Extension> getExtensions(Element element, String url) {
548    List<Extension> results = new ArrayList<Extension>();
549    for (Extension ex : element.getExtension())
550      if (ex.getUrl().equals(url))
551        results.add(ex);
552    return results;
553  }
554
555  public static List<Extension> getExtensions(DomainResource resource, String url) {
556    List<Extension> results = new ArrayList<Extension>();
557    for (Extension ex : resource.getExtension())
558      if (ex.getUrl().equals(url))
559        results.add(ex);
560    return results;
561  }
562
563//  public static void addDEReference(DataElement de, String value) {
564//    for (Extension e : de.getExtension()) 
565//      if (e.getUrl().equals(EXT_CIMI_REFERENCE)) {
566//        e.setValue(new UriType(value));
567//        return;
568//      }
569//    de.getExtension().add(new Extension().setUrl(EXT_CIMI_REFERENCE).setValue(new UriType(value)));
570//  }
571
572//  public static void setDeprecated(Element nc) {
573//    for (Extension e : nc.getExtension()) 
574//      if (e.getUrl().equals(EXT_DEPRECATED)) {
575//        e.setValue(new BooleanType(true));
576//        return;
577//      }
578//    nc.getExtension().add(new Extension().setUrl(EXT_DEPRECATED).setValue(new BooleanType(true)));    
579//  }
580
581  public static void setExtension(Element focus, String url, Coding c) {
582    for (Extension e : focus.getExtension()) 
583      if (e.getUrl().equals(url)) {
584        e.setValue(c);
585        return;
586      }
587    focus.getExtension().add(new Extension().setUrl(url).setValue(c));    
588  }
589
590  public static void removeExtension(DomainResource focus, String url) {
591    Iterator<Extension> i = focus.getExtension().iterator();
592    while (i.hasNext()) {
593      Extension e = i.next(); // must be called before you can call i.remove()
594      if (e.getUrl().equals(url)) {
595        i.remove();
596      }
597    }
598  }
599  
600  public static void removeExtension(Element focus, String url) {
601    Iterator<Extension> i = focus.getExtension().iterator();
602    while (i.hasNext()) {
603      Extension e = i.next(); // must be called before you can call i.remove()
604      if (e.getUrl().equals(url)) {
605        i.remove();
606      }
607    }
608  }
609
610  public static int readIntegerExtension(DomainResource dr, String uri, int defaultValue) {
611    Extension ex = ExtensionHelper.getExtension(dr, uri);
612    if (ex == null)
613      return defaultValue;
614    if (ex.getValue() instanceof IntegerType)
615      return ((IntegerType) ex.getValue()).getValue();
616    throw new Error("Unable to read extension "+uri+" as an integer");
617  }
618
619  public static Map<String, String> getLanguageTranslations(Element e) {
620    Map<String, String> res = new HashMap<String, String>();
621    for (Extension ext : e.getExtension()) {
622      if (ext.getUrl().equals(EXT_TRANSLATION)) {
623        String lang = readStringExtension(ext, "lang");
624        String value = readStringExtension(ext, "content");
625        res.put(lang,  value);
626      }
627    }
628    return res;
629  }
630
631  public static StandardsStatus getStandardsStatus(DomainResource dr) throws FHIRException {
632    return StandardsStatus.fromCode(ToolingExtensions.readStringExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS));
633  }
634
635  public static void setStandardsStatus(DomainResource dr, StandardsStatus status) {
636    if (status == null)
637      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
638    else
639      ToolingExtensions.setStringExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS, status.toDisplay());
640  }
641
642//  public static boolean hasOID(ValueSet vs) {
643//    return hasExtension(vs, EXT_OID);
644//  }
645//  
646//  public static boolean hasOID(CodeSystem cs) {
647//    return hasExtension(cs, EXT_OID);
648//  }
649//  
650  
651}