import java.util.*;
import java.util.regex.Pattern;
import org.dom4j.*;
import org.dom4j.io.SAXReader;

SAXReader reader = new SAXReader(false);
reader.setIncludeInternalDTDDeclarations(false);
reader.setIncludeExternalDTDDeclarations(false);

Document document = reader.read(new StringReader(xml_text));
List nodelist = document.selectNodes(xpath);

ArrayList outputXmlList = new ArrayList();
ArrayList outputXmlList_false = new ArrayList();
int i = 1;
Map collections = new LinkedHashMap();
Map collectionsEnd = new HashMap();
Map collections_false = new LinkedHashMap();
Map collectionsEnd_false = new HashMap();
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE | Pattern.DOTALL | (Boolean.parseBoolean(case_sensitive) ? 0 : Pattern.CASE_INSENSITIVE));
for (Iterator iter = nodelist.iterator(); iter.hasNext();) {
        Node node = (Node) iter.next();
        boolean match = false;
        switch(node.getNodeType()){
                case Node.ELEMENT_NODE:
                        if(pattern.matcher(node.getText()).find()){
                                match = true;
                        }
                        break;
                case Node.ATTRIBUTE_NODE:
                        if(pattern.matcher(node.getValue()).find()){
                                match = true;
                        }
                        break;
                default: break;
        }

	Map cs = null;
	Map csEnd = null;
        if(match){
		cs = collections;
		csEnd = collectionsEnd;
	}
	else{
		cs = collections_false;
		csEnd = collectionsEnd_false;
        }
        //go up the tree until we hit a mobyData...this is the unit we can forward
        StringBuilder collection = null;
        StringBuilder collectionEnd = null;
        while(node != null && (node.getName() == null || !node.getName().equals("mobyData"))){
                if(node.getParent() != null &&
                   node.getParent().getName().equals("Collection")){
                        collection = new StringBuilder();  //start tracking parents
                        collectionEnd = new StringBuilder();
                        if(!cs.containsKey(collection)){
                                cs.put(collection, new Vector());
                                csEnd.put(collection, collectionEnd);
                        }
                        ((Vector)cs.get(collection)).add(node.asXML());
                }
                node = node.getParent();
                if(node != null && collection != null){
                        StringBuilder nodeAttrs = new StringBuilder();
                        for(Object a: ((Element) node).attributeIterator()){
                                Attribute attr = (Attribute) a;
                                nodeAttrs.append(" " + attr.getQualifiedName() + "='" +
                                                 attr.getValue().replaceAll("'","&apos;") + "'");
                        }
                        collection.insert(0, "<"+((Element) node).getQualifiedName() + nodeAttrs.toString() + ">");
                        collectionEnd.append("</"+((Element) node).getQualifiedName()+">");
                }
        }
        if(node == null){ // wasn't part of a mobyData block
                continue;
        }
        // At mobyData level if we got here, add if job not already present
        if(collection == null){
		String jobData = "<moby:MOBY xmlns:moby='http://www.biomoby.org/moby' xmlns='http://www.biomoby.org/moby'>"+
                		 "<moby:mobyContent>"+node.asXML()+"</moby:mobyContent></moby:MOBY>";
                List list = (match ? outputXmlList : outputXmlList_false);
		if(!list.contains(jobData)){
			list.add(jobData);
		}
        }
}

//collapse stringbuilders with same text contents into one
Map uniqueCollections = new LinkedHashMap();
Map uniqueCollectionsEnd = new LinkedHashMap();
for(Map.Entry collection: collections.entrySet()){
        String keyString = collection.getKey().toString();
        if(!uniqueCollections.containsKey(keyString)){
                uniqueCollections.put(keyString, new Vector());
                uniqueCollectionsEnd.put(keyString, collectionsEnd.get(collection.getKey()));
        }
        ((List) uniqueCollections.get(keyString)).addAll((List) collection.getValue());
}
Map uniqueCollections_false = new LinkedHashMap();
Map uniqueCollectionsEnd_false = new LinkedHashMap();
for(Map.Entry collection: collections_false.entrySet()){
        String keyString = collection.getKey().toString();
        if(!uniqueCollections_false.containsKey(keyString)){
                uniqueCollections_false.put(keyString, new Vector());
                uniqueCollectionsEnd_false.put(keyString, collectionsEnd_false.get(collection.getKey()));
        }
        ((List) uniqueCollections_false.get(keyString)).addAll((List) collection.getValue());
}

//Now concat the collection members that pass the filter
for(Map.Entry collection: uniqueCollections.entrySet()){
        StringBuilder block = new StringBuilder();
        block.append("<moby:MOBY xmlns:moby='http://www.biomoby.org/moby' xmlns='http://www.biomoby.org/moby'>\n");
        block.append("<moby:mobyContent>\n");
        block.append(collection.getKey().toString());
        for(String val: (List) collection.getValue()){
                block.append(val);
        }
        block.append(uniqueCollectionsEnd.get(collection.getKey().toString()));  // closing tags
        block.append("</moby:mobyContent>\n");
        block.append("</moby:MOBY>\n");

        outputXmlList.add(block.toString());
}
for(Map.Entry collection: uniqueCollections_false.entrySet()){
        StringBuilder block = new StringBuilder();
        block.append("<moby:MOBY xmlns:moby='http://www.biomoby.org/moby' xmlns='http://www.biomoby.org/moby'>\n");
        block.append("<moby:mobyContent>\n");
        block.append(collection.getKey().toString());
        for(String val: (List) collection.getValue()){
                block.append(val);
        }
        block.append(uniqueCollectionsEnd_false.get(collection.getKey().toString()));  // closing tags
        block.append("</moby:mobyContent>\n");
        block.append("</moby:MOBY>\n");

        outputXmlList_false.add(block.toString());
}

List TRUE_nodelistAsXML=outputXmlList;
List FALSE_nodelistAsXML=outputXmlList_false;

