001package org.hl7.fhir.dstu3.model;
002
003import java.io.IOException;
004import java.io.Serializable;
005import java.util.ArrayList;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009
010import org.hl7.fhir.dstu3.elementmodel.Element;
011import org.hl7.fhir.exceptions.FHIRException;
012import org.hl7.fhir.instance.model.api.IBase;
013import org.hl7.fhir.utilities.Utilities;
014import org.hl7.fhir.utilities.xhtml.XhtmlNode;
015import org.hl7.fhir.utilities.xhtml.XhtmlParser;
016
017import ca.uhn.fhir.model.api.IElement;
018//Add comment to test SVN
019public abstract class Base implements Serializable, IBase, IElement {
020
021  /**
022   * User appended data items - allow users to add extra information to the class
023   */
024private Map<String, Object> userData; 
025
026  /**
027   * Round tracking xml comments for testing convenience
028   */
029  private List<String> formatCommentsPre; 
030   
031  /**
032   * Round tracking xml comments for testing convenience
033   */
034  private List<String> formatCommentsPost; 
035   
036  
037  public Object getUserData(String name) {
038    if (userData == null)
039      return null;
040    return userData.get(name);
041  }
042  
043  public void setUserData(String name, Object value) {
044    if (userData == null)
045      userData = new HashMap<String, Object>();
046    userData.put(name, value);
047  }
048
049  public void clearUserData(String name) {
050    if (userData != null)
051      userData.remove(name);
052  }
053  
054  public void setUserDataINN(String name, Object value) {
055    if (value == null)
056      return;
057    
058    if (userData == null)
059      userData = new HashMap<String, Object>();
060    userData.put(name, value);
061  }
062
063  public boolean hasUserData(String name) {
064    if (userData == null)
065      return false;
066    else
067      return userData.containsKey(name);
068  }
069
070        public String getUserString(String name) {
071    Object ud = getUserData(name);
072    if (ud == null)
073      return null;
074    if (ud instanceof String)
075      return (String) ud;
076    return ud.toString();
077  }
078
079  public int getUserInt(String name) {
080    if (!hasUserData(name))
081      return 0;
082    return (Integer) getUserData(name);
083  }
084
085  public boolean hasFormatComment() {
086        return (formatCommentsPre != null && !formatCommentsPre.isEmpty()) || (formatCommentsPost != null && !formatCommentsPost.isEmpty());
087  }
088  
089  public List<String> getFormatCommentsPre() {
090    if (formatCommentsPre == null)
091      formatCommentsPre = new ArrayList<String>();
092    return formatCommentsPre;
093  }
094  
095  public List<String> getFormatCommentsPost() {
096    if (formatCommentsPost == null)
097      formatCommentsPost = new ArrayList<String>();
098    return formatCommentsPost;
099  }  
100  
101        // these 3 allow evaluation engines to get access to primitive values
102        public boolean isPrimitive() {
103                return false;
104        }
105        
106        public boolean hasPrimitiveValue() {
107                return isPrimitive();
108        }
109        
110        public String primitiveValue() {
111                return null;
112        }
113        
114        public abstract String fhirType() ;
115        
116        public boolean hasType(String... name) {
117                String t = fhirType();
118                for (String n : name)
119                  if (n.equalsIgnoreCase(t))
120                        return true;
121                return false;
122        }
123        
124        protected abstract void listChildren(List<Property> result) ;
125        
126        public Base setProperty(String name, Base value) throws FHIRException {
127          throw new FHIRException("Attempt to set unknown property "+name);
128        }
129        
130        public Base addChild(String name) throws FHIRException {
131    throw new FHIRException("Attempt to add child with unknown name "+name);
132  }
133
134  /**
135   * Supports iterating the children elements in some generic processor or browser
136   * All defined children will be listed, even if they have no value on this instance
137   * 
138   * Note that the actual content of primitive or xhtml elements is not iterated explicitly.
139   * To find these, the processing code must recognise the element as a primitive, typecast
140   * the value to a {@link Type}, and examine the value
141   *  
142   * @return a list of all the children defined for this element
143   */
144  public List<Property> children() {
145        List<Property> result = new ArrayList<Property>();
146        listChildren(result);
147        return result;
148  }
149
150  public Property getChildByName(String name) {
151    List<Property> children = new ArrayList<Property>();
152    listChildren(children);
153    for (Property c : children)
154      if (c.getName().equals(name))
155        return c;
156    return null;
157  }  
158  
159  public List<Base> listChildrenByName(String name) throws FHIRException {
160    List<Base> result = new ArrayList<Base>();
161        for (Base b : listChildrenByName(name, true))
162                if (b != null)
163                  result.add(b);
164    return result;
165  }
166
167  public Base[] listChildrenByName(String name, boolean checkValid) throws FHIRException {
168        if (name.equals("*")) {
169                List<Property> children = new ArrayList<Property>();
170                listChildren(children);
171                List<Base> result = new ArrayList<Base>();
172                for (Property c : children)
173                                result.addAll(c.getValues());
174                return result.toArray(new Base[result.size()]);
175        }
176        else
177        return getProperty(name.hashCode(), name, checkValid);
178  }
179
180        public boolean isEmpty() {
181          return true; // userData does not count
182  }
183
184        public boolean equalsDeep(Base other) {
185          return other != null;
186  }  
187  
188        public boolean equalsShallow(Base other) {
189          return other != null;
190  }  
191  
192        public static boolean compareDeep(List<? extends Base> e1, List<? extends Base> e2, boolean allowNull) {
193                if (noList(e1) && noList(e2) && allowNull)
194                        return true;
195                if (noList(e1) || noList(e2))
196                        return false;
197                if (e1.size() != e2.size())
198                        return false;
199                for (int i = 0; i < e1.size(); i++) {
200                        if (!compareDeep(e1.get(i), e2.get(i), allowNull))
201                                return false;
202                }
203                return true;
204        }
205        
206        private static boolean noList(List<? extends Base> list) {
207    return list == null || list.isEmpty();
208  }
209
210        public static boolean compareDeep(Base e1, Base e2, boolean allowNull) {
211                if (allowNull) {
212                        boolean noLeft = e1 == null || e1.isEmpty();
213                        boolean noRight = e2 == null || e2.isEmpty();
214                        if (noLeft && noRight) {
215                        return true;
216                        }
217                }
218                if (e1 == null || e2 == null)
219                        return false;
220                if (e2.isMetadataBased() && !e1.isMetadataBased()) // respect existing order for debugging consistency; outcome must be the same either way
221                        return e2.equalsDeep(e1);
222                else
223                return e1.equalsDeep(e2);
224        }
225        
226        public static boolean compareDeep(XhtmlNode div1, XhtmlNode div2, boolean allowNull) {
227                if (div1 == null && div2 == null && allowNull)
228                        return true;
229                if (div1 == null || div2 == null)
230                        return false;
231                return div1.equalsDeep(div2);
232  }
233
234
235        public static boolean compareValues(List<? extends PrimitiveType> e1, List<? extends PrimitiveType> e2, boolean allowNull) {
236                if (e1 == null && e2 == null && allowNull)
237                        return true;
238                if (e1 == null || e2 == null)
239                        return false;
240                if (e1.size() != e2.size())
241                        return false;
242                for (int i = 0; i < e1.size(); i++) {
243                        if (!compareValues(e1.get(i), e2.get(i), allowNull))
244                                return false;
245                }
246                return true;
247        }
248
249        public static boolean compareValues(PrimitiveType e1, PrimitiveType e2, boolean allowNull) {
250                boolean noLeft = e1 == null || e1.isEmpty();
251                boolean noRight = e2 == null || e2.isEmpty();
252      if (noLeft && noRight && allowNull) {
253                        return true;
254      }
255                if (noLeft != noRight)
256                        return false;
257                return e1.equalsShallow(e2);
258  }
259        
260        // -- converters for property setters
261        
262  public Type castToType(Base b) throws FHIRException {
263    if (b instanceof Type)
264      return (Type) b;
265    else if (b.isMetadataBased())
266      return ((org.hl7.fhir.dstu3.elementmodel.Element) b).asType();
267    else
268      throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Reference");
269  }
270  
271
272        public BooleanType castToBoolean(Base b) throws FHIRException {
273                if (b instanceof BooleanType)
274                        return (BooleanType) b;
275                else
276                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Boolean");
277        }
278        
279        public IntegerType castToInteger(Base b) throws FHIRException {
280                if (b instanceof IntegerType)
281                        return (IntegerType) b;
282                else
283                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Integer");
284        }
285        
286        public DecimalType castToDecimal(Base b) throws FHIRException {
287                if (b instanceof DecimalType)
288                        return (DecimalType) b;
289                else
290                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Decimal");
291        }
292        
293        public Base64BinaryType castToBase64Binary(Base b) throws FHIRException {
294                if (b instanceof Base64BinaryType)
295                        return (Base64BinaryType) b;
296                else
297                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Base64Binary");
298        }
299        
300        public InstantType castToInstant(Base b) throws FHIRException {
301                if (b instanceof InstantType)
302                        return (InstantType) b;
303                else
304                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Instant");
305        }
306        
307        public StringType castToString(Base b) throws FHIRException {
308                if (b instanceof StringType)
309                        return (StringType) b;
310                else if (b.hasPrimitiveValue())
311                        return new StringType(b.primitiveValue());
312                else
313                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a String");
314        }
315        
316        public UriType castToUri(Base b) throws FHIRException {
317                if (b instanceof UriType)
318                        return (UriType) b;
319                else if (b.hasPrimitiveValue())
320                        return new UriType(b.primitiveValue());
321                else
322                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Uri");
323        }
324        
325        public DateType castToDate(Base b) throws FHIRException {
326                if (b instanceof DateType)
327                        return (DateType) b;
328                else if (b.hasPrimitiveValue())
329                        return new DateType(b.primitiveValue());
330                else
331                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Date");
332        }
333        
334        public DateTimeType castToDateTime(Base b) throws FHIRException {
335                if (b instanceof DateTimeType)
336                        return (DateTimeType) b;
337                else if (b.fhirType().equals("dateTime"))
338                        return new DateTimeType(b.primitiveValue());
339                else
340                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a DateTime");
341        }
342        
343        public TimeType castToTime(Base b) throws FHIRException {
344                if (b instanceof TimeType)
345                        return (TimeType) b;
346                else
347                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Time");
348        }
349        
350        public CodeType castToCode(Base b) throws FHIRException {
351                if (b instanceof CodeType)
352                        return (CodeType) b;
353                else if (b.isPrimitive())
354                        return new CodeType(b.primitiveValue());
355                else
356                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Code");
357        }
358        
359        public OidType castToOid(Base b) throws FHIRException {
360                if (b instanceof OidType)
361                        return (OidType) b;
362                else
363                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Oid");
364        }
365        
366        public IdType castToId(Base b) throws FHIRException {
367                if (b instanceof IdType)
368                        return (IdType) b;
369                else
370                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Id");
371        }
372        
373        public UnsignedIntType castToUnsignedInt(Base b) throws FHIRException {
374                if (b instanceof UnsignedIntType)
375                        return (UnsignedIntType) b;
376                else
377                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a UnsignedInt");
378        }
379        
380        public PositiveIntType castToPositiveInt(Base b) throws FHIRException {
381                if (b instanceof PositiveIntType)
382                        return (PositiveIntType) b;
383                else
384                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a PositiveInt");
385        }
386        
387  public MarkdownType castToMarkdown(Base b) throws FHIRException {
388                if (b instanceof MarkdownType)
389                        return (MarkdownType) b;
390                else
391                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Markdown");
392        }
393                
394  public Annotation castToAnnotation(Base b) throws FHIRException {
395    if (b instanceof Annotation)
396      return (Annotation) b;
397    else
398      throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Annotation");
399  }
400  
401  public Dosage castToDosage(Base b) throws FHIRException {
402    if (b instanceof Dosage)
403      return (Dosage) b;
404    else      throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an DosageInstruction");
405  }
406  
407        
408        public Attachment castToAttachment(Base b) throws FHIRException {
409                if (b instanceof Attachment)
410                        return (Attachment) b;
411                else
412                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Attachment");
413        }
414        
415        public Identifier castToIdentifier(Base b) throws FHIRException {
416                if (b instanceof Identifier)
417                        return (Identifier) b;
418                else
419                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Identifier");
420        }
421        
422        public CodeableConcept castToCodeableConcept(Base b) throws FHIRException {
423                if (b instanceof CodeableConcept)
424                        return (CodeableConcept) b;
425                else if (b instanceof CodeType) {
426                  CodeableConcept cc = new CodeableConcept();
427                  cc.addCoding().setCode(((CodeType) b).asStringValue());
428                  return cc;
429                } else
430                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a CodeableConcept");
431        }
432        
433        public Coding castToCoding(Base b) throws FHIRException {
434                if (b instanceof Coding)
435                        return (Coding) b;
436                else
437                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Coding");
438        }
439        
440        public Quantity castToQuantity(Base b) throws FHIRException {
441                if (b instanceof Quantity)
442                        return (Quantity) b;
443                else
444                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Quantity");
445        }
446        
447        public Money castToMoney(Base b) throws FHIRException {
448                if (b instanceof Money)
449                        return (Money) b;
450                else
451                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Money");
452        }
453        
454        public Duration castToDuration(Base b) throws FHIRException {
455                if (b instanceof Duration)
456                        return (Duration) b;
457                else
458                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an Duration");
459        }
460        
461        public SimpleQuantity castToSimpleQuantity(Base b) throws FHIRException {
462                if (b instanceof SimpleQuantity)
463                        return (SimpleQuantity) b;
464                else if (b instanceof Quantity) {
465                  Quantity q = (Quantity) b;
466                  SimpleQuantity sq = new SimpleQuantity();
467      sq.setValueElement(q.getValueElement());
468      sq.setComparatorElement(q.getComparatorElement());
469      sq.setUnitElement(q.getUnitElement());
470      sq.setSystemElement(q.getSystemElement());
471      sq.setCodeElement(q.getCodeElement());
472      return sq;
473                } else
474                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to an SimpleQuantity");
475        }
476        
477        public Range castToRange(Base b) throws FHIRException {
478                if (b instanceof Range)
479                        return (Range) b;
480                else
481                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Range");
482        }
483        
484        public Period castToPeriod(Base b) throws FHIRException {
485                if (b instanceof Period)
486                        return (Period) b;
487                else
488                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Period");
489        }
490        
491        public Ratio castToRatio(Base b) throws FHIRException {
492                if (b instanceof Ratio)
493                        return (Ratio) b;
494                else
495                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Ratio");
496        }
497        
498        public SampledData castToSampledData(Base b) throws FHIRException {
499                if (b instanceof SampledData)
500                        return (SampledData) b;
501                else
502                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a SampledData");
503        }
504        
505        public Signature castToSignature(Base b) throws FHIRException {
506                if (b instanceof Signature)
507                        return (Signature) b;
508                else
509                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Signature");
510        }
511        
512        public HumanName castToHumanName(Base b) throws FHIRException {
513                if (b instanceof HumanName)
514                        return (HumanName) b;
515                else
516                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a HumanName");
517        }
518        
519        public Address castToAddress(Base b) throws FHIRException {
520                if (b instanceof Address)
521                        return (Address) b;
522                else
523                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Address");
524        }
525        
526        public ContactDetail castToContactDetail(Base b) throws FHIRException {
527                if (b instanceof ContactDetail)
528                        return (ContactDetail) b;
529                else
530                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a ContactDetail");
531        }
532
533        public Contributor castToContributor(Base b) throws FHIRException {
534                if (b instanceof Contributor)
535                        return (Contributor) b;
536                else
537                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Contributor");
538        }
539
540        public UsageContext castToUsageContext(Base b) throws FHIRException {
541                if (b instanceof UsageContext)
542                        return (UsageContext) b;
543                else
544                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a UsageContext");
545        }
546
547        public RelatedArtifact castToRelatedArtifact(Base b) throws FHIRException {
548                if (b instanceof RelatedArtifact)
549                        return (RelatedArtifact) b;
550                else
551                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a RelatedArtifact");
552        }
553
554        public ContactPoint castToContactPoint(Base b) throws FHIRException {
555                if (b instanceof ContactPoint)
556                        return (ContactPoint) b;
557                else
558                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a ContactPoint");
559        }
560        
561        public Timing castToTiming(Base b) throws FHIRException {
562                if (b instanceof Timing)
563                        return (Timing) b;
564                else
565                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Timing");
566        }
567        
568        public Reference castToReference(Base b) throws FHIRException {
569                if (b instanceof Reference)
570                        return (Reference) b;
571                else if (b.isPrimitive() && Utilities.isURL(b.primitiveValue()))
572      return new Reference().setReference(b.primitiveValue());
573    else if (b instanceof org.hl7.fhir.dstu3.elementmodel.Element && b.fhirType().equals("Reference")) {
574      org.hl7.fhir.dstu3.elementmodel.Element e = (org.hl7.fhir.dstu3.elementmodel.Element) b;
575      return new Reference().setReference(e.getChildValue("reference")).setDisplay(e.getChildValue("display"));
576    } else
577                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Reference");
578        }
579        
580        public Meta castToMeta(Base b) throws FHIRException {
581                if (b instanceof Meta)
582                        return (Meta) b;
583                else
584                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Meta");
585        }
586                
587        public Extension castToExtension(Base b) throws FHIRException {
588                if (b instanceof Extension)
589                        return (Extension) b;
590                else
591                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Extension");
592        }
593        
594        public Resource castToResource(Base b) throws FHIRException {
595                if (b instanceof Resource)
596                        return (Resource) b;
597                else
598                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Resource");
599        }
600        
601        public Narrative castToNarrative(Base b) throws FHIRException {
602                if (b instanceof Narrative)
603                        return (Narrative) b;
604                else
605                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a Narrative");
606        }
607        
608        
609        public ElementDefinition castToElementDefinition(Base b) throws FHIRException {
610                if (b instanceof ElementDefinition)
611                        return (ElementDefinition) b;
612                else
613                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a ElementDefinition");
614        }
615
616        public DataRequirement castToDataRequirement(Base b) throws FHIRException {
617                if (b instanceof DataRequirement)
618                        return (DataRequirement) b;
619                else
620                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a DataRequirement");
621        }
622
623        public ParameterDefinition castToParameterDefinition(Base b) throws FHIRException {
624                if (b instanceof ParameterDefinition)
625                        return (ParameterDefinition) b;
626                else
627                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a ParameterDefinition");
628        }
629
630        public TriggerDefinition castToTriggerDefinition(Base b) throws FHIRException {
631                if (b instanceof TriggerDefinition)
632                        return (TriggerDefinition) b;
633                else
634                        throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to a TriggerDefinition");
635        }
636
637  public XhtmlNode castToXhtml(Base b) throws FHIRException {
638    if (b instanceof Element) {
639      return ((Element) b).getXhtml();
640    } else if (b instanceof StringType) {
641      try {
642        return new XhtmlParser().parseFragment(((StringType) b).asStringValue());
643      } catch (IOException e) {
644        throw new FHIRException(e);
645      }
646    } else
647      throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to XHtml");
648  }
649  
650  public String castToXhtmlString(Base b) throws FHIRException {
651    if (b instanceof Element) {
652      return ((Element) b).getValue();
653    } else if (b instanceof StringType) {
654      return ((StringType) b).asStringValue();
655    } else
656      throw new FHIRException("Unable to convert a "+b.getClass().getName()+" to XHtml string");
657  }
658  
659        protected boolean isMetadataBased() {
660        return false;
661        }
662
663        public Base[] getProperty(int hash, String name, boolean checkValid) throws FHIRException {
664                if (checkValid)
665                        throw new FHIRException("Attempt to read invalid property '"+name+"' on type "+fhirType());
666        return null; 
667        }
668
669        public Base setProperty(int hash, String name, Base value) throws FHIRException {
670                throw new FHIRException("Attempt to write to invalid property '"+name+"' on type "+fhirType());
671        }
672
673        public Base makeProperty(int hash, String name) throws FHIRException {
674                throw new FHIRException("Attempt to make an invalid property '"+name+"' on type "+fhirType());
675        }
676
677        public String[] getTypesForProperty(int hash, String name) throws FHIRException {
678    throw new FHIRException("Attempt to get types for an invalid property '"+name+"' on type "+fhirType());
679        }
680        
681        public static boolean equals(String v1, String v2) {
682        if (v1 == null && v2 == null)
683                return true;
684        else if (v1 == null || v2 == null)
685        return false;
686        else
687                return v1.equals(v2);
688        }
689
690  public boolean isResource() {
691    return false;
692  }
693        
694
695  public abstract String getIdBase();
696  public abstract void setIdBase(String value);
697}