001package org.hl7.fhir.dstu2.model;
002
003/*-
004 * #%L
005 * org.hl7.fhir.dstu2
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.io.Serializable;
025import java.util.ArrayList;
026import java.util.HashMap;
027import java.util.List;
028import java.util.Map;
029
030import org.hl7.fhir.instance.model.api.IBase;
031import org.hl7.fhir.exceptions.FHIRException;
032import org.hl7.fhir.utilities.xhtml.XhtmlNode;
033
034public abstract class Base implements Serializable, IBase {
035
036  /**
037   * User appended data items - allow users to add extra information to the class
038   */
039private Map<String, Object> userData; 
040
041  /**
042   * Round tracking xml comments for testing convenience
043   */
044  private List<String> formatCommentsPre; 
045   
046  /**
047   * Round tracking xml comments for testing convenience
048   */
049  private List<String> formatCommentsPost; 
050   
051  
052  public Object getUserData(String name) {
053    if (userData == null)
054      return null;
055    return userData.get(name);
056  }
057  
058  public void setUserData(String name, Object value) {
059    if (userData == null)
060      userData = new HashMap<String, Object>();
061    userData.put(name, value);
062  }
063
064  public void setUserDataINN(String name, Object value) {
065    if (value == null)
066      return;
067    
068    if (userData == null)
069      userData = new HashMap<String, Object>();
070    userData.put(name, value);
071  }
072
073  public boolean hasUserData(String name) {
074    if (userData == null)
075      return false;
076    else
077      return userData.containsKey(name);
078  }
079
080        public String getUserString(String name) {
081    return (String) getUserData(name);
082  }
083
084  public int getUserInt(String name) {
085    if (!hasUserData(name))
086      return 0;
087    return (Integer) getUserData(name);
088  }
089
090  public boolean hasFormatComment() {
091        return (formatCommentsPre != null && !formatCommentsPre.isEmpty()) || (formatCommentsPost != null && !formatCommentsPost.isEmpty());
092  }
093  
094  public List<String> getFormatCommentsPre() {
095    if (formatCommentsPre == null)
096      formatCommentsPre = new ArrayList<String>();
097    return formatCommentsPre;
098  }
099  
100  public List<String> getFormatCommentsPost() {
101    if (formatCommentsPost == null)
102      formatCommentsPost = new ArrayList<String>();
103    return formatCommentsPost;
104  }  
105  
106        // these 2 allow evaluation engines to get access to primitive values
107        public boolean isPrimitive() {
108                return false;
109        }
110        
111        public String primitiveValue() {
112                return null;
113        }
114        
115        public abstract String fhirType() ;
116        
117        public boolean hasType(String... name) {
118                String t = fhirType();
119                for (String n : name)
120                  if (n.equals(t))
121                        return true;
122                return false;
123        }
124        
125        protected abstract void listChildren(List<Property> result) ;
126        
127        public void setProperty(String name, Base value) throws FHIRException {
128          throw new FHIRException("Attempt to set unknown property "+name);
129        }
130        
131        public Base addChild(String name) throws FHIRException {
132    throw new FHIRException("Attempt to add child with unknown name "+name);
133  }
134
135  /**
136   * Supports iterating the children elements in some generic processor or browser
137   * All defined children will be listed, even if they have no value on this instance
138   * 
139   * Note that the actual content of primitive or xhtml elements is not iterated explicitly.
140   * To find these, the processing code must recognise the element as a primitive, typecast
141   * the value to a {@link Type}, and examine the value
142   *  
143   * @return a list of all the children defined for this element
144   */
145  public List<Property> children() {
146        List<Property> result = new ArrayList<Property>();
147        listChildren(result);
148        return result;
149  }
150
151  public Property getChildByName(String name) {
152    List<Property> children = new ArrayList<Property>();
153    listChildren(children);
154    for (Property c : children)
155      if (c.getName().equals(name))
156        return c;
157    return null;
158  }  
159  
160  public List<Base> listChildrenByName(String name) {
161    List<Property> children = new ArrayList<Property>();
162    listChildren(children);
163    if (name.equals("*")) {
164      List<Base> res = new ArrayList<Base>();
165      for (Property p : children) {
166        res.addAll(p.getValues());
167      }
168      return res;
169    } else {
170    for (Property c : children)
171      if (c.getName().equals(name) || (c.getName().equals(name+"[x]")))
172        return c.getValues();
173    }
174    return new ArrayList<Base>();
175  }
176
177        public boolean isEmpty() {
178          return true; // userData does not count
179  }
180
181        public boolean equalsDeep(Base other) {
182          return other != null;
183  }  
184  
185        public boolean equalsShallow(Base other) {
186          return other != null;
187  }  
188  
189        public static boolean compareDeep(List<? extends Base> e1, List<? extends Base> e2, boolean allowNull) {
190                if (noList(e1) && noList(e2) && allowNull)
191                        return true;
192                if (noList(e1) || noList(e2))
193                        return false;
194                if (e1.size() != e2.size())
195                        return false;
196                for (int i = 0; i < e1.size(); i++) {
197                        if (!compareDeep(e1.get(i), e2.get(i), allowNull))
198                                return false;
199                }
200                return true;
201        }
202        
203        private static boolean noList(List<? extends Base> list) {
204    return list == null || list.isEmpty();
205  }
206
207        public static boolean compareDeep(Base e1, Base e2, boolean allowNull) {
208                if (e1 == null && e2 == null && allowNull)
209                        return true;
210                if (e1 == null || e2 == null)
211                        return false;
212                if (e2.isMetadataBased() && !e1.isMetadataBased()) // respect existing order for debugging consistency; outcome must be the same either way
213                        return e2.equalsDeep(e1);
214                else
215                return e1.equalsDeep(e2);
216        }
217        
218        public static boolean compareDeep(XhtmlNode div1, XhtmlNode div2, boolean allowNull) {
219                if (div1 == null && div2 == null && allowNull)
220                        return true;
221                if (div1 == null || div2 == null)
222                        return false;
223                return div1.equalsDeep(div2);
224  }
225
226
227        public static boolean compareValues(List<? extends PrimitiveType> e1, List<? extends PrimitiveType> e2, boolean allowNull) {
228                if (e1 == null && e2 == null && allowNull)
229                        return true;
230                if (e1 == null || e2 == null)
231                        return false;
232                if (e1.size() != e2.size())
233                        return false;
234                for (int i = 0; i < e1.size(); i++) {
235                        if (!compareValues(e1.get(i), e2.get(i), allowNull))
236                                return false;
237                }
238                return true;
239        }
240
241        public static boolean compareValues(PrimitiveType e1, PrimitiveType e2, boolean allowNull) {
242                if (e1 == null && e2 == null && allowNull)
243                        return true;
244                if (e1 == null || e2 == null)
245                        return false;
246                return e1.equalsShallow(e2);
247  }
248        
249        // -- converters for property setters
250        
251
252        public BooleanType castToBoolean(Base b) throws FHIRException {
253                if (b instanceof BooleanType)
254                        return (BooleanType) b;
255                else
256                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Boolean");
257        }
258        
259        public IntegerType castToInteger(Base b) throws FHIRException {
260                if (b instanceof IntegerType)
261                        return (IntegerType) b;
262                else
263                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Integer");
264        }
265        
266        public DecimalType castToDecimal(Base b) throws FHIRException {
267                if (b instanceof DecimalType)
268                        return (DecimalType) b;
269                else
270                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Decimal");
271        }
272        
273        public Base64BinaryType castToBase64Binary(Base b) throws FHIRException {
274                if (b instanceof Base64BinaryType)
275                        return (Base64BinaryType) b;
276                else
277                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Base64Binary");
278        }
279        
280        public InstantType castToInstant(Base b) throws FHIRException {
281                if (b instanceof InstantType)
282                        return (InstantType) b;
283                else
284                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Instant");
285        }
286        
287        public StringType castToString(Base b) throws FHIRException {
288                if (b instanceof StringType)
289                        return (StringType) b;
290                else
291                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a String");
292        }
293        
294        public UriType castToUri(Base b) throws FHIRException {
295                if (b instanceof UriType)
296                        return (UriType) b;
297                else
298                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Uri");
299        }
300        
301        public DateType castToDate(Base b) throws FHIRException {
302                if (b instanceof DateType)
303                        return (DateType) b;
304                else
305                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Date");
306        }
307        
308        public DateTimeType castToDateTime(Base b) throws FHIRException {
309                if (b instanceof DateTimeType)
310                        return (DateTimeType) b;
311                else
312                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a DateTime");
313        }
314        
315        public TimeType castToTime(Base b) throws FHIRException {
316                if (b instanceof TimeType)
317                        return (TimeType) b;
318                else
319                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Time");
320        }
321        
322        public CodeType castToCode(Base b) throws FHIRException {
323                if (b instanceof CodeType)
324                        return (CodeType) b;
325                else
326                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Code");
327        }
328        
329        public OidType castToOid(Base b) throws FHIRException {
330                if (b instanceof OidType)
331                        return (OidType) b;
332                else
333                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Oid");
334        }
335        
336        public IdType castToId(Base b) throws FHIRException {
337                if (b instanceof IdType)
338                        return (IdType) b;
339                else
340                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Id");
341        }
342        
343        public UnsignedIntType castToUnsignedInt(Base b) throws FHIRException {
344                if (b instanceof UnsignedIntType)
345                        return (UnsignedIntType) b;
346                else
347                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a UnsignedInt");
348        }
349        
350        public PositiveIntType castToPositiveInt(Base b) throws FHIRException {
351                if (b instanceof PositiveIntType)
352                        return (PositiveIntType) b;
353                else
354                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a PositiveInt");
355        }
356        
357  public MarkdownType castToMarkdown(Base b) throws FHIRException {
358                if (b instanceof MarkdownType)
359                        return (MarkdownType) b;
360                else
361                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Markdown");
362        }
363                
364        public Annotation castToAnnotation(Base b) throws FHIRException {
365                if (b instanceof Annotation)
366                        return (Annotation) b;
367                else
368                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Annotation");
369        }
370        
371        public Attachment castToAttachment(Base b) throws FHIRException {
372                if (b instanceof Attachment)
373                        return (Attachment) b;
374                else
375                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Attachment");
376        }
377        
378        public Identifier castToIdentifier(Base b) throws FHIRException {
379                if (b instanceof Identifier)
380                        return (Identifier) b;
381                else
382                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Identifier");
383        }
384        
385        public CodeableConcept castToCodeableConcept(Base b) throws FHIRException {
386                if (b instanceof CodeableConcept)
387                        return (CodeableConcept) b;
388                else if (b instanceof CodeType) {
389                  CodeableConcept cc = new CodeableConcept();
390                  cc.addCoding().setCode(((CodeType) b).asStringValue());
391                  return cc;
392                } else
393                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a CodeableConcept");
394        }
395        
396        public Coding castToCoding(Base b) throws FHIRException {
397                if (b instanceof Coding)
398                        return (Coding) b;
399                else
400                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Coding");
401        }
402        
403        public Quantity castToQuantity(Base b) throws FHIRException {
404                if (b instanceof Quantity)
405                        return (Quantity) b;
406                else
407                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Quantity");
408        }
409        
410        public Money castToMoney(Base b) throws FHIRException {
411                if (b instanceof Money)
412                        return (Money) b;
413                else
414                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Money");
415        }
416        
417        public Duration castToDuration(Base b) throws FHIRException {
418                if (b instanceof Duration)
419                        return (Duration) b;
420                else
421                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Duration");
422        }
423        
424        public SimpleQuantity castToSimpleQuantity(Base b) throws FHIRException {
425                if (b instanceof SimpleQuantity)
426                        return (SimpleQuantity) b;
427                else if (b instanceof Quantity) {
428                  Quantity q = (Quantity) b;
429                  SimpleQuantity sq = new SimpleQuantity();
430      sq.setValueElement(q.getValueElement());
431      sq.setComparatorElement(q.getComparatorElement());
432      sq.setUnitElement(q.getUnitElement());
433      sq.setSystemElement(q.getSystemElement());
434      sq.setCodeElement(q.getCodeElement());
435      return sq;
436                } else
437                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an SimpleQuantity");
438        }
439        
440        public Range castToRange(Base b) throws FHIRException {
441                if (b instanceof Range)
442                        return (Range) b;
443                else
444                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Range");
445        }
446        
447        public Period castToPeriod(Base b) throws FHIRException {
448                if (b instanceof Period)
449                        return (Period) b;
450                else
451                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Period");
452        }
453        
454        public Ratio castToRatio(Base b) throws FHIRException {
455                if (b instanceof Ratio)
456                        return (Ratio) b;
457                else
458                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Ratio");
459        }
460        
461        public SampledData castToSampledData(Base b) throws FHIRException {
462                if (b instanceof SampledData)
463                        return (SampledData) b;
464                else
465                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a SampledData");
466        }
467        
468        public Signature castToSignature(Base b) throws FHIRException {
469                if (b instanceof Signature)
470                        return (Signature) b;
471                else
472                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Signature");
473        }
474        
475        public HumanName castToHumanName(Base b) throws FHIRException {
476                if (b instanceof HumanName)
477                        return (HumanName) b;
478                else
479                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a HumanName");
480        }
481        
482        public Address castToAddress(Base b) throws FHIRException {
483                if (b instanceof Address)
484                        return (Address) b;
485                else
486                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Address");
487        }
488        
489        public ContactPoint castToContactPoint(Base b) throws FHIRException {
490                if (b instanceof ContactPoint)
491                        return (ContactPoint) b;
492                else
493                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a ContactPoint");
494        }
495        
496        public Timing castToTiming(Base b) throws FHIRException {
497                if (b instanceof Timing)
498                        return (Timing) b;
499                else
500                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Timing");
501        }
502        
503        public Reference castToReference(Base b) throws FHIRException {
504                if (b instanceof Reference)
505                        return (Reference) b;
506                else
507                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Reference");
508        }
509        
510        public Meta castToMeta(Base b) throws FHIRException {
511                if (b instanceof Meta)
512                        return (Meta) b;
513                else
514                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Meta");
515        }
516        
517        public Extension castToExtension(Base b) throws FHIRException {
518                if (b instanceof Extension)
519                        return (Extension) b;
520                else
521                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Extension");
522        }
523        
524        public Resource castToResource(Base b) throws FHIRException {
525                if (b instanceof Resource)
526                        return (Resource) b;
527                else
528                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Resource");
529        }
530        
531        public Narrative castToNarrative(Base b) throws FHIRException {
532                if (b instanceof Narrative)
533                        return (Narrative) b;
534                else
535                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Narrative");
536        }
537        
538        
539        public ElementDefinition castToElementDefinition(Base b) throws FHIRException {
540                if (b instanceof ElementDefinition)
541                        return (ElementDefinition) b;
542                else
543                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a ElementDefinition");
544        }
545        
546        protected boolean isMetadataBased() {
547        return false;
548        }
549
550  public static boolean equals(String v1, String v2) {
551    if (v1 == null && v2 == null)
552      return true;
553    else if (v1 == null || v2 == null)
554      return false;
555    else
556      return v1.equals(v2);
557  }
558
559
560}