1   package org.daisy.pipeline.braille.dotify.impl;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   import java.util.Locale;
6   import java.util.Map;
7   
8   import cz.vutbr.web.css.CSSProperty;
9   import cz.vutbr.web.css.Term;
10  import cz.vutbr.web.css.TermIdent;
11  import cz.vutbr.web.css.TermList;
12  
13  import org.daisy.braille.css.SimpleInlineStyle;
14  import org.daisy.braille.css.BrailleCSSProperty.TextTransform;
15  import org.daisy.pipeline.braille.common.AbstractBrailleTranslator;
16  import org.daisy.pipeline.braille.common.BrailleTranslator;
17  import org.daisy.pipeline.braille.common.BrailleTranslator.LineBreakingFromStyledText;
18  import org.daisy.pipeline.braille.common.Hyphenator;
19  import org.daisy.pipeline.braille.css.CSSStyledText;
20  import org.daisy.pipeline.css.CounterStyle;
21  
22  /**
23   * {@link BrailleTranslator} that handles the <code>text-transform</code> value
24   * "<code>-dotify-counter</code>", which causes numbers to be formatted according to the
25   * value of the <code>-dotify-counter-style</code>
26   * property. <code>-dotify-counter-style</code> can be the name of a custom counter style,
27   * or a <code>symbols()</code> function.
28   */
29  public class CounterHandlingBrailleTranslator extends AbstractBrailleTranslator implements LineBreakingFromStyledText {
30  
31  	private final BrailleTranslator backingTranslator;
32  	private final LineBreakingFromStyledText backingLineBreakingTranslator;
33  	private final Map<String,CounterStyle> customCounterStyles;
34  
35  	public CounterHandlingBrailleTranslator(BrailleTranslator backingTranslator,
36  	                                        Map<String,CounterStyle> customCounterStyles) {
37  		this.backingTranslator = backingTranslator;
38  		this.backingLineBreakingTranslator = backingTranslator.lineBreakingFromStyledText();
39  		this.customCounterStyles = customCounterStyles;
40  	}
41  
42  	private CounterHandlingBrailleTranslator(CounterHandlingBrailleTranslator from, BrailleTranslator backingTranslator) {
43  		super(from);
44  		this.backingTranslator = backingTranslator;
45  		this.backingLineBreakingTranslator = backingTranslator.lineBreakingFromStyledText();
46  		this.customCounterStyles = from.customCounterStyles;
47  	}
48  
49  	/**
50  	 * @throws UnsupportedOperationException if {@code backingTranslator.withHyphenator()} throws
51  	 *                                       UnsupportedOperationException
52  	 */
53  	@Override
54  	public CounterHandlingBrailleTranslator _withHyphenator(Hyphenator hyphenator) throws UnsupportedOperationException {
55  		return new CounterHandlingBrailleTranslator(this, backingTranslator.withHyphenator(hyphenator));
56  	}
57  
58  	@Override
59  	public LineBreakingFromStyledText lineBreakingFromStyledText() {
60  		return this;
61  	}
62  
63  	public LineIterator transform(Iterable<CSSStyledText> styledText, int from, int to) {
64  		return backingLineBreakingTranslator.transform(handleCounterStyles(styledText), from, to);
65  	}
66  
67  	private Iterable<CSSStyledText> handleCounterStyles(Iterable<CSSStyledText> styledText) {
68  		List<CSSStyledText> segments = new ArrayList<CSSStyledText>();
69  		String segment = null;
70  		SimpleInlineStyle style = null;
71  		Locale lang = null;
72  		Map<String,String> attrs = null;
73  		for (CSSStyledText st : styledText) {
74  			String t = st.getText();
75  			SimpleInlineStyle s = st.getStyle();
76  			Locale l = st.getLanguage();
77  			Map<String,String> a = st.getTextAttributes();
78  			if (s != null) {
79  				if (s.getProperty("text-transform") == TextTransform.list_values) {
80  					TermList list = s.getValue(TermList.class, "text-transform");
81  					if (((TermIdent)list.get(0)).getValue().equals("-dotify-counter")) {
82  						if (list.size() == 1)
83  							s.removeProperty("text-transform");
84  						else
85  							list.remove(0);
86  						if ("??".equals(t)) {
87  							// If input text is "??", it will be used for creating a placeholder for content that
88  							// can not be computed yet (see org.daisy.dotify.formatter.impl.row.SegmentProcessor).
89  						} else {
90  							int counterValue = Integer.parseInt(t);
91  							Term<?> symbolsFunction = s.getValue("-dotify-counter-style");
92  							if (symbolsFunction != null) {
93  								try {
94  									t = CounterStyle.fromSymbolsFunction(symbolsFunction).format(counterValue);
95  								} catch (IllegalArgumentException e) {
96  									// FIXME: show warning
97  								}
98  							} else {
99  								CSSProperty counterStyleName = s.getProperty("-dotify-counter-style");
100 								if (counterStyleName != null
101 								    && customCounterStyles != null
102 								    && customCounterStyles.containsKey(counterStyleName.toString())) {
103 									t = customCounterStyles.get(counterStyleName.toString()).format(counterValue);
104 								}
105 							}
106 						}
107 					}
108 				}
109 				s.removeProperty("-dotify-counter-style"); }
110 			if (segment != null)
111 				segments.add(new CSSStyledText(segment, style, lang, attrs));
112 			segment = t;
113 			style = s;
114 			lang = l;
115 			attrs = a; }
116 		if (segment != null)
117 			segments.add(new CSSStyledText(segment, style, lang, attrs));
118 		return segments;
119 	}
120 }