001package org.hl7.fhir.dstu2016may.terminologies;
002
003import java.util.List;
004
005import org.hl7.fhir.dstu2016may.model.CodeSystem;
006import org.hl7.fhir.dstu2016may.model.CodeSystem.ConceptDefinitionComponent;
007import org.hl7.fhir.dstu2016may.model.UriType;
008import org.hl7.fhir.dstu2016may.model.ValueSet;
009import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptReferenceComponent;
010import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetComponent;
011import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetFilterComponent;
012import org.hl7.fhir.dstu2016may.model.ValueSet.ValueSetExpansionContainsComponent;
013import org.hl7.fhir.dstu2016may.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
014import org.hl7.fhir.dstu2016may.utils.EOperationOutcome;
015import org.hl7.fhir.dstu2016may.utils.IWorkerContext;
016import org.hl7.fhir.dstu2016may.utils.IWorkerContext.ValidationResult;
017
018public class ValueSetCheckerSimple implements ValueSetChecker {
019
020  private ValueSet valueset;
021  private ValueSetExpanderFactory factory;
022  private IWorkerContext context;
023
024  public ValueSetCheckerSimple(ValueSet source, ValueSetExpanderFactory factory, IWorkerContext context) {
025    this.valueset = source;
026    this.factory = factory;
027    this.context = context;
028  }
029
030  @Override
031  public boolean codeInValueSet(String system, String code) throws EOperationOutcome, Exception {
032
033    if (valueset.hasCompose()) {
034      boolean ok = false;
035      for (UriType uri : valueset.getCompose().getImport()) {
036        ok = ok || inImport(uri.getValue(), system, code);
037      }
038      for (ConceptSetComponent vsi : valueset.getCompose().getInclude()) {
039        ok = ok || inComponent(vsi, system, code);
040      }
041      for (ConceptSetComponent vsi : valueset.getCompose().getExclude()) {
042        ok = ok && !inComponent(vsi, system, code);
043      }
044    }
045    
046    return false;
047  }
048
049  private boolean inImport(String uri, String system, String code) throws EOperationOutcome, Exception {
050    ValueSet vs = context.fetchResource(ValueSet.class, uri);
051    if (vs == null) 
052      return false ; // we can't tell
053    return codeInExpansion(factory.getExpander().expand(vs), system, code);
054  }
055
056  private boolean codeInExpansion(ValueSetExpansionOutcome vso, String system, String code) throws EOperationOutcome, Exception {
057    if (vso.getService() != null) {
058      return vso.getService().codeInValueSet(system, code);
059    } else {
060      for (ValueSetExpansionContainsComponent c : vso.getValueset().getExpansion().getContains()) {
061        if (code.equals(c.getCode()) && (system == null || system.equals(c.getSystem())))
062          return true;
063        if (codeinExpansion(c, system, code)) 
064          return true;
065      }
066    }
067    return false;
068  }
069
070  private boolean codeinExpansion(ValueSetExpansionContainsComponent cnt, String system, String code) {
071    for (ValueSetExpansionContainsComponent c : cnt.getContains()) {
072      if (code.equals(c.getCode()) && system.equals(c.getSystem().toString()))
073        return true;
074      if (codeinExpansion(c, system, code)) 
075        return true;
076    }
077    return false;
078  }
079
080
081  private boolean inComponent(ConceptSetComponent vsi, String system, String code) {
082    if (!vsi.getSystem().equals(system))
083      return false; 
084    // whether we know the system or not, we'll accept the stated codes at face value
085    for (ConceptReferenceComponent cc : vsi.getConcept())
086      if (cc.getCode().equals(code)) {
087        return true;
088      }
089      
090    CodeSystem def = context.fetchCodeSystem(system);
091    if (def != null) {
092      if (!def.getCaseSensitive()) {
093        // well, ok, it's not case sensitive - we'll check that too now
094        for (ConceptReferenceComponent cc : vsi.getConcept())
095          if (cc.getCode().equalsIgnoreCase(code)) {
096            return false;
097          }
098      }
099      if (vsi.getConcept().isEmpty() && vsi.getFilter().isEmpty()) {
100        return codeInDefine(def.getConcept(), code, def.getCaseSensitive());
101      }
102      for (ConceptSetFilterComponent f: vsi.getFilter())
103        throw new Error("not done yet: "+f.getValue());
104
105      return false;
106    } else if (context.supportsSystem(system)) {
107      ValidationResult vv = context.validateCode(system, code, null, vsi);
108      return vv.isOk();
109    } else
110      // we don't know this system, and can't resolve it
111      return false;
112  }
113
114  private boolean codeInDefine(List<ConceptDefinitionComponent> concepts, String code, boolean caseSensitive) {
115    for (ConceptDefinitionComponent c : concepts) {
116      if (caseSensitive && code.equals(c.getCode()))
117        return true;
118      if (!caseSensitive && code.equalsIgnoreCase(c.getCode()))
119        return true;
120      if (codeInDefine(c.getConcept(), code, caseSensitive))
121        return true;
122    }
123    return false;
124  }
125
126}