/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.xml.xsd.typeprovider.xmlsorter;
import gw.internal.xml.xsd.typeprovider.XmlSchemaIndex;
import gw.internal.xml.xsd.typeprovider.schema.XmlSchemaObject;
import gw.internal.xml.xsd.typeprovider.schema.XmlSchemaParticle;
import gw.internal.xml.xsd.typeprovider.schema.XmlSchemaSequence;
import gw.xml.XmlElement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Sort handler that represents an xsd:sequence.
*/
public class XmlSchemaSequenceXmlSortHandler extends XmlSortHandler {
private final XmlSortHandler[] _children;
public XmlSchemaSequenceXmlSortHandler( XmlSchemaSequence sequence ) {
this( sequence, convertChildrenToHandlers( sequence ) );
}
public XmlSchemaSequenceXmlSortHandler( XmlSchemaObject schemaObject, XmlSortHandler... children ) {
super( schemaObject );
_children = children;
}
private static XmlSortHandler[] convertChildrenToHandlers( XmlSchemaSequence sequence ) {
List<XmlSchemaParticle> items = sequence.getItems();
Iterator<XmlSchemaParticle> iter = items.iterator();
XmlSortHandler[] children = new XmlSortHandler[ items.size() ];
int idx = 0;
while ( iter.hasNext() ) {
children[ idx++ ] = XmlSorter.createHandler( iter.next() );
}
return children;
}
@Override
public List<XmlElement> sortDirect( LinkedList<XmlElement> remainingChildren, boolean preferredOnly, List<XmlSchemaIndex> requiredSchemas, Set<XmlElement> mustMatch ) {
Map<XmlElement, Set<Integer>> matches = new HashMap<XmlElement, Set<Integer>>();
for ( int i = 0; i < _children.length; i++ ) {
Set<XmlElement> matchResults = new HashSet<XmlElement>( mustMatch );
Set<XmlElement> matchResults2 = new HashSet<XmlElement>( mustMatch );
_children[i].match( matchResults, requiredSchemas );
// this is NOT equivalent to removeAll() when multiples of the same child exist in the content list
for ( XmlElement match : matchResults ) {
matchResults2.remove( match );
}
// each item in matchResults2 was matched by this child
for ( XmlElement match : matchResults2 ) {
addMatch( matches, i, match );
}
}
List<XmlElement> sortedChildren = new ArrayList<XmlElement>();
LinkedList<XmlElement> localRemainingChildren = new LinkedList<XmlElement>( remainingChildren );
for ( int i = 0; i < _children.length; i++ ) {
Set<XmlElement> localMustMatch = new HashSet<XmlElement>();
for ( XmlElement remainingChild : localRemainingChildren ) {
Set<Integer> indexes = matches.get( remainingChild );
if ( indexes != null && indexes.size() == 1 && indexes.iterator().next() == i ) {
// we must match this child
localMustMatch.add( remainingChild );
}
}
List<XmlElement> localSortedChildren = _children[i].sort( localRemainingChildren, preferredOnly, requiredSchemas, localMustMatch );
sortedChildren.addAll( localSortedChildren );
// this is NOT equivalent to removeAll() when multiples of the same child exist in the content list
for ( XmlElement localSortedChild : localSortedChildren ) {
localRemainingChildren.remove( localSortedChild );
}
}
return sortedChildren;
}
private void addMatch( Map<XmlElement, Set<Integer>> matches, int i, XmlElement match ) {
Set<Integer> set = matches.get( match );
if ( set == null ) {
set = new HashSet<Integer>();
matches.put( match, set );
}
set.add( i );
}
@Override
protected boolean selectNextChoiceDirect() {
return selectNextChoice( _children.length - 1 );
}
@Override
public void _reset() {
for ( XmlSortHandler child : _children ) {
child.reset();
}
}
@Override
protected void checkMissingRequiredElements( LinkedList<XmlElement> remainingChildren, List<XmlSchemaIndex> requiredSchemas ) {
for ( XmlSortHandler child : _children ) {
child.checkMissingRequiredElements( remainingChildren, requiredSchemas );
}
}
@Override
public void match( Set<XmlElement> children, List<XmlSchemaIndex> requiredSchemas ) {
for ( XmlSortHandler child : _children ) {
child.match( children, requiredSchemas );
}
}
private boolean selectNextChoice( int idx ) {
if ( idx >= 0 ) {
final XmlSortHandler child = _children[ idx ];
if ( child.selectNextChoice() ) {
return true;
}
else {
// try next child
if ( selectNextChoice( idx - 1 ) ) {
child.reset();
return true;
}
}
}
return false;
}
}