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