001package org.hl7.fhir.dstu2016may.metamodel;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import org.hl7.fhir.dstu2016may.model.Base;
007import org.hl7.fhir.exceptions.FHIRException;
008import org.hl7.fhir.utilities.Utilities;
009import org.hl7.fhir.utilities.xhtml.XhtmlNode;
010
011/**
012 * This class represents the reference model of FHIR
013 * 
014 * A resource is nothing but a set of elements, where every element has a 
015 * name, maybe a stated type, maybe an id, and either a value or child elements 
016 * (one or the other, or both (but not neither if it's null)
017 * 
018 * @author Grahame Grieve
019 *
020 */
021public class Element extends Base {
022
023        public enum SpecialElement {
024                CONTAINED, BUNDLE_ENTRY;
025        }
026
027        private List<String> comments;// not relevant for production, but useful in documentation
028        private String name;
029        private String type;
030        private String value;
031        private int index = -1;
032        private List<Element> children;
033        private Property property;
034        private int line;
035        private int col;
036        private SpecialElement special;
037        private XhtmlNode xhtml; // if this is populated, then value will also hold the string representation
038
039        public Element(String name) {
040                super();
041                this.name = name;
042        }
043
044        public Element(String name, Property property) {
045                super();
046                this.name = name;
047                this.property = property;
048        }
049
050        public Element(String name, Property property, String type, String value) {
051                super();
052                this.name = name;
053                this.property = property;
054                this.type = type;
055                this.value = value;
056        }
057
058        public void updateProperty(Property property, SpecialElement special) {
059                this.property = property;
060                this.special = special;
061        }
062
063        public SpecialElement getSpecial() {
064                return special;
065        }
066
067        public String getName() {
068                return name;
069        }
070
071        public String getType() {
072                if (type == null)
073                        return property.getType(name);
074                else
075                  return type;
076        }
077
078        public String getValue() {
079                return value;
080        }
081
082        public boolean hasChildren() {
083                return !(children == null || children.isEmpty());
084        }
085
086        public List<Element> getChildren() {
087                if (children == null)
088                        children = new ArrayList<Element>();
089                return children;
090        }
091
092        public boolean hasComments() {
093                return !(comments == null || comments.isEmpty());
094        }
095
096        public List<String> getComments() {
097                if (comments == null)
098                        comments = new ArrayList<String>();
099                return comments;
100        }
101
102        public Property getProperty() {
103                return property;
104        }
105
106        public void setValue(String value) {
107                this.value = value;
108        }
109
110        public void setType(String type) {
111                this.type = type;
112
113        }
114
115        public boolean hasValue() {
116                return value != null;
117        }
118
119        public List<Element> getChildrenByName(String name) {
120                List<Element> res = new ArrayList<Element>();
121                if (hasChildren()) {
122                        for (Element child : children)
123                                if (name.equals(child.getName()))
124                                        res.add(child);
125                }
126                return res;
127        }
128
129        public void numberChildren() {
130                if (children == null)
131                        return;
132                
133                String last = "";
134                int index = 0;
135                for (Element child : children) {
136                        if (child.getProperty().isList()) {
137                          if (last.equals(child.getName())) {
138                                index++;
139                          } else {
140                                last = child.getName();
141                                index = 0;
142                          }
143                        child.index = index;
144                        } else {
145                                child.index = -1;
146                        }
147                        child.numberChildren();
148                }       
149        }
150
151        public int getIndex() {
152                return index;
153        }
154
155        public boolean hasIndex() {
156                return index > -1;
157        }
158
159        public void setIndex(int index) {
160                this.index = index;
161        }
162
163        public String getChildValue(String name) {
164                if (children == null)
165                        return null;
166                for (Element child : children) {
167                        if (name.equals(child.getName()))
168                                return child.getValue();
169                }
170        return null;
171        }
172
173        public List<Element> getChildren(String name) {
174                List<Element> res = new ArrayList<Element>(); 
175                for (Element child : children) {
176                        if (name.equals(child.getName()))
177                                res.add(child);
178                }
179                return res;
180        }
181
182  public boolean hasType() {
183    if (type == null)
184      return property.hasType(name);
185    else
186      return true;
187  }
188
189  @Override
190  public String fhirType() {
191    return getType();
192  }
193
194  @Override
195        public Base[] getProperty(int hash, String name, boolean checkValid) throws FHIRException {
196        if (isPrimitive() && (hash == "value".hashCode()) && !Utilities.noString(value)) {
197                String tn = getType();
198                throw new Error("not done yet"); 
199        }
200                
201        List<Base> result = new ArrayList<Base>();
202        for (Element child : children) {
203                if (child.getName().equals(name))
204                        result.add(child);
205                if (child.getName().startsWith(name) && child.getProperty().isChoice() && child.getProperty().getName().equals(name+"[x]"))
206                        result.add(child);
207        }
208        if (result.isEmpty() && checkValid) {
209//              throw new FHIRException("not determined yet");
210        }
211        return result.toArray(new Base[result.size()]);
212        }
213
214        @Override
215        protected void listChildren(
216            List<org.hl7.fhir.dstu2016may.model.Property> result) {
217        // TODO Auto-generated method stub
218    
219  }
220
221        @Override
222        public boolean isPrimitive() {
223                return type != null ? ParserBase.isPrimitive(type) : property.isPrimitive(name);
224        }
225        
226        @Override
227        public boolean hasPrimitiveValue() {
228                return property.isPrimitive(name) || property.IsLogicalAndHasPrimitiveValue(name);
229        }
230        
231
232        @Override
233        public String primitiveValue() {
234                if (isPrimitive())
235                  return value;
236                else {
237                        if (hasPrimitiveValue()) {
238                                for (Element c : children) {
239                                        if (c.getName().equals("value"))
240                                                return c.primitiveValue();
241                                }
242                        }
243                        return null;
244                }
245        }
246
247        // for the validator
248  public int line() {
249    return line;
250        }
251
252  public int col() {
253    return col;
254  }
255
256        public Element markLocation(int line, int col) {
257                this.line = line;
258                this.col = col; 
259                return this;
260  }
261
262        public Element getNamedChild(String name) {
263          if (children == null)
264                return null;
265          Element result = null;
266          for (Element child : children) {
267                if (child.getName().equals(name)) {
268                        if (result == null)
269                                result = child;
270                        else 
271                                throw new Error("Attempt to read a single element when there is more than one present ("+name+")");
272                }
273          }
274          return result;
275  }
276
277  public void getNamedChildren(String name, List<Element> list) {
278        if (children != null)
279          for (Element child : children) 
280                if (child.getName().equals(name))
281                        list.add(child);
282  }
283    
284  public String getNamedChildValue(String name) {
285        Element child = getNamedChild(name);
286    return child == null ? null : child.value;
287  }
288
289  public void getNamedChildrenWithWildcard(String string, List<Element> values) {
290                throw new Error("not done yet");  
291  }
292
293  
294        public XhtmlNode getXhtml() {
295                return xhtml;
296        }
297
298        public Element setXhtml(XhtmlNode xhtml) {
299                this.xhtml = xhtml;
300                return this;
301        }
302
303
304}