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