1   package org.daisy.pipeline.nlp.calabash.impl;
2   
3   import java.util.ArrayList;
4   import java.util.HashSet;
5   import java.util.List;
6   import java.util.Set;
7   
8   import net.sf.saxon.om.NodeInfo;
9   import net.sf.saxon.s9api.QName;
10  import net.sf.saxon.s9api.XdmNode;
11  
12  /**
13   * This class keeps track of the duplicated nodes. Rather than maintaining a set
14   * of all the nodes created, it keeps under watch only those that might not have
15   * been closed yet in the original document. The nodes' depth levels are used
16   * for detecting when they are closed.
17   */
18  public class DuplicationManager {
19  
20  	private List<NodeInfo> mDuplicatedNodes;
21  	private ArrayList<Set<NodeInfo>> mUnderWatch;
22  
23  	private boolean mForbidAnyDup;
24  	private final static QName IDattr = new QName("id");
25  
26  	public DuplicationManager(boolean forbidAnyDup) {
27  		mForbidAnyDup = forbidAnyDup;
28  	}
29  
30  	public void onNewDocument() {
31  		mDuplicatedNodes = new ArrayList<NodeInfo>();
32  		mUnderWatch = new ArrayList<Set<NodeInfo>>();
33  	}
34  
35  	public void onNewSection() {
36  	}
37  
38  	public void onNewNode(XdmNode node, int level) {
39  		if (!mForbidAnyDup && node.getAttributeValue(IDattr) == null)
40  			return;
41  
42  		NodeInfo info = node.getUnderlyingNode();
43  		for (Set<NodeInfo> watched : mUnderWatch)
44  			if (watched.contains(info)) {
45  				mDuplicatedNodes.add(info);
46  				break;
47  			}
48  
49  		if (mUnderWatch.size() > level)
50  			mUnderWatch.subList(level + 1, mUnderWatch.size()).clear();
51  		else
52  			while (mUnderWatch.size() <= level)
53  				mUnderWatch.add(new HashSet<NodeInfo>());
54  		mUnderWatch.get(level).add(info);
55  	}
56  
57  	//the result may contain multiple occurrences of the same node
58  	public List<NodeInfo> getDuplicatedNodes() {
59  		return mDuplicatedNodes;
60  	}
61  }