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 "GroupPointer.java".  Description: 
010"A GroupPointer is used when parsing traditionally encoded HL7 messages" 
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*/
027
028package ca.uhn.hl7v2.parser;
029
030import ca.uhn.hl7v2.HL7Exception;
031import ca.uhn.hl7v2.model.Group;
032
033/**
034 * A GroupPointer is used when parsing traditionally encoded HL7 messages. 
035 * It acts as a placeholder for a unique group "slot" in a message structure. 
036 * There is one GroupPointer per unique Group path (even if the group 
037 * repeats, and regardless of whether any instances exist).  
038 *
039 * @deprecated MessageIterator is now used 
040 * @author Bryan Tripp (bryan_tripp@sourceforge.net)
041 */
042public class GroupPointer extends Pointer {
043
044    private PipeParser parser;
045    private Group parent;
046    private String name;
047    private boolean repeating;
048    private EncodingCharacters encodingChars;
049    private Pointer[] children;
050    private Group currentGroup = null;
051    private int childAtWhichToStart;
052
053    /** 
054     * Creates new GroupPointer 
055     */
056    public GroupPointer(PipeParser parser, Group parent, int position, EncodingCharacters encodingChars)
057        throws HL7Exception {
058        this.parser = parser;
059        this.parent = parent;
060        this.name = parent.getNames()[position];
061        this.repeating = parent.isRepeating(this.name);
062        this.encodingChars = encodingChars;
063        //this.createNewInstance();  
064    }
065
066    /**
067     * Parses the given String, which must contain a single traditionally encoded 
068     * message segment, into the current repetition of the message Group  
069     * underlying this Pointer by forwarding it to each of it's children until 
070     * one of them succeeds.    
071     */
072    public int setSegment(String segment, boolean orderedCorrectly) throws HL7Exception {
073        if (this.currentGroup == null)
074            createNewInstance(); //make first instance of the group
075        int status = tryToFillChildren(segment, orderedCorrectly);
076        if ((status == Pointer.FILL_FAILED_FULL || status == Pointer.FILL_FAILED_OUT_OF_ORDER)
077            && this.repeating
078            && orderedCorrectly) {
079            createNewInstance();
080            status = tryToFillChildren(segment, orderedCorrectly);
081        }
082        return status;
083    }
084
085    private int tryToFillChildren(String segment, boolean orderedCorrectlyInParent) throws HL7Exception {
086        int status = Pointer.FILL_FAILED_WRONG_SEGMENT;
087        int c = 0;
088        boolean fullOneExists = false;
089        boolean rightSegmentWrongOrder = false;
090
091        //loop through children ... 
092        //note: can't just stop if FILL_FAILED_FULL b/c have to check all nesting levels 
093        while (status != Pointer.FILL_OK && c < this.children.length) {
094            boolean orderedCorrectly = orderedCorrectlyInParent;
095            if (c < childAtWhichToStart)
096                orderedCorrectly = false;
097
098            status = children[c++].setSegment(segment, orderedCorrectly);
099            if (status == Pointer.FILL_FAILED_FULL)
100                fullOneExists = true;
101            if (status == Pointer.FILL_FAILED_OUT_OF_ORDER)
102                rightSegmentWrongOrder = true;
103        }
104
105        //note: but if there was a FILL_FAILED_FULL at any point, can't return FILL_FAILED_WRONG_SEGMENT
106        if (fullOneExists && status == Pointer.FILL_FAILED_WRONG_SEGMENT)
107            status = Pointer.FILL_FAILED_FULL;
108        if (rightSegmentWrongOrder && status == Pointer.FILL_FAILED_WRONG_SEGMENT)
109            status = Pointer.FILL_FAILED_OUT_OF_ORDER;
110
111        //if filled, update start location so that subsequent segments can't be 
112        //parsed into locations prior to this one 
113        if (status == Pointer.FILL_OK)
114            childAtWhichToStart = c - 1;
115
116        return status;
117    }
118
119    /** 
120     * Creates a new, empty repetition of the underlying Group and sets up 
121     * Pointers to it's components.  
122     * @thows HL7Exception if there is already 1 rep and group is non-repeating
123     */
124    private void createNewInstance() throws HL7Exception {
125        //find next rep # ... 
126        int nextRepNum = parent.getAll(this.name).length;
127
128        this.currentGroup = (Group) parent.get(this.name, nextRepNum);
129        this.childAtWhichToStart = 0;
130
131        //set up pointers for children ... 
132        String[] childNames = currentGroup.getNames();
133        this.children = new Pointer[childNames.length];
134        for (int i = 0; i < childNames.length; i++) {
135            Pointer p;
136            //make new SegmentPointer or GroupPointer depending on whether child is a Group ... 
137            Class<?> childClass = currentGroup.getClass(childNames[i]);
138            if (Group.class.isAssignableFrom(childClass)) {
139                p = new GroupPointer(this.parser, currentGroup, i, this.encodingChars);
140            }
141            else {
142                p = new SegmentPointer(this.parser, currentGroup, i, encodingChars);
143            }
144
145            this.children[i] = p;
146        }
147
148    }
149
150}