001package org.hl7.fhir.r5.extensions;
002
003import java.math.BigDecimal;
004import java.util.ArrayList;
005import java.util.List;
006
007import org.hl7.fhir.exceptions.FHIRException;
008import org.hl7.fhir.r5.model.BackboneElement;
009import org.hl7.fhir.r5.model.BackboneType;
010import org.hl7.fhir.r5.model.Base;
011import org.hl7.fhir.r5.model.DataType;
012import org.hl7.fhir.r5.model.DomainResource;
013import org.hl7.fhir.r5.model.Element;
014import org.hl7.fhir.r5.model.Extension;
015import org.hl7.fhir.r5.model.Property;
016import org.hl7.fhir.r5.model.Resource;
017import org.hl7.fhir.utilities.Utilities;
018
019public class ExtensionsUtils {
020
021  private static Extension setExtensionE(Element context, String url, DataType value) {
022    for (Extension ext : context.getExtension()) {
023      if (ext.getUrl().equals(url)) {
024        return ext.setValue(value);        
025      }
026    }
027    return context.addExtension().setUrl(url).setValue(value);
028  }
029
030  private static Extension setExtensionBE(BackboneElement context, boolean mod, String url, DataType value) {
031    if (mod) {
032      for (Extension ext : context.getModifierExtension()) {
033        if (ext.getUrl().equals(url)) {
034          return ext.setValue(value);        
035        }
036      }
037      return context.addModifierExtension().setUrl(url).setValue(value);
038    } else {
039      return setExtensionE(context, url, value);
040    }
041  }
042
043  private static Extension setExtensionBT(BackboneType context, boolean mod, String url, DataType value) {
044    if (mod) {
045      for (Extension ext : context.getModifierExtension()) {
046        if (ext.getUrl().equals(url)) {
047          return ext.setValue(value);        
048        }
049      } 
050      return context.addModifierExtension().setUrl(url).setValue(value);
051    } else {
052      return setExtensionE(context, url, value);
053    }
054  }  
055
056  private static Extension setExtensionR(DomainResource context, boolean mod, String url, DataType value) {
057    if (mod) {
058      for (Extension ext : context.getModifierExtension()) {
059        if (ext.getUrl().equals(url)) {
060          return ext.setValue(value);        
061        }
062      }
063      return context.addModifierExtension().setUrl(url).setValue(value);
064    } else {
065      for (Extension ext : context.getExtension()) {
066        if (ext.getUrl().equals(url)) {
067          return ext.setValue(value);        
068        }
069      }
070      return context.addExtension().setUrl(url).setValue(value);
071    }
072  }
073
074  public static Extension setExtension(Base context, String url, DataType value) {
075    boolean mod = ExtensionConstants.isModifier(url);
076    if (context instanceof BackboneElement) {
077      return setExtensionBE((BackboneElement) context, mod, url, value);
078    } else if (mod && context instanceof BackboneType) {
079      return setExtensionBT((BackboneType) context, mod, url, value);
080    } else if (context instanceof Element) {
081      if (mod) {
082        throw new FHIRException("Can't use a modifier extension on "+context.getClass().getName());
083      } else {
084        return setExtensionE((Element) context, url, value);
085      }
086    } else if (context instanceof DomainResource) {
087      return setExtensionR((DomainResource) context, mod, url, value);
088    } else {
089      throw new FHIRException("Can't use an extension on "+context.getClass().getName());
090    }
091  }
092
093
094  private static Extension addExtensionE(Element context, String url, DataType value) {
095    return context.addExtension().setValue(value);
096  }
097
098  private static Extension addExtensionBE(BackboneElement context, boolean mod, String url, DataType value) {
099    if (mod) {
100      return context.addModifierExtension().setValue(value);
101    } else {
102      return setExtensionE(context, url, value);
103    }
104  }
105
106  private static Extension addExtensionBT(BackboneType context, boolean mod, String url, DataType value) {
107    if (mod) {
108      return context.addModifierExtension().setUrl(url).setValue(value);
109    } else {
110      return setExtensionE(context, url, value);
111    }
112  }  
113
114  private static Extension addExtensionR(DomainResource context, boolean mod, String url, DataType value) {
115    if (mod) {
116      return context.addModifierExtension().setUrl(url).setValue(value);
117    } else {
118      return context.addExtension().setUrl(url).setValue(value);
119    }
120  }
121
122  public static Extension addExtension(Base context, String url, DataType value) {
123    boolean mod = ExtensionConstants.isModifier(url);
124    if (context instanceof BackboneElement) {
125      return addExtensionBE((BackboneElement) context, mod, url, value);
126    } else if (mod && context instanceof BackboneType) {
127      return addExtensionBT((BackboneType) context, mod, url, value);
128    } else if (context instanceof Element) {
129      if (mod) {
130        throw new FHIRException("Can't use a modifier extension on "+context.getClass().getName());
131      } else {
132        return addExtensionE((Element) context, url, value);
133      }
134    } else if (context instanceof DomainResource) {
135      return addExtensionR((DomainResource) context, mod, url, value);
136    } else {
137      throw new FHIRException("Can't use an extension on "+context.getClass().getName());
138    }
139  }
140
141  private static List<Extension> getAllExtensions(Base context, String url) {
142    List<Extension> list = new ArrayList<>();
143    boolean mod = ExtensionConstants.isModifier(url);
144    if (mod) {
145      if (context instanceof BackboneElement) {
146        list.addAll(((BackboneElement) context).getModifierExtension());
147      }
148      if (context instanceof BackboneType) {
149        list.addAll(((BackboneElement) context).getModifierExtension());
150      }
151      if (context instanceof DomainResource) {
152        list.addAll(((DomainResource) context).getModifierExtension());
153      }
154    } else {
155      if (context instanceof Element) {
156        list.addAll(((Element) context).getExtension());
157      }
158      if (context instanceof DomainResource) {
159        list.addAll(((DomainResource) context).getExtension());
160      }
161    }
162    return list;
163  }
164
165  public static <T extends DataType> T getExtension(Class<T> class_, Base context, String url) {
166    boolean found = false;
167    T result = null;
168    for (Extension ext : getAllExtensions(context, url)) {
169      if (ext.hasUrl() && ext.getUrl().equals(url)) {
170        if (found) {
171          throw new FHIRException("Multiple Extensions for "+url);
172        } else if (ext.hasValue() && class_.isInstance(ext.getValue())) {
173          found = true;
174          result = (T) ext.getValue();
175        }
176      }
177    }
178    return result;    
179  }
180
181  public static <T extends DataType> List<T> getExtensionList(Class<T> class_, Base context, String url) {
182    List<T> result = new ArrayList<>();
183    for (Extension ext : getAllExtensions(context, url)) {
184      if (ext.hasUrl() && ext.getUrl().equals(url)) {
185        if (ext.hasValue() && class_.isInstance(ext.getValue())) {
186          result.add((T) ext.getValue());
187        }
188      }
189    }
190    return result;    
191  }
192
193  public static String getExtensionString(Base context, String url) {
194    boolean found = false;
195    String result = null;
196    for (Extension ext : getAllExtensions(context, url)) {
197      if (ext.hasUrl() && ext.getUrl().equals(url)) {
198        if (found) {
199          throw new FHIRException("Multiple Extensions for "+url);
200        } else if (ext.hasValue() && ext.getValue().isPrimitive()) {
201          found = true;
202          result = ext.getValue().primitiveValue();
203        }
204      }
205    }
206    return result;  
207  }
208
209  public static Boolean getExtensionBoolean(Base context, String url) {
210    boolean found = false;
211    Boolean result = null;
212    for (Extension ext : getAllExtensions(context, url)) {
213      if (ext.hasUrl() && ext.getUrl().equals(url)) {
214        if (found) {
215          throw new FHIRException("Multiple Extensions for "+url);
216        } else if (ext.hasValueBooleanType()) {
217          found = true;
218          result = ext.getValueBooleanType().getValue();
219        }
220      }
221    }
222    return result;  
223  }
224
225  public static Integer getExtensionInt(Base context, String url) {
226    boolean found = false;
227    Integer result = null;
228    for (Extension ext : getAllExtensions(context, url)) {
229      if (ext.hasUrl() && ext.getUrl().equals(url)) {
230        if (found) {
231          throw new FHIRException("Multiple Extensions for "+url);
232        } else if (ext.hasValueIntegerType()) {
233          found = true;
234          result = ext.getValueIntegerType().getValue();
235        }
236      }
237    }
238    return result;  
239  }
240
241  public static BigDecimal getExtensionFloat(Base context, String url) {
242    boolean found = false;
243    BigDecimal result = null;
244    for (Extension ext : getAllExtensions(context, url)) {
245      if (ext.hasUrl() && ext.getUrl().equals(url)) {
246        if (found) {
247          throw new FHIRException("Multiple Extensions for "+url);
248        } else if (ext.hasValueIntegerType()) {
249          found = true;
250          result = ext.getValueDecimalType().getValue();
251        }
252      }
253    }
254    return result; 
255  }
256
257  public static List<String> getExtensionStringList(Base context, String url) {
258    List<String> result = new ArrayList<>();
259    for (Extension ext : getAllExtensions(context, url)) {
260      if (ext.hasUrl() && ext.getUrl().equals(url)) {
261        if (ext.hasValue() && ext.getValue().isPrimitive()) {
262          result.add(ext.getValue().primitiveValue());
263        }
264      }
265    }
266    return result; 
267  }
268
269  public static List<Integer> getExtensionIntList(Base context, String url) {
270    List<Integer> result = new ArrayList<>();
271    for (Extension ext : getAllExtensions(context, url)) {
272      if (ext.hasUrl() && ext.getUrl().equals(url)) {
273        if (ext.hasValueIntegerType()) {
274          result.add(ext.getValueIntegerType().getValue());
275        }
276      }
277    }
278    return result; 
279  }
280  
281  public static boolean stripExtensions(Element element, String... exceptions) {
282    return stripExtensions(element, Utilities.strings(exceptions));
283  }
284  
285  public static boolean stripExtensions(Element element, List<String> exceptions) {
286    boolean res = element.getExtension().removeIf(ex -> !exceptions.contains(ex.getUrl()));
287    if (element instanceof BackboneElement) {
288      res = ((BackboneElement) element).getModifierExtension().removeIf(ex -> !exceptions.contains(ex.getUrl())) || res;      
289    }
290    if (element instanceof BackboneElement) {
291      res = ((BackboneElement) element).getModifierExtension().removeIf(ex -> !exceptions.contains(ex.getUrl())) || res;      
292    }
293    for (Property p : element.children()) {
294      for (Base v : p.getValues()) {
295        if (v instanceof Element) {
296          res = stripExtensions((Element) v, exceptions) || res;
297        } else if (v instanceof Element) {
298          res = stripExtensions((Resource) v, exceptions) || res;
299        }
300      }
301    }
302    return res;
303  }
304
305  public static boolean stripExtensions(Resource resource, String... exceptions) {
306    return stripExtensions(resource, Utilities.strings(exceptions));
307  }
308  
309  public static boolean stripExtensions(Resource resource, List<String> exceptions) {
310    boolean res = false;
311    if (resource instanceof DomainResource) {
312      res = ((DomainResource) resource).getExtension().removeIf(ex -> !exceptions.contains(ex.getUrl())) ||
313            ((DomainResource) resource).getModifierExtension().removeIf(ex -> !exceptions.contains(ex.getUrl()));      
314    }
315    for (Property p : resource.children()) {
316      for (Base v : p.getValues()) {
317        if (v instanceof Element) {
318          res = stripExtensions((Element) v, exceptions) || res;
319        } else if (v instanceof Element) {
320          res = stripExtensions((Resource) v, exceptions) || res;
321        }
322      }
323    }
324    return res;
325  }
326
327  public static void copyExtensions(List<Extension> source, List<Extension> dest, String... urls) {
328    if (source != null && dest != null) {
329      for (Extension ex : source) {
330        if (Utilities.existsInList(ex.getUrl(), urls)) {
331          dest.add(ex.copy());
332        }
333      }
334    }
335  }
336
337
338
339  public static DataType getExtensionValue(List<Extension> extensions, String url) {
340    for (Extension ex : extensions) {
341      if (ex.getUrl().equals(url)) {
342        return ex.getValue();
343      }
344    }
345    return null;
346  }
347  
348
349  public static String getExtensionString(List<Extension> extensions, String url) {
350    for (Extension ex : extensions) {
351      if (ex.getUrl().equals(url)) {
352        return ex.getValue().primitiveValue();
353      }
354    }
355    return null;
356  }
357  
358
359
360  public static Integer getExtensionInteger(List<Extension> extensions, String url) {
361    for (Extension ex : extensions) {
362      if (ex.getUrl().equals(url) && ex.hasValueIntegerType()) {
363        return ex.getValueIntegerType().getValue();
364      }
365    }
366    return null;
367  }
368  
369  public static boolean hasExtension(List<Extension> extensions, String url) {
370    if (extensions == null) {
371      return false;
372    }
373    for (Extension ex : extensions) {
374      if (ex.getUrl().equals(url)) {
375        return true;
376      }
377    }
378    return false;
379  }
380}