1   package org.daisy.pipeline.nlp.calabash.impl;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   import java.util.Locale;
6   import java.util.Set;
7   
8   import net.sf.saxon.om.NodeInfo;
9   import net.sf.saxon.s9api.Axis;
10  import net.sf.saxon.s9api.XdmNode;
11  import net.sf.saxon.s9api.XdmNodeKind;
12  import net.sf.saxon.s9api.XdmSequenceIterator;
13  
14  import org.daisy.pipeline.nlp.LanguageUtils;
15  import org.daisy.pipeline.nlp.calabash.impl.InlineSectionProcessor.Leaf;
16  import org.daisy.pipeline.nlp.lexing.LexService.LexerInitException;
17  
18  /**
19   * The InlineSectionFinder notifies an InlineSectionProcessor that a new inline
20   * section has been found, whenever:
21   * 
22   * - A non-inline element is found, in document order ;
23   * 
24   * - The language changes ;
25   * 
26   * - An element with an ID attribute is found and if its children would belong
27   * to different inline sections. It prevents the algorithm from splitting up
28   * such elements.
29   */
30  public class InlineSectionFinder {
31  	private FormatSpecifications mSpecs;
32  	private InlineSectionProcessor mProc;
33  	private List<Leaf> mCurrentSection;
34  	private List<String> mCurrentText;
35  	private int mCurrentSectionSize;
36  	private Locale mCurrentLang;
37  	private Set<NodeInfo> mUnsplittable;
38  
39  	public void find(XdmNode root, int rootLevel, FormatSpecifications specs,
40  	        InlineSectionProcessor processor, Set<NodeInfo> unsplittable)
41  	        throws LexerInitException {
42  
43  		mCurrentSection = new ArrayList<Leaf>();
44  		mCurrentText = new ArrayList<String>();
45  		mCurrentSectionSize = 0;
46  		mSpecs = specs;
47  		mProc = processor;
48  		mCurrentLang = null;
49  		mUnsplittable = unsplittable;
50  
51  		findRec(root, rootLevel, null);
52  		mProc = null;
53  		mSpecs = null;
54  		mCurrentSection = null;
55  		mUnsplittable = null;
56  	}
57  
58  	private void addToSection(XdmNode node, int level, String text) {
59  		if (mCurrentSectionSize == mCurrentSection.size()) {
60  			mCurrentSection.add(new Leaf());
61  			mCurrentText.add(null);
62  		}
63  
64  		Leaf l = mCurrentSection.get(mCurrentSectionSize);
65  		l.formatting = node;
66  		l.level = level;
67  
68  		mCurrentText.set(mCurrentSectionSize++, text);
69  	}
70  
71  	private void notifyNewSection() throws LexerInitException {
72  		if (mCurrentSectionSize > 0) {
73  			int k = 0;
74  			for (k = 0; k < mCurrentSectionSize
75  			        && (mCurrentText.get(k) == null || mCurrentSection.get(k).formatting == null); ++k);
76  			if (k == mCurrentSectionSize) {
77  				mProc.onEmptySectionFound(mCurrentSection.subList(0, mCurrentSectionSize));
78  			} else {
79  				mProc.onInlineSectionFound(mCurrentSection.subList(0, mCurrentSectionSize),
80  				        mCurrentText.subList(0, mCurrentSectionSize), mCurrentLang);
81  			}
82  			mCurrentSectionSize = 0;
83  		}
84  	}
85  
86  	private void findRec(XdmNode node, int level, Locale lang) throws LexerInitException {
87  		if (node.getNodeKind() == XdmNodeKind.TEXT) {
88  			addToSection(node.getParent(), level - 1, node.getStringValue());
89  		} else {
90  
91  			String langstr = node.getAttributeValue(mSpecs.langAttr);
92  			if (langstr != null) {
93  				Locale x = LanguageUtils.stringToLanguage(langstr);
94  				if (x != null) {
95  					lang = x;
96  				}
97  			}
98  
99  			if (lang != mCurrentLang) {
100 				notifyNewSection();
101 				mCurrentLang = lang;
102 			}
103 
104 			XdmSequenceIterator iter = node.axisIterator(Axis.CHILD);
105 			if (node.getNodeName() != null
106 			        && mSpecs.inlineElements.test(node)
107 			        && (!mUnsplittable.contains(node.getUnderlyingNode()))) {
108 
109 				//*** inline element ***
110 				if (mSpecs.ensureSentenceBefore.test(node)) {
111 					addToSection(null, level, LanguageUtils.getFullStopSymbol(lang));
112 				}
113 				if (mSpecs.ensureWordBefore.test(node)) {
114 					addToSection(null, level, LanguageUtils.getCommaSymbol(lang));
115 				}
116 
117 				if (!iter.hasNext()) {
118 					//*** text-free leaf ***
119 					addToSection(node, level, null);
120 				} else {
121 					while (iter.hasNext()) {
122 						XdmNode child = (XdmNode) iter.next();
123 						findRec(child, level + 1, lang);
124 					}
125 				}
126 
127 				if (mSpecs.ensureWordAfter.test(node)) {
128 					addToSection(null, level, LanguageUtils.getCommaSymbol(lang));
129 				}
130 				if (mSpecs.ensureSentenceAfter.test(node)) {
131 					addToSection(null, level, LanguageUtils.getFullStopSymbol(lang));
132 				}
133 			} else {
134 				notifyNewSection();
135 				if (!iter.hasNext()) {
136 					//*** text-free leaf ***
137 					addToSection(node, level, null);
138 
139 				} else {
140 					//*** non-inline element ***
141 					while (iter.hasNext()) {
142 						XdmNode child = (XdmNode) iter.next();
143 						findRec(child, level + 1, lang);
144 					}
145 				}
146 				notifyNewSection();
147 			}
148 		}
149 	}
150 }