001package org.hl7.fhir.r5.context;
002
003import java.util.ArrayList;
004import java.util.HashMap;
005import java.util.HashSet;
006import java.util.List;
007import java.util.Map;
008import java.util.Set;
009
010import org.hl7.fhir.exceptions.FHIRException;
011import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
012import org.hl7.fhir.r5.model.StructureDefinition;
013import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
014import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
015import org.hl7.fhir.utilities.Utilities;
016
017public class TypeManager {
018
019  
020  private CanonicalResourceManager<StructureDefinition> structures;
021  private Map<String, Set<StructureDefinition>> typeDefinitions = new HashMap<>();
022  private Map<String, Set<StructureDefinition>> fhirTypeDefinitions = new HashMap<>();
023  private Set<String> primitiveNames = new HashSet<>();
024  private Set<String> dataTypeNames = new HashSet<>();
025  
026  public TypeManager(CanonicalResourceManager<StructureDefinition> structures) {
027    super();
028    this.structures = structures;
029    reload();
030  }
031
032  public void reload() {
033    typeDefinitions.clear();
034    primitiveNames.clear();
035    dataTypeNames.clear();
036    for (CanonicalResourceManager<StructureDefinition>.CachedCanonicalResource<StructureDefinition> cr : structures.getCachedList()) {
037      if (!"constraint".equals(cr.getDerivation())) {
038        see(cr.getResource());
039      }
040    }    
041  }
042
043  public void see(CanonicalResourceProxy r) {
044    if (!"constraint".equals(r.getDerivation())) {
045      see((StructureDefinition) r.getResource());
046    }
047  }
048
049  public void see(StructureDefinition sd) {
050    if (sd.getDerivation() != TypeDerivationRule.CONSTRAINT && (sd.getSourcePackage() == null || !sd.getSourcePackage().isExamplesPackage())) {
051      String type = sd.getType();
052      Set<StructureDefinition> types = typeDefinitions.get(type);
053      if (types == null) {
054        types = new HashSet<>();
055        typeDefinitions.put(type, types);
056      }
057      types.add(sd);
058      if (sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/")) {
059        types = fhirTypeDefinitions.get(type);
060        if (types == null) {
061          types = new HashSet<>();
062          fhirTypeDefinitions.put(type, types);
063        }
064        types.add(sd);
065      }
066      if (Utilities.isAbsoluteUrl(type)) {
067        type = sd.getTypeTail();
068        types = typeDefinitions.get(type);
069        if (types == null) {
070          types = new HashSet<>();
071          typeDefinitions.put(type, types);
072        }
073        types.add(sd);
074      }
075      if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
076        primitiveNames.add(sd.getType());
077      } else if (sd.getKind() == StructureDefinitionKind.COMPLEXTYPE) {
078        dataTypeNames.add(sd.getType());
079      }
080    }
081  }
082
083
084  public List<StructureDefinition> getDefinitions(String typeName) {
085    List<StructureDefinition> list = new ArrayList<>();
086    Set<StructureDefinition> defined = typeDefinitions.get(typeName);
087    if (defined != null) {
088      list.addAll(defined);
089    }
090    return list;
091  }
092
093  public StructureDefinition fetchTypeDefinition(String typeName) {
094    Set<StructureDefinition> types = typeDefinitions.get(typeName);
095    if (types == null) {
096      return null; // throw new FHIRException("Unresolved type "+typeName+" (0)");
097    } else if (types.size() == 1) {
098      return types.iterator().next(); 
099    } else { 
100      types = fhirTypeDefinitions.get(typeName);
101      if (types == null) {
102        return null;
103      } else if (types.size() != 1) {
104        throw new FHIRException("Ambiguous type "+typeName+" ("+types.toString()+") (contact Grahame Grieve for investigation)");
105      } else  {
106        return types.iterator().next(); 
107      }
108    }
109  }
110
111  public boolean isPrimitive(String type) {
112    if (primitiveNames.contains(type) || Utilities.existsInList(type, "boolean", "integer", "integer64", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "uuid", "xhtml", "url", "canonical")) {
113      return true;
114    } else {
115      StructureDefinition sd = structures.get(type);
116      return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
117    }
118  }
119
120  public boolean isDataType(String type) {
121    if (dataTypeNames.contains(type) || Utilities.existsInList(type, "Address", "Age", "Annotation", "Attachment", "CodeableConcept", "Coding", "ContactPoint", "Count", "Distance", "Duration", "HumanName", "Identifier", "Money", "Period", "Quantity", "Range", "Ratio", "Reference", "SampledData", "Signature", "Timing", 
122        "ContactDetail", "Contributor", "DataRequirement", "Expression", "ParameterDefinition", "RelatedArtifact", "TriggerDefinition", "UsageContext")) {
123      return true;
124    } else {
125      StructureDefinition sd = structures.get(type);
126      return sd != null && sd.getKind() == StructureDefinitionKind.COMPLEXTYPE;      
127    }
128  }
129
130  public void unload() {
131
132    structures.unload();
133    typeDefinitions.clear(); 
134    fhirTypeDefinitions.clear();
135    primitiveNames.clear();
136    dataTypeNames.clear();
137  }
138  
139}