001package org.hl7.fhir.r5.terminologies.client;
002
003import java.io.IOException;
004import java.util.HashMap;
005import java.util.HashSet;
006import java.util.Map;
007import java.util.Set;
008
009import org.hl7.fhir.r5.model.CanonicalResource;
010import org.hl7.fhir.r5.model.CapabilityStatement;
011import org.hl7.fhir.r5.model.TerminologyCapabilities;
012import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesCodeSystemComponent;
013import org.hl7.fhir.r5.model.TerminologyCapabilities.TerminologyCapabilitiesExpansionParameterComponent;
014import org.hl7.fhir.r5.terminologies.client.TerminologyClientContext.TerminologyClientContextUseCount;
015import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
016
017public class TerminologyClientContext {
018  public enum TerminologyClientContextUseType {
019    expand, validate, readVS, readCS
020  }
021  public class TerminologyClientContextUseCount {
022    private int expands;
023    private int validates;
024    private int readVS;
025    private int readCS;
026
027    public int getReadVS() {
028      return readVS;
029    }
030    public void setReadVS(int readVS) {
031      this.readVS = readVS;
032    }
033    public int getReadCS() {
034      return readCS;
035    }
036    public void setReadCS(int readCS) {
037      this.readCS = readCS;
038    }
039    public int getExpands() {
040      return expands;
041    }
042    public void setExpands(int expands) {
043      this.expands = expands;
044    }
045    public int getValidates() {
046      return validates;
047    }
048    public void setValidates(int validates) {
049      this.validates = validates;
050    }
051    
052  }
053
054  private static boolean canUseCacheId;
055
056  private ITerminologyClient client;
057  private boolean initialised = false;
058  private CapabilityStatement capabilitiesStatementQuick;
059  private TerminologyCapabilities txcaps;
060  private TerminologyCache txCache;
061  
062  private Map<String, TerminologyClientContextUseCount> useCounts = new HashMap<>();
063  private boolean isTxCaching;
064  private final Set<String> cached = new HashSet<>();
065  private boolean master;
066  private String cacheId;
067
068  protected TerminologyClientContext(ITerminologyClient client, String cacheId, boolean master) {
069    super();
070    this.client = client;
071    this.cacheId = cacheId;
072    this.master = master;
073  }
074
075  public Map<String, TerminologyClientContextUseCount> getUseCounts() {
076    return useCounts;
077  }
078
079  public boolean isMaster() {
080    return master;
081  }
082
083  public ITerminologyClient getClient() {
084    return client;
085  }
086
087  public void seeUse(Set<String> systems, TerminologyClientContextUseType useType) {
088    for (String s : systems) {
089      seeUse(s, useType);
090    }
091  }
092  
093  public void seeUse(String s, TerminologyClientContextUseType useType) {
094    TerminologyClientContextUseCount uc = useCounts.get(s);
095    if (uc == null) {
096      uc = new TerminologyClientContextUseCount();
097      useCounts.put(s,uc);
098    }
099    switch (useType) {
100    case expand:
101      uc.expands++;
102      break;
103    case readVS:
104      uc.readVS++;
105      break;
106    case readCS:
107      uc.readCS++;
108      break;
109    case validate:
110      uc.validates++;
111      break;
112    default:
113      break;
114    }
115  }
116
117  public TerminologyCapabilities getTxCapabilities() {
118    return txcaps;
119  }
120
121  public void setTxCapabilities(TerminologyCapabilities txcaps) {
122    this.txcaps = txcaps;
123  }
124
125  public Set<String> getCached() {
126    return cached;
127  }
128
129  public boolean alreadyCached(CanonicalResource cr) {
130    return cached.contains(cr.getVUrl());
131  }
132
133  public void addToCache(CanonicalResource cr) {
134    cached.add(cr.getVUrl());
135  }
136
137  public String getAddress() {
138    return client.getAddress();
139  }
140
141  public int getUseCount() {
142    return getClient().getUseCount();
143  }
144
145  public boolean isTxCaching() {
146    return isTxCaching;
147  }
148  
149  public void setTxCaching(boolean isTxCaching) {
150    this.isTxCaching = isTxCaching;
151  }
152
153  public boolean usingCache() {
154    return isTxCaching && cacheId != null;
155  }
156
157  public String getCacheId() {
158    return cacheId;
159  }
160
161  public TerminologyCache getTxCache() {
162    return txCache;
163  }
164
165  public void setTxCache(TerminologyCache txCache) {
166    this.txCache = txCache;
167  }
168
169  public void initialize() throws IOException {
170    if (!initialised) {
171      // we don't cache the quick CS - we want to know that the server is with us. 
172      capabilitiesStatementQuick =  client.getCapabilitiesStatementQuick();
173      if (txCache != null && txCache.hasTerminologyCapabilities(getAddress())) {
174        txcaps = txCache.getTerminologyCapabilities(getAddress());
175        if (txcaps.getSoftware().hasVersion() && !txcaps.getSoftware().getVersion().equals(capabilitiesStatementQuick.getSoftware().getVersion())) {
176          txcaps = null;
177        }
178      } 
179      if (txcaps == null) {
180        txcaps = client.getTerminologyCapabilities();
181        if (txCache != null) {
182          txCache.cacheTerminologyCapabilities(getAddress(), txcaps);
183        }
184      }
185      if (txcaps != null && TerminologyClientContext.canUseCacheId) {
186        for (TerminologyCapabilitiesExpansionParameterComponent t : txcaps.getExpansion().getParameter()) {
187          if ("cache-id".equals(t.getName())) {
188            setTxCaching(true);
189            break;
190          }
191        }
192      }
193      initialised = true;
194    }    
195  }
196
197  public boolean supportsSystem(String system) throws IOException {
198    initialize();
199    for (TerminologyCapabilitiesCodeSystemComponent tccs : txcaps.getCodeSystem()) {
200      if (system.equals(tccs.getUri())) {
201        return true;
202      }
203    }
204    return false;
205  }
206
207  @Override
208  public String toString() {
209    return client.getAddress();
210  }
211
212  public static boolean isCanUseCacheId() {
213    return canUseCacheId;
214  }
215
216  public static void setCanUseCacheId(boolean canUseCacheId) {
217    TerminologyClientContext.canUseCacheId = canUseCacheId;
218  }
219  
220}