001/**
002The contents of this file are subject to the Mozilla Public License Version 1.1 
003(the "License"); you may not use this file except in compliance with the License. 
004You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
005Software distributed under the License is distributed on an "AS IS" basis, 
006WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 
007specific language governing rights and limitations under the License. 
008
009The Original Code is "StructureDefinition.java".  Description: 
010"A definition element" 
011
012The Initial Developer of the Original Code is University Health Network. Copyright (C) 
0132001.  All Rights Reserved. 
014
015Contributor(s): ______________________________________. 
016
017Alternatively, the contents of this file may be used under the terms of the 
018GNU General Public License (the  �GPL�), in which case the provisions of the GPL are 
019applicable instead of those above.  If you wish to allow use of your version of this 
020file only under the terms of the GPL and not to allow others to use your version 
021of this file under the MPL, indicate your decision by deleting  the provisions above 
022and replace  them with the notice and other provisions required by the GPL License.  
023If you do not delete the provisions above, a recipient may use your version of 
024this file under either the MPL or the GPL. 
025
026 */
027package ca.uhn.hl7v2.parser;
028
029import java.util.ArrayList;
030import java.util.HashSet;
031import java.util.Set;
032
033/**
034 * Defines
035 * 
036 * @author James
037 * 
038 */
039public class StructureDefinition implements IStructureDefinition {
040
041    private HashSet<String> myAllChildrenNames;
042    private HashSet<String> myAllFirstLeafNames;
043    private final ArrayList<StructureDefinition> myChildren = new ArrayList<>();
044    private IStructureDefinition myFirstSibling;
045    private boolean myFirstSiblingIsSet;
046    private Boolean myIsFinalChildOfParent;
047    private boolean myIsRepeating;
048    private boolean myIsRequired;
049    private boolean myIsSegment;
050    private String myName;
051    private String myNameAsItAppearsInParent;
052    private volatile Set<String> myNamesOfAllPossibleFollowingLeaves;
053    private IStructureDefinition myNextLeaf;
054    private IStructureDefinition myNextSibling;
055    private IStructureDefinition myParent;
056    private int myPosition;
057        private boolean myChoiceElement;
058
059
060    /**
061     * Constructor
062     */
063    public StructureDefinition() {
064    }
065
066
067    /**
068     * Setter
069     */
070    void addChild(StructureDefinition theChild) {
071        myChildren.add(theChild);
072    }
073
074
075    /**
076     * {@inheritDoc }
077     */
078    @Override
079    public boolean equals(Object theObj) {
080        if (!(theObj instanceof StructureDefinition)) {
081            return false;
082        }
083        StructureDefinition o = (StructureDefinition) theObj;
084        return o.myName.equals(myName) && o.myPosition == myPosition;
085    }
086
087
088    /**
089     * {@inheritDoc }
090     */
091    @Override
092    public HashSet<String> getAllChildNames() {
093        if (myAllChildrenNames == null) {
094            myAllChildrenNames = new HashSet<>();
095            for (IStructureDefinition next : myChildren) {
096                myAllChildrenNames.add(next.getName());
097                myAllChildrenNames.addAll(next.getAllChildNames());
098            }
099        }
100
101        return myAllChildrenNames;
102    }
103
104
105    /**
106     * {@inheritDoc }
107     */
108    @Override
109    public HashSet<String> getAllPossibleFirstChildren() {
110        if (myAllFirstLeafNames == null) {
111            myAllFirstLeafNames = new HashSet<>();
112            
113            boolean hasChoice = false;
114            for (IStructureDefinition next : myChildren) {
115                myAllFirstLeafNames.addAll(next.getAllPossibleFirstChildren());
116                
117                if (next.isChoiceElement()) {
118                        hasChoice = true;
119                        continue;
120                } else if (hasChoice) {
121                        break;
122                }
123                
124                if (next.isRequired()) {
125                    break;
126                }
127            }
128
129            myAllFirstLeafNames.add(getName());
130        }
131
132        return myAllFirstLeafNames;
133    }
134
135
136    /**
137     * {@inheritDoc }
138     */
139    @Override
140    public ArrayList<StructureDefinition> getChildren() {
141        return myChildren;
142    }
143
144
145    /**
146     * {@inheritDoc }
147     */
148    @Override
149    public IStructureDefinition getFirstChild() {
150        return myChildren.get(0);
151    }
152
153
154    /**
155     * {@inheritDoc }
156     */
157    @Override
158    public IStructureDefinition getFirstSibling() {
159        if (!myFirstSiblingIsSet) {
160            if (myParent == null) {
161                myFirstSibling = null;
162            } else if (myParent.getChildren().get(0) == this) {
163                myFirstSibling = null;
164            } else {
165                myFirstSibling = myParent.getChildren().get(0);
166            }
167            myFirstSiblingIsSet = true;
168        }
169
170        return myFirstSibling;
171    }
172
173
174    /**
175     * {@inheritDoc }
176     */
177    public String getName() {
178        return myName;
179    }
180
181
182    /**
183     * {@inheritDoc}
184     */
185    @Override
186    public String getNameAsItAppearsInParent() {
187        return myNameAsItAppearsInParent;
188    }
189
190
191    /**
192     * {@inheritDoc }
193     */
194    @Override
195    public Set<String> getNamesOfAllPossibleFollowingLeaves() {
196        if (myNamesOfAllPossibleFollowingLeaves != null) {
197            return myNamesOfAllPossibleFollowingLeaves;
198        }
199
200        HashSet<String> retVal = new HashSet<>();
201
202        IStructureDefinition nextLeaf = getNextLeaf();
203        if (nextLeaf != null) {
204            retVal.add(nextLeaf.getName());
205            Set<String> namesOfAllPossibleFollowingLeaves = nextLeaf.getNamesOfAllPossibleFollowingLeaves();
206            retVal.addAll(namesOfAllPossibleFollowingLeaves);
207        }
208
209        IStructureDefinition parent = myParent;
210        while (parent != null) {
211            if (parent.isRepeating()) {
212                retVal.addAll(parent.getAllPossibleFirstChildren());
213            }
214            parent = parent.getParent();
215        }
216
217        myNamesOfAllPossibleFollowingLeaves = retVal;
218        return retVal;
219    }
220
221
222    /**
223     * {@inheritDoc }
224     */
225    @Override
226    public IStructureDefinition getNextLeaf() {
227        return myNextLeaf;
228    }
229
230
231    /**
232     * {@inheritDoc }
233     */
234    @Override
235    public IStructureDefinition getNextSibling() {
236        if (myNextSibling != null) {
237            return myNextSibling;
238        }
239
240        if (isFinalChildOfParent()) {
241            throw new IllegalStateException("Final child");
242        }
243
244        myNextSibling = myParent.getChildren().get(myPosition + 1);
245        return myNextSibling;
246    }
247
248
249    /**
250     * {@inheritDoc }
251     */
252    @Override
253    public IStructureDefinition getParent() {
254        return myParent;
255    }
256
257
258    /**
259     * {@inheritDoc }
260     */
261    @Override
262    public int getPosition() {
263        return myPosition;
264    }
265
266
267    /**
268     * {@inheritDoc }
269     */
270    @Override
271    public boolean hasChildren() {
272        return !myChildren.isEmpty();
273    }
274
275
276    /**
277     * {@inheritDoc }
278     */
279    @Override
280    public int hashCode() {
281        return 17 * myName.hashCode() * myPosition;
282    }
283
284
285    /**
286     * {@inheritDoc }
287     */
288    @Override
289    public boolean isFinalChildOfParent() {
290        if (myIsFinalChildOfParent != null) {
291            return myIsFinalChildOfParent;
292        }
293        myIsFinalChildOfParent = myParent == null || (myPosition == (myParent.getChildren().size() - 1));
294        return myIsFinalChildOfParent;
295    }
296
297
298    /**
299     * {@inheritDoc }
300     */
301    @Override
302    public boolean isRepeating() {
303        return myIsRepeating;
304    }
305
306
307    /**
308     * {@inheritDoc }
309     */
310    @Override
311    public boolean isRequired() {
312        return myIsRequired;
313    }
314
315
316    /**
317     * {@inheritDoc }
318     */
319    @Override
320    public boolean isSegment() {
321        return myIsSegment;
322    }
323
324
325    /**
326     * Setter
327     */
328    void setName(String theName) {
329        myName = theName;
330    }
331
332
333    /**
334     * Setter
335     */
336    void setNameAsItAppearsInParent(String theName) {
337        myNameAsItAppearsInParent = theName;
338    }
339
340
341    /**
342     * Setter
343     */
344    void setNextLeaf(IStructureDefinition theNextLeaf) {
345        myNextLeaf = theNextLeaf;
346    }
347
348
349    /**
350     * Setter
351     */
352    void setParent(IStructureDefinition theParent) {
353        myParent = theParent;
354    }
355
356
357    /**
358     * Setter
359     */
360    void setPosition(int thePosition) {
361        myPosition = thePosition;
362    }
363
364
365    /**
366     * Setter
367     */
368    void setRepeating(boolean theIsRepeating) {
369        myIsRepeating = theIsRepeating;
370    }
371
372
373    /**
374     * Setter
375     */
376    void setRequired(boolean theIsRequired) {
377        myIsRequired = theIsRequired;
378    }
379
380
381    /**
382     * Setter
383     */
384    void setSegment(boolean theIsSegment) {
385        myIsSegment = theIsSegment;
386    }
387
388
389    /**
390     * {@inheritDoc }
391     */
392    @Override
393    public String toString() {
394        return "StructureDefinition[" + getName() + "]";
395    }
396
397
398        /**
399     * @param theChoiceElement true if the definition of this structure is a choice
400         * @see ca.uhn.hl7v2.model.Group#isChoiceElement(String)
401     */
402        public void setChoiceElement(boolean theChoiceElement) {
403                myChoiceElement = theChoiceElement;
404        }
405
406
407        /**
408         * @see ca.uhn.hl7v2.model.Group#isChoiceElement(String)
409         */
410        @Override
411    public boolean isChoiceElement() {
412                return myChoiceElement;
413        }
414
415}