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