001package org.hl7.fhir.dstu3.terminologies;
002
003/*-
004 * #%L
005 * org.hl7.fhir.dstu3
006 * %%
007 * Copyright (C) 2014 - 2019 Health Level 7
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023
024import java.util.List;
025
026import org.hl7.fhir.dstu3.model.BooleanType;
027import org.hl7.fhir.dstu3.model.CodeSystem;
028import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
029import org.hl7.fhir.dstu3.model.CodeSystem.ConceptPropertyComponent;
030import org.hl7.fhir.dstu3.model.CodeSystem.PropertyComponent;
031import org.hl7.fhir.dstu3.model.CodeSystem.PropertyType;
032import org.hl7.fhir.dstu3.model.DateTimeType;
033import org.hl7.fhir.dstu3.model.Identifier;
034import org.hl7.fhir.dstu3.model.Meta;
035import org.hl7.fhir.dstu3.model.UriType;
036import org.hl7.fhir.dstu3.utils.ToolingExtensions;
037import org.hl7.fhir.exceptions.FHIRException;
038import org.hl7.fhir.exceptions.FHIRFormatError;
039import org.hl7.fhir.utilities.Utilities;
040
041public class CodeSystemUtilities {
042
043  public static boolean isDeprecated(CodeSystem cs, ConceptDefinitionComponent def) {
044    for (ConceptPropertyComponent p : def.getProperty()) {
045      if (p.getCode().equals("deprecated") && p.hasValue() && p.getValue() instanceof BooleanType) 
046        return ((BooleanType) p.getValue()).getValue();
047      if (p.getCode().equals("deprecationDate") && p.hasValue() && p.getValue() instanceof DateTimeType) 
048        return ((DateTimeType) p.getValue()).before(new DateTimeType());
049    }
050    return false;
051  }
052
053  public static boolean isNotSelectable(CodeSystem cs, ConceptDefinitionComponent def) {
054    for (ConceptPropertyComponent p : def.getProperty()) {
055      if (p.getCode().equals("notSelectable") && p.hasValue() && p.getValue() instanceof BooleanType) 
056        return ((BooleanType) p.getValue()).getValue();
057    }
058    return false;
059  }
060
061  public static void setNotSelectable(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError {
062    defineNotSelectableProperty(cs);
063    concept.addProperty().setCode("notSelectable").setValue(new BooleanType(true));    
064  }
065
066  public static void setInactive(CodeSystem cs, ConceptDefinitionComponent concept) throws FHIRFormatError {
067    defineInactiveProperty(cs);
068    concept.addProperty().setCode("inactive").setValue(new BooleanType(true));    
069  }
070
071  public static void setDeprecated(CodeSystem cs, ConceptDefinitionComponent concept, DateTimeType date) throws FHIRFormatError {
072    defineDeprecatedProperty(cs);
073    concept.addProperty().setCode("deprecationDate").setValue(date);    
074  }
075
076  public static void defineNotSelectableProperty(CodeSystem cs) {
077    defineCodeSystemProperty(cs, "notSelectable", "Indicates that the code is abstract - only intended to be used as a selector for other concepts", PropertyType.BOOLEAN);
078  }
079
080  public static void defineInactiveProperty(CodeSystem cs) {
081    defineCodeSystemProperty(cs, "inactive", "True if the concept is not considered active - e.g. not a valid concept any more", PropertyType.BOOLEAN);
082  }
083
084  public static void defineDeprecatedProperty(CodeSystem cs) {
085    defineCodeSystemProperty(cs, "deprecationDate", "The date at which a concept was deprecated. Concepts that are deprecated but not inactive can still be used, but their use is discouraged", PropertyType.DATETIME);
086  }
087
088  public static void defineCodeSystemProperty(CodeSystem cs, String code, String description, PropertyType type) {
089    for (PropertyComponent p : cs.getProperty()) {
090      if (p.getCode().equals(code))
091        return;
092    }
093    cs.addProperty().setCode(code).setDescription(description).setType(type).setUri("http://hl7.org/fhir/concept-properties#"+code);
094  }
095
096  public static String getCodeDefinition(CodeSystem cs, String code) {
097    return getCodeDefinition(cs.getConcept(), code);
098  }
099
100  private static String getCodeDefinition(List<ConceptDefinitionComponent> list, String code) {
101    for (ConceptDefinitionComponent c : list) {
102      if (c.getCode().equals(code))
103        return c.getDefinition();
104      String s = getCodeDefinition(c.getConcept(), code);
105      if (s != null)
106        return s;
107    }
108    return null;
109  }
110
111  public static CodeSystem makeShareable(CodeSystem cs) {
112    if (!cs.hasMeta())
113      cs.setMeta(new Meta());
114    for (UriType t : cs.getMeta().getProfile()) 
115      if (t.getValue().equals("http://hl7.org/fhir/StructureDefinition/shareablecodesystem"))
116        return cs;
117    cs.getMeta().getProfile().add(new UriType("http://hl7.org/fhir/StructureDefinition/shareablecodesystem"));
118    return cs;
119  }
120
121  public static void setOID(CodeSystem cs, String oid) {
122    if (!oid.startsWith("urn:oid:"))
123       oid = "urn:oid:" + oid;
124    if (!cs.hasIdentifier())
125      cs.setIdentifier(new Identifier().setSystem("urn:ietf:rfc:3986").setValue(oid));
126    else if ("urn:ietf:rfc:3986".equals(cs.getIdentifier().getSystem()) && cs.getIdentifier().hasValue() && cs.getIdentifier().getValue().startsWith("urn:oid:"))
127      cs.getIdentifier().setValue(oid);
128    else
129      throw new Error("unable to set OID on code system");
130    
131  }
132
133  public static boolean hasOID(CodeSystem cs) {
134    return getOID(cs) != null;
135  }
136
137  public static String getOID(CodeSystem cs) {
138    if (cs.hasIdentifier() && "urn:ietf:rfc:3986".equals(cs.getIdentifier().getSystem()) && cs.getIdentifier().hasValue() && cs.getIdentifier().getValue().startsWith("urn:oid:"))
139        return cs.getIdentifier().getValue().substring(8);
140    return null;
141  }
142
143  public static boolean isInactive(CodeSystem cs, ConceptDefinitionComponent def) throws FHIRException {
144    for (ConceptPropertyComponent p : def.getProperty()) {
145      if (p.getCode().equals("status") && p.hasValueStringType()) 
146        return "inactive".equals(p.getValueStringType());
147    }
148    return false;
149  }
150  
151  public static boolean isInactive(CodeSystem cs, String code) throws FHIRException {
152    ConceptDefinitionComponent def = findCode(cs.getConcept(), code);
153    if (def == null)
154      return true;
155    return isInactive(cs, def);
156  }
157
158  private static ConceptDefinitionComponent findCode(List<ConceptDefinitionComponent> list, String code) {
159    for (ConceptDefinitionComponent c : list) {
160      if (c.getCode().equals(code))
161        return c;
162      ConceptDefinitionComponent s = findCode(c.getConcept(), code);
163      if (s != null)
164        return s;
165    }
166    return null;
167  }
168
169  public static void markStatus(CodeSystem cs, String wg, String status, String fmm) {
170    if (wg != null) {
171      if (!ToolingExtensions.hasExtension(cs, ToolingExtensions.EXT_WORKGROUP) || 
172          (Utilities.existsInList(ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_WORKGROUP), "fhir", "vocab") && !Utilities.existsInList(wg, "fhir", "vocab"))) {
173        ToolingExtensions.setCodeExtension(cs, ToolingExtensions.EXT_WORKGROUP, wg);
174      }
175    }
176    if (status != null) {
177      String ss = ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_BALLOT_STATUS);
178      if (Utilities.noString(ss) || ssval(ss) < ssval(status)) 
179        ToolingExtensions.setStringExtension(cs, ToolingExtensions.EXT_BALLOT_STATUS, status);
180    }
181    if (fmm != null) {
182      String sfmm = ToolingExtensions.readStringExtension(cs, ToolingExtensions.EXT_FMM_LEVEL);
183      if (Utilities.noString(sfmm) || Integer.parseInt(sfmm) < Integer.parseInt(fmm)) 
184        ToolingExtensions.setIntegerExtension(cs, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(fmm));
185    }
186  }
187
188  private static int ssval(String status) {
189    if ("Draft".equals("status")) 
190      return 1;
191    if ("Informative".equals("status")) 
192      return 2;
193    if ("External".equals("status")) 
194      return 3;
195    if ("Trial Use".equals("status")) 
196      return 3;
197    if ("Normative".equals("status")) 
198      return 4;
199    return -1;
200  }
201
202}