(myCurrentDefinitionPath.subList(0, myCurrentDefinitionPath.size() - 1));
Group parentStructure = (Group) navigateToStructure(parentDefinitionPath);
// Current position within parent
Position currentPosition = getCurrentPosition();
String nameAsItAppearsInParent = currentPosition.getStructureDefinition().getNameAsItAppearsInParent();
int index = Arrays.asList(parentStructure.getNames()).indexOf(nameAsItAppearsInParent) + 1;
String newSegmentName;
try {
newSegmentName = parentStructure.addNonstandardSegment(myDirection, index);
} catch (HL7Exception e) {
throw new Error("Unable to add nonstandard segment " + myDirection + ": ", e);
}
IStructureDefinition previousSibling = getCurrentPosition().getStructureDefinition();
IStructureDefinition parentStructureDefinition = parentDefinitionPath.get(parentDefinitionPath.size() - 1).getStructureDefinition();
NonStandardStructureDefinition nextDefinition = new NonStandardStructureDefinition(parentStructureDefinition, previousSibling, newSegmentName, index);
myCurrentDefinitionPath = parentDefinitionPath;
myCurrentDefinitionPath.add(new Position(nextDefinition, 0));
myNextIsSet = true;
}
/**
*
* Returns the next node in the message. Sometimes the next node is
* ambiguous. For example at the end of a repeating group, the next node may
* be the first segment in the next repetition of the group, or the next
* sibling, or an undeclared segment locally added to the group's end. Cases
* like this are disambiguated using getDirection(), which returns the name
* of the structure that we are "iterating towards". Usually we are
* "iterating towards" a segment of a certain name because we have a segment
* string that we would like to parse into that node. Here are the rules:
*
*
* - If at a group, next means first child.
* - If at a non-repeating segment, next means next "position"
* - If at a repeating segment: if segment name matches direction then
* next means next rep, otherwise next means next "position".
* - If at a segment within a group (not at the end of the group), next
* "position" means next sibling
* - If at the end of a group: If name of group or any of its "first
* decendents" matches direction, then next position means next rep of
* group. Otherwise if direction matches name of next sibling of the group,
* or any of its first descendents, next position means next sibling of the
* group. Otherwise, next means a new segment added to the group (with a
* name that matches "direction").
* - "First descendents" means first child, or first child of the first
* child, or first child of the first child of the first child, etc.
*
*/
public Structure next() {
if (!hasNext()) {
throw new NoSuchElementException("No more nodes in message");
}
Structure currentStructure = navigateToStructure(myCurrentDefinitionPath);
clearNext();
return currentStructure;
}
private Structure navigateToStructure(List theDefinitionPath) throws Error {
Structure currentStructure = null;
for (Position next : theDefinitionPath) {
if (currentStructure == null) {
currentStructure = myMessage;
} else {
try {
IStructureDefinition structureDefinition = next.getStructureDefinition();
Group currentStructureGroup = (Group) currentStructure;
String nextStructureName = structureDefinition.getNameAsItAppearsInParent();
currentStructure = currentStructureGroup.get(nextStructureName, next.getRepNumber());
} catch (HL7Exception e) {
throw new Error("Failed to retrieve structure: ", e);
}
}
}
return currentStructure;
}
/** Not supported */
public void remove() {
throw new UnsupportedOperationException("Can't remove a node from a message");
}
public String getDirection() {
return this.myDirection;
}
public void setDirection(String direction) {
clearNext();
this.myDirection = direction;
}
private void clearNext() {
myNextIsSet = false;
}
/**
* A structure position within a message.
*/
public static class Position {
private IStructureDefinition myStructureDefinition;
private int myRepNumber = -1;
public IStructureDefinition getStructureDefinition() {
return myStructureDefinition;
}
public void resetRepNumber() {
myRepNumber = -1;
}
public void setStructureDefinition(IStructureDefinition theStructureDefinition) {
myStructureDefinition = theStructureDefinition;
}
public int getRepNumber() {
return myRepNumber;
}
public Position(IStructureDefinition theStructureDefinition, int theRepNumber) {
myStructureDefinition = theStructureDefinition;
myRepNumber = theRepNumber;
}
public void incrementRep() {
myRepNumber++;
}
/** @see Object#equals */
public boolean equals(Object o) {
boolean equals = false;
if (o != null && o instanceof Position) {
Position p = (Position) o;
if (p.myStructureDefinition.equals(myStructureDefinition) && p.myRepNumber == myRepNumber)
equals = true;
}
return equals;
}
/** @see Object#hashCode */
public int hashCode() {
return myStructureDefinition.hashCode() + myRepNumber;
}
public String toString() {
StringBuffer ret = new StringBuffer();
if (myStructureDefinition.getParent() != null) {
ret.append(myStructureDefinition.getParent().getName());
} else {
ret.append("Root");
}
ret.append(":");
ret.append(myStructureDefinition.getName());
ret.append("(");
ret.append(myRepNumber);
ret.append(")");
return ret.toString();
}
}
/**
* Must be called after {@link #next()}
*
* @return
*/
public int getNextIndexWithinParent() {
return getCurrentPosition().getStructureDefinition().getPosition();
}
}