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//  private static final String EXT_OID = "http://hl7.org/fhir/StructureDefinition/valueset-oid";
074//  public static final String EXT_DEPRECATED = "http://hl7.org/fhir/StructureDefinition/codesystem-deprecated";
075  public static final String EXT_DEFINITION = "http://hl7.org/fhir/StructureDefinition/valueset-concept-definition";
076  public static final String EXT_CS_COMMENT = "http://hl7.org/fhir/StructureDefinition/codesystem-concept-comments";
077  public static final String EXT_VS_COMMENT = "http://hl7.org/fhir/StructureDefinition/valueset-concept-comments";
078  private static final String EXT_IDENTIFIER = "http://hl7.org/fhir/StructureDefinition/identifier";
079  public static final String EXT_TRANSLATION = "http://hl7.org/fhir/StructureDefinition/translation";
080  public static final String EXT_ISSUE_SOURCE = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-source";
081  public static final String EXT_DISPLAY_HINT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-display-hint"; 
082  public static final String EXT_REPLACED_BY = "http://hl7.org/fhir/StructureDefinition/valueset-replacedby";
083  public static final String EXT_JSON_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type"; 
084  public static final String EXT_RDF_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-rdf-type"; 
085  public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type"; 
086  public static final String EXT_REGEX = "http://hl7.org/fhir/StructureDefinition/regex"; 
087  public static final String EXT_CONTROL = "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl"; 
088  public static final String EXT_MINOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs"; 
089  public static final String EXT_MAXOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-maxOccurs";
090  public static final String EXT_ALLOWEDRESOURCE = "http://hl7.org/fhir/StructureDefinition/questionnaire-allowedResource";
091  public static final String EXT_REFERENCEFILTER = "http://hl7.org/fhir/StructureDefinition/questionnaire-referenceFilter";
092  public static final String EXT_CODE_GENERATION_PARENT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-codegen-super";
093  public static final String EXT_HIERARCHY = "http://hl7.org/fhir/StructureDefinition/structuredefinition-hierarchy";
094  public static final String EXT_BEST_PRACTICE = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice";
095  public static final String EXT_BEST_PRACTICE_EXPLANATION = "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice-explanation";
096  // unregistered?
097  public static final String EXT_MAPPING_PREFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-prefix";
098  public static final String EXT_MAPPING_SUFFIX = "http://hl7.org/fhir/tools/StructureDefinition/logical-mapping-suffix";
099
100//  public static final String EXT_FLYOVER = "http://hl7.org/fhir/Profile/questionnaire-extensions#flyover";
101  public static final String EXT_QTYPE = "http://hl7.org/fhir/StructureDefinition/questionnnaire-baseType";
102//  private static final String EXT_QREF = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
103//  private static final String EXTENSION_FILTER_ONLY = "http://www.healthintersections.com.au/fhir/Profile/metadata#expandNeedsFilter";
104//  private static final String EXT_TYPE = "http://www.healthintersections.com.au/fhir/Profile/metadata#type";
105//  private static final String EXT_REFERENCE = "http://www.healthintersections.com.au/fhir/Profile/metadata#reference";
106  private static final String EXT_FHIRTYPE = "http://hl7.org/fhir/StructureDefinition/questionnaire-fhirType";
107  private static final String EXT_ALLOWABLE_UNITS = "http://hl7.org/fhir/StructureDefinition/elementdefinition-allowedUnits";
108  public static final String EXT_CIMI_REFERENCE = "http://hl7.org/fhir/StructureDefinition/cimi-reference";
109  public static final String EXT_UNCLOSED = "http://hl7.org/fhir/StructureDefinition/valueset-unclosed";
110  public static final String EXT_FMM_LEVEL = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm";
111  public static final String EXT_SEC_CAT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-security-category";
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_NORMATIVE_VERSION = "http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version";
118  public static final String EXT_IGP_BASE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-base";
119  public static final String EXT_IGP_DEFNS = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-defns";
120  public static final String EXT_IGP_FORMAT = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-format";
121  public static final String EXT_IGP_SOURCE = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-source";
122  public static final String EXT_IGP_VERSION = "http://hl7.org/fhir/StructureDefinition/igpublisher-res-version";
123  public static final String EXT_IGP_RESOURCES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-resource";
124  public static final String EXT_IGP_PAGES = "http://hl7.org/fhir/StructureDefinition/igpublisher-folder-pages";
125  public static final String EXT_IGP_SPREADSHEET = "http://hl7.org/fhir/StructureDefinition/igpublisher-spreadsheet";
126  public static final String EXT_IGP_BUNDLE = "http://hl7.org/fhir/StructureDefinition/igpublisher-bundle";
127  public static final String EXT_MAX_VALUESET = "http://hl7.org/fhir/StructureDefinition/elementdefinition-maxValueSet";
128  public static final String EXT_PROFILE_ELEMENT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-profile-element";
129
130
131  // specific extension helpers
132
133  public static Extension makeIssueSource(Source source) {
134    Extension ex = new Extension();
135    // todo: write this up and get it published with the pack (and handle the redirect?)
136    ex.setUrl(ToolingExtensions.EXT_ISSUE_SOURCE);
137    CodeType c = new CodeType();
138    c.setValue(source.toString());
139    ex.setValue(c);
140    return ex;
141  }
142
143  public static boolean hasExtension(DomainResource de, String url) {
144    return getExtension(de, url) != null;
145  }
146
147  public static boolean hasExtension(Element e, String url) {
148    return getExtension(e, url) != null;
149  }
150
151//  public static void addStringExtension(DomainResource dr, String url, String content) {
152//    if (!StringUtils.isBlank(content)) {
153//      Extension ex = getExtension(dr, url);
154//      if (ex != null)
155//        ex.setValue(new StringType(content));
156//      else
157//        dr.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
158//    }
159//  }
160
161  public static void addMarkdownExtension(DomainResource dr, String url, String content) {
162    if (!StringUtils.isBlank(content)) {
163      Extension ex = getExtension(dr, url);
164      if (ex != null)
165        ex.setValue(new StringType(content));
166      else
167        dr.getExtension().add(Factory.newExtension(url, new MarkdownType(content), true));   
168    }
169  }
170
171  public static void addStringExtension(Element e, String url, String content) {
172    if (!StringUtils.isBlank(content)) {
173      Extension ex = getExtension(e, url);
174      if (ex != null)
175        ex.setValue(new StringType(content));
176      else
177        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
178    }
179  }
180
181  public static void addStringExtension(DomainResource e, String url, String content) {
182    if (!StringUtils.isBlank(content)) {
183      Extension ex = getExtension(e, url);
184      if (ex != null)
185        ex.setValue(new StringType(content));
186      else
187        e.getExtension().add(Factory.newExtension(url, new StringType(content), true));   
188    }
189  }
190
191  public static void addBooleanExtension(Element e, String url, boolean content) {
192    Extension ex = getExtension(e, url);
193    if (ex != null)
194      ex.setValue(new BooleanType(content));
195    else
196      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
197  }
198
199  public static void addBooleanExtension(DomainResource e, String url, boolean content) {
200    Extension ex = getExtension(e, url);
201    if (ex != null)
202      ex.setValue(new BooleanType(content));
203    else
204      e.getExtension().add(Factory.newExtension(url, new BooleanType(content), true));   
205  }
206
207  public static void addIntegerExtension(DomainResource dr, String url, int value) {
208    Extension ex = getExtension(dr, url);
209    if (ex != null)
210      ex.setValue(new IntegerType(value));
211    else
212      dr.getExtension().add(Factory.newExtension(url, new IntegerType(value), true));   
213  }
214
215  public static void addCodeExtension(DomainResource dr, String url, String value) {
216    Extension ex = getExtension(dr, url);
217    if (ex != null)
218      ex.setValue(new CodeType(value));
219    else
220      dr.getExtension().add(Factory.newExtension(url, new CodeType(value), true));   
221  }
222
223  public static void addVSComment(ConceptSetComponent nc, String comment) {
224    if (!StringUtils.isBlank(comment))
225      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
226  }
227  public static void addVSComment(ConceptReferenceComponent nc, String comment) {
228    if (!StringUtils.isBlank(comment))
229      nc.getExtension().add(Factory.newExtension(EXT_VS_COMMENT, Factory.newString_(comment), true));   
230  }
231
232  public static void addCSComment(ConceptDefinitionComponent nc, String comment) {
233    if (!StringUtils.isBlank(comment))
234      nc.getExtension().add(Factory.newExtension(EXT_CS_COMMENT, Factory.newString_(comment), true));   
235  }
236
237//  public static void markDeprecated(Element nc) {
238//    setDeprecated(nc);   
239//  }
240//
241
242  public static void addDefinition(Element nc, String definition) {
243    if (!StringUtils.isBlank(definition))
244      nc.getExtension().add(Factory.newExtension(EXT_DEFINITION, Factory.newString_(definition), true));   
245  }
246
247  public static void addDisplayHint(Element def, String hint) {
248    if (!StringUtils.isBlank(hint))
249      def.getExtension().add(Factory.newExtension(EXT_DISPLAY_HINT, Factory.newString_(hint), true));   
250  }
251
252  public static String getDisplayHint(Element def) {
253    return readStringExtension(def, EXT_DISPLAY_HINT);    
254  }
255
256  public static String readStringExtension(Element c, String uri) {
257    Extension ex = ExtensionHelper.getExtension(c, uri);
258    if (ex == null)
259      return null;
260    if (ex.getValue() instanceof UriType)
261      return ((UriType) ex.getValue()).getValue();
262    if (ex.getValue() instanceof CanonicalType)
263      return ((CanonicalType) ex.getValue()).getValue();
264    if (ex.getValue() instanceof CodeType)
265      return ((CodeType) ex.getValue()).getValue();
266    if (ex.getValue() instanceof IntegerType)
267      return ((IntegerType) ex.getValue()).asStringValue();
268    if ((ex.getValue() instanceof MarkdownType))
269      return ((MarkdownType) ex.getValue()).getValue();
270    if (!(ex.getValue() instanceof StringType))
271      return null;
272    return ((StringType) ex.getValue()).getValue();
273  }
274
275  public static String readStringExtension(DomainResource c, String uri) {
276    Extension ex = getExtension(c, uri);
277    if (ex == null)
278      return null;
279    if ((ex.getValue() instanceof StringType))
280      return ((StringType) ex.getValue()).getValue();
281    if ((ex.getValue() instanceof UriType))
282      return ((UriType) ex.getValue()).getValue();
283    if (ex.getValue() instanceof CodeType)
284      return ((CodeType) ex.getValue()).getValue();
285    if (ex.getValue() instanceof IntegerType)
286      return ((IntegerType) ex.getValue()).asStringValue();
287    if ((ex.getValue() instanceof MarkdownType))
288      return ((MarkdownType) ex.getValue()).getValue();
289    return null;
290  }
291
292  @SuppressWarnings("unchecked")
293  public static PrimitiveType<Type> readPrimitiveExtension(DomainResource c, String uri) {
294    Extension ex = getExtension(c, uri);
295    if (ex == null)
296      return null;
297    return (PrimitiveType<Type>) ex.getValue();
298  }
299
300  public static boolean findStringExtension(Element c, String uri) {
301    Extension ex = ExtensionHelper.getExtension(c, uri);
302    if (ex == null)
303      return false;
304    if (!(ex.getValue() instanceof StringType))
305      return false;
306    return !StringUtils.isBlank(((StringType) ex.getValue()).getValue());
307  }
308
309  public static Boolean readBooleanExtension(Element c, String uri) {
310    Extension ex = ExtensionHelper.getExtension(c, uri);
311    if (ex == null)
312      return null;
313    if (!(ex.getValue() instanceof BooleanType))
314      return null;
315    return ((BooleanType) ex.getValue()).getValue();
316  }
317
318  public static boolean findBooleanExtension(Element c, String uri) {
319    Extension ex = ExtensionHelper.getExtension(c, uri);
320    if (ex == null)
321      return false;
322    if (!(ex.getValue() instanceof BooleanType))
323      return false;
324    return true;
325  }
326
327  public static Boolean readBooleanExtension(DomainResource c, String uri) {
328    Extension ex = ExtensionHelper.getExtension(c, uri);
329    if (ex == null)
330      return null;
331    if (!(ex.getValue() instanceof BooleanType))
332      return null;
333    return ((BooleanType) ex.getValue()).getValue();
334  }
335
336  public static boolean readBoolExtension(DomainResource c, String uri) {
337    Extension ex = ExtensionHelper.getExtension(c, uri);
338    if (ex == null)
339      return false;
340    if (!(ex.getValue() instanceof BooleanType))
341      return false;
342    return ((BooleanType) ex.getValue()).getValue();
343  }
344
345  public static boolean findBooleanExtension(DomainResource c, String uri) {
346    Extension ex = ExtensionHelper.getExtension(c, uri);
347    if (ex == null)
348      return false;
349    if (!(ex.getValue() instanceof BooleanType))
350      return false;
351    return true;
352  }
353
354  public static String getCSComment(ConceptDefinitionComponent c) {
355    return readStringExtension(c, EXT_CS_COMMENT);    
356  }
357//
358//  public static Boolean getDeprecated(Element c) {
359//    return readBooleanExtension(c, EXT_DEPRECATED);    
360//  }
361
362  public static boolean hasCSComment(ConceptDefinitionComponent c) {
363    return findStringExtension(c, EXT_CS_COMMENT);    
364  }
365
366//  public static boolean hasDeprecated(Element c) {
367//    return findBooleanExtension(c, EXT_DEPRECATED);    
368//  }
369
370  public static void addFlyOver(QuestionnaireItemComponent item, String text){
371    if (!StringUtils.isBlank(text)) {
372        QuestionnaireItemComponent display = item.addItem();
373        display.setType(QuestionnaireItemType.DISPLAY);
374        display.setText(text);
375        display.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept("flyover", "http://hl7.org/fhir/questionnaire-item-control", "Fly-over"), true));
376    }
377  }
378
379  public static void addMin(QuestionnaireItemComponent item, int min) {
380    item.getExtension().add(Factory.newExtension(EXT_MINOCCURS, Factory.newInteger(min), true));
381  }
382  
383  public static void addMax(QuestionnaireItemComponent item, int max) {
384    item.getExtension().add(Factory.newExtension(EXT_MAXOCCURS, Factory.newInteger(max), true));
385  }
386  
387  public static void addFhirType(QuestionnaireItemComponent group, String value) {
388    group.getExtension().add(Factory.newExtension(EXT_FHIRTYPE, Factory.newString_(value), true));       
389  }
390
391  public static void addControl(QuestionnaireItemComponent group, String value) {
392    group.getExtension().add(Factory.newExtension(EXT_CONTROL, Factory.newCodeableConcept(value, "http://hl7.org/fhir/questionnaire-item-control", value), true));
393  }
394
395  public static void addAllowedResource(QuestionnaireItemComponent group, String value) {
396    group.getExtension().add(Factory.newExtension(EXT_ALLOWEDRESOURCE, Factory.newCode(value), true));       
397  }
398
399  public static void addReferenceFilter(QuestionnaireItemComponent group, String value) {
400    group.getExtension().add(Factory.newExtension(EXT_REFERENCEFILTER, Factory.newString_(value), true));       
401  }
402
403  public static void addIdentifier(Element element, Identifier value) {
404    element.getExtension().add(Factory.newExtension(EXT_IDENTIFIER, value, true));       
405  }
406
407  /**
408   * @param name the identity of the extension of interest
409   * @return The extension, if on this element, else null
410   */
411  public static Extension getExtension(DomainResource resource, String name) {
412    if (name == null)
413      return null;
414    if (!resource.hasExtension())
415      return null;
416    for (Extension e : resource.getExtension()) {
417      if (name.equals(e.getUrl()))
418        return e;
419    }
420    return null;
421  }
422
423  public static Extension getExtension(Element el, String name) {
424    if (name == null)
425      return null;
426    if (!el.hasExtension())
427      return null;
428    for (Extension e : el.getExtension()) {
429      if (name.equals(e.getUrl()))
430        return e;
431    }
432    return null;
433  }
434
435  public static void setStringExtension(DomainResource resource, String uri, String value) {
436    if (Utilities.noString(value))
437      return;
438        Extension ext = getExtension(resource, uri);
439    if (ext != null)
440      ext.setValue(new StringType(value));
441    else
442      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new StringType(value)));
443  }
444
445  public static void setStringExtension(Element resource, String uri, String value) {
446    if (Utilities.noString(value))
447      return;
448        Extension ext = getExtension(resource, uri);
449    if (ext != null)
450      ext.setValue(new StringType(value));
451    else
452      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new StringType(value)));
453  }
454
455  public static void setCodeExtension(DomainResource resource, String uri, String value) {
456    if (Utilities.noString(value))
457      return;
458    
459    Extension ext = getExtension(resource, uri);
460    if (ext != null)
461      ext.setValue(new CodeType(value));
462    else
463      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new CodeType(value)));
464  }
465
466  public static void setCodeExtension(Element element, String uri, String value) {
467    if (Utilities.noString(value))
468      return;
469    
470    Extension ext = getExtension(element, uri);
471    if (ext != null)
472      ext.setValue(new CodeType(value));
473    else
474      element.getExtension().add(new Extension(new UriType(uri)).setValue(new CodeType(value)));
475  }
476
477  public static void setIntegerExtension(DomainResource resource, String uri, int value) {
478    Extension ext = getExtension(resource, uri);
479    if (ext != null)
480      ext.setValue(new IntegerType(value));
481    else
482      resource.getExtension().add(new Extension(new UriType(uri)).setValue(new IntegerType(value)));
483  }
484
485//  public static String getOID(CodeSystem define) {
486//    return readStringExtension(define, EXT_OID);    
487//  }
488//
489//  public static String getOID(ValueSet vs) {
490//    return readStringExtension(vs, EXT_OID);    
491//  }
492//
493//  public static void setOID(CodeSystem define, String oid) throws FHIRFormatError, URISyntaxException {
494//    if (!oid.startsWith("urn:oid:"))
495//      throw new FHIRFormatError("Error in OID format");
496//    if (oid.startsWith("urn:oid:urn:oid:"))
497//      throw new FHIRFormatError("Error in OID format");
498//    if (!hasExtension(define, EXT_OID))
499//    define.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
500//    else if (!oid.equals(readStringExtension(define, EXT_OID)))
501//      throw new Error("Attempt to assign multiple OIDs to a code system");
502//  }
503//  public static void setOID(ValueSet vs, String oid) throws FHIRFormatError, URISyntaxException {
504//    if (!oid.startsWith("urn:oid:"))
505//      throw new FHIRFormatError("Error in OID format");
506//    if (oid.startsWith("urn:oid:urn:oid:"))
507//      throw new FHIRFormatError("Error in OID format");
508//    if (!hasExtension(vs, EXT_OID))
509//    vs.getExtension().add(Factory.newExtension(EXT_OID, Factory.newUri(oid), false));       
510//    else if (!oid.equals(readStringExtension(vs, EXT_OID)))
511//      throw new Error("Attempt to assign multiple OIDs to value set "+vs.getName()+" ("+vs.getUrl()+"). Has "+readStringExtension(vs, EXT_OID)+", trying to add "+oid);
512//  }
513
514  public static boolean hasLanguageTranslation(Element element, String lang) {
515    for (Extension e : element.getExtension()) {
516      if (e.getUrl().equals(EXT_TRANSLATION)) {
517        Extension e1 = ExtensionHelper.getExtension(e, "lang");
518
519        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang))
520          return true;
521      }
522    }
523    return false;
524  }
525
526  public static String getLanguageTranslation(Element element, String lang) {
527    for (Extension e : element.getExtension()) {
528      if (e.getUrl().equals(EXT_TRANSLATION)) {
529        Extension e1 = ExtensionHelper.getExtension(e, "lang");
530
531        if (e1 != null && e1.getValue() instanceof CodeType && ((CodeType) e.getValue()).getValue().equals(lang)) {
532          e1 = ExtensionHelper.getExtension(e, "content");
533          return ((StringType) e.getValue()).getValue();
534        }
535      }
536    }
537    return null;
538  }
539
540  public static void addLanguageTranslation(Element element, String lang, String value) {
541    if (Utilities.noString(lang) || Utilities.noString(value))
542      return;
543    
544    Extension extension = new Extension().setUrl(EXT_TRANSLATION);
545    extension.addExtension().setUrl("lang").setValue(new StringType(lang));
546    extension.addExtension().setUrl("content").setValue(new StringType(value));
547    element.getExtension().add(extension);
548  }
549
550  public static Type getAllowedUnits(ElementDefinition eld) {
551    for (Extension e : eld.getExtension()) 
552      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) 
553        return e.getValue();
554    return null;
555  }
556
557  public static void setAllowableUnits(ElementDefinition eld, CodeableConcept cc) {
558    for (Extension e : eld.getExtension()) 
559      if (e.getUrl().equals(EXT_ALLOWABLE_UNITS)) {
560        e.setValue(cc);
561        return;
562      }
563    eld.getExtension().add(new Extension().setUrl(EXT_ALLOWABLE_UNITS).setValue(cc));
564  }
565
566  public static List<Extension> getExtensions(Element element, String url) {
567    List<Extension> results = new ArrayList<Extension>();
568    for (Extension ex : element.getExtension())
569      if (ex.getUrl().equals(url))
570        results.add(ex);
571    return results;
572  }
573
574  public static List<Extension> getExtensions(DomainResource resource, String url) {
575    List<Extension> results = new ArrayList<Extension>();
576    for (Extension ex : resource.getExtension())
577      if (ex.getUrl().equals(url))
578        results.add(ex);
579    return results;
580  }
581
582//  public static void addDEReference(DataElement de, String value) {
583//    for (Extension e : de.getExtension()) 
584//      if (e.getUrl().equals(EXT_CIMI_REFERENCE)) {
585//        e.setValue(new UriType(value));
586//        return;
587//      }
588//    de.getExtension().add(new Extension().setUrl(EXT_CIMI_REFERENCE).setValue(new UriType(value)));
589//  }
590
591//  public static void setDeprecated(Element nc) {
592//    for (Extension e : nc.getExtension()) 
593//      if (e.getUrl().equals(EXT_DEPRECATED)) {
594//        e.setValue(new BooleanType(true));
595//        return;
596//      }
597//    nc.getExtension().add(new Extension().setUrl(EXT_DEPRECATED).setValue(new BooleanType(true)));    
598//  }
599
600  public static void setExtension(Element focus, String url, Coding c) {
601    for (Extension e : focus.getExtension()) 
602      if (e.getUrl().equals(url)) {
603        e.setValue(c);
604        return;
605      }
606    focus.getExtension().add(new Extension().setUrl(url).setValue(c));    
607  }
608
609  public static void removeExtension(DomainResource focus, String url) {
610    Iterator<Extension> i = focus.getExtension().iterator();
611    while (i.hasNext()) {
612      Extension e = i.next(); // must be called before you can call i.remove()
613      if (e.getUrl().equals(url)) {
614        i.remove();
615      }
616    }
617  }
618  
619  public static void removeExtension(Element focus, String url) {
620    Iterator<Extension> i = focus.getExtension().iterator();
621    while (i.hasNext()) {
622      Extension e = i.next(); // must be called before you can call i.remove()
623      if (e.getUrl().equals(url)) {
624        i.remove();
625      }
626    }
627  }
628
629  public static int readIntegerExtension(DomainResource dr, String uri, int defaultValue) {
630    Extension ex = ExtensionHelper.getExtension(dr, uri);
631    if (ex == null)
632      return defaultValue;
633    if (ex.getValue() instanceof IntegerType)
634      return ((IntegerType) ex.getValue()).getValue();
635    throw new Error("Unable to read extension "+uri+" as an integer");
636  }
637
638  public static Map<String, String> getLanguageTranslations(Element e) {
639    Map<String, String> res = new HashMap<String, String>();
640    for (Extension ext : e.getExtension()) {
641      if (ext.getUrl().equals(EXT_TRANSLATION)) {
642        String lang = readStringExtension(ext, "lang");
643        String value = readStringExtension(ext, "content");
644        res.put(lang,  value);
645      }
646    }
647    return res;
648  }
649
650  public static StandardsStatus getStandardsStatus(DomainResource dr) throws FHIRException {
651    return StandardsStatus.fromCode(ToolingExtensions.readStringExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS));
652  }
653
654  public static void setStandardsStatus(DomainResource dr, StandardsStatus status, String normativeVersion) {
655    if (status == null)
656      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
657    else
658      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS, status.toCode());
659    if (normativeVersion == null)
660      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION);
661    else
662      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION, normativeVersion);
663  }
664
665  public static void setStandardsStatus(Element dr, StandardsStatus status, String normativeVersion) {
666    if (status == null)
667      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS);
668    else
669      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_STANDARDS_STATUS, status.toCode());
670    if (normativeVersion == null)
671      ToolingExtensions.removeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION);
672    else
673      ToolingExtensions.setCodeExtension(dr, ToolingExtensions.EXT_NORMATIVE_VERSION, normativeVersion);
674  }
675
676//  public static boolean hasOID(ValueSet vs) {
677//    return hasExtension(vs, EXT_OID);
678//  }
679//  
680//  public static boolean hasOID(CodeSystem cs) {
681//    return hasExtension(cs, EXT_OID);
682//  }
683//  
684  
685}