1 package org.daisy.pipeline.braille.dotify.impl;
2
3 import java.net.URI;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.Map;
7 import java.util.NoSuchElementException;
8
9 import javax.xml.namespace.QName;
10
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.collect.ImmutableMap;
14
15 import com.xmlcalabash.core.XProcRuntime;
16 import com.xmlcalabash.runtime.XAtomicStep;
17
18 import org.daisy.common.file.URLs;
19 import org.daisy.common.transform.InputValue;
20 import org.daisy.common.transform.Mult;
21 import org.daisy.common.transform.SingleInSingleOutXMLTransformer;
22 import org.daisy.common.transform.XMLInputValue;
23 import org.daisy.common.transform.XMLOutputValue;
24 import org.daisy.common.xproc.calabash.XProcStep;
25 import org.daisy.common.xproc.calabash.XProcStepProvider;
26 import org.daisy.common.xproc.XProcMonitor;
27 import org.daisy.dotify.api.table.Table;
28 import org.daisy.pipeline.braille.common.AbstractTransform;
29 import org.daisy.pipeline.braille.common.AbstractTransformProvider;
30 import org.daisy.pipeline.braille.common.AbstractTransformProvider.util.Iterables;
31 import org.daisy.pipeline.braille.common.calabash.CxEvalBasedTransformer;
32 import static org.daisy.pipeline.braille.common.AbstractTransformProvider.util.logCreate;
33 import static org.daisy.pipeline.braille.common.AbstractTransformProvider.util.logSelect;
34 import org.daisy.pipeline.braille.common.BrailleTranslator;
35 import org.daisy.pipeline.braille.common.BrailleTranslatorRegistry;
36 import org.daisy.pipeline.braille.common.Query;
37 import org.daisy.pipeline.braille.common.Query.Feature;
38 import org.daisy.pipeline.braille.common.Query.MutableQuery;
39 import static org.daisy.pipeline.braille.common.Query.util.mutableQuery;
40 import static org.daisy.pipeline.braille.common.Query.util.query;
41 import org.daisy.pipeline.braille.common.Transform;
42 import org.daisy.pipeline.braille.common.TransformProvider;
43 import org.daisy.pipeline.braille.pef.TableRegistry;
44
45 import org.osgi.service.component.annotations.Activate;
46 import org.osgi.service.component.annotations.Component;
47 import org.osgi.service.component.annotations.Reference;
48 import org.osgi.service.component.annotations.ReferenceCardinality;
49 import org.osgi.service.component.annotations.ReferencePolicy;
50
51 import static org.slf4j.helpers.NOPLogger.NOP_LOGGER;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55
56
57
58 public interface DotifyCSSStyledDocumentTransform {
59
60 @Component(
61 name = "org.daisy.pipeline.braille.dotify.impl.DotifyCSSStyledDocumentTransform.Provider",
62 service = {
63 TransformProvider.class
64 }
65 )
66 public class Provider extends AbstractTransformProvider<Transform> {
67
68 private static final Logger logger = LoggerFactory.getLogger(DotifyCSSStyledDocumentTransform.class);
69
70 private URI href;
71
72 @Activate
73 protected void activate(final Map<?,?> properties) {
74 href = URLs.asURI(URLs.getResourceFromJAR("xml/transform/dotify-transform.xpl", DotifyCSSStyledDocumentTransform.class));
75 }
76
77 private final static Iterable<Transform> empty = Iterables.<Transform>empty();
78
79 protected Iterable<Transform> _get(Query query) {
80 final MutableQuery q = mutableQuery(query);
81 try {
82 if ("css".equals(q.removeOnly("input").getValue().get())) {
83 if (q.containsKey("formatter"))
84 if (!"dotify".equals(q.removeOnly("formatter").getValue().get()))
85 return empty;
86 boolean braille = false;
87 boolean pef = false;
88 boolean obfl = false;
89 for (Feature f : q.removeAll("output"))
90 if ("pef".equals(f.getValue().get()))
91 pef = true;
92 else if ("obfl".equals(f.getValue().get()))
93 obfl = true;
94 else if ("braille".equals(f.getValue().get()))
95 braille = true;
96 else
97 return empty;
98 if ((pef && obfl) || !(pef || obfl))
99 return empty;
100 boolean forcePretranslation = false;
101 if (q.containsKey("force-pre-translation")) {
102 forcePretranslation = true;
103 q.removeOnly("force-pre-translation");
104 }
105 Query textTransformQuery = mutableQuery(q).add("input", "text-css").add("output", "braille");
106 if (logSelect(textTransformQuery, translatorRegistry).apply(NOP_LOGGER).iterator().hasNext()) {
107 MutableQuery blockTransformQuery = null; {
108
109 if (obfl && braille || forcePretranslation) {
110 blockTransformQuery = mutableQuery(q).add("input", "css")
111 .add("output", "css")
112 .add("output", "braille");
113 if (!logSelect(blockTransformQuery, translatorRegistry).apply(NOP_LOGGER).iterator().hasNext())
114 return empty;
115 }
116 }
117 return AbstractTransformProvider.util.Iterables.of(
118 logCreate(new TransformImpl(obfl, blockTransformQuery, textTransformQuery))); }}}
119 catch (IllegalStateException e) {}
120 return empty;
121 }
122
123 private class TransformImpl extends AbstractTransform implements XProcStepProvider {
124
125 private final String output;
126 private final Query blockTransformQuery;
127 private final Query textTransformQuery;
128 private final Map<String,String> options;
129
130 private TransformImpl(boolean obfl,
131 Query blockTransformQuery,
132 Query textTransformQuery) {
133 MutableQuery mode = mutableQuery(textTransformQuery);
134 String locale = "und";
135 if (mode.containsKey("document-locale"))
136 locale = mode.removeOnly("document-locale").getValue().get();
137
138 Iterator<Feature> input = mode.get("input").iterator();
139 while (input.hasNext())
140 if ("text-css".equals(input.next().getValue().get()))
141 input.remove();
142
143 Iterator<Feature> output = mode.get("output").iterator();
144 while (output.hasNext())
145 if ("braille".equals(output.next().getValue().get()))
146 output.remove();
147 this.output = obfl ? "obfl" : "pef";
148 options = ImmutableMap.of(
149 "output", this.output,
150 "css-block-transform", blockTransformQuery != null ? blockTransformQuery.toString() : "",
151 "document-locale", locale,
152 "text-transform", mode.toString());
153 this.blockTransformQuery = blockTransformQuery;
154 this.textTransformQuery = textTransformQuery;
155 }
156
157 @Override
158 public XProcStep newStep(XProcRuntime runtime, XAtomicStep step, XProcMonitor monitor, Map<String,String> properties) {
159 return XProcStep.of(
160 new SingleInSingleOutXMLTransformer() {
161 public Runnable transform(XMLInputValue<?> source, XMLOutputValue<?> result, InputValue<?> params) {
162 return () -> {
163 Map<String,String> options = TransformImpl.this.options;
164 InputValue<?> paramsCopy = params;
165
166 try {
167 Mult<? extends InputValue<?>> m = params.mult(2);
168 paramsCopy = m.get();
169 Map map = m.get().asObject(Map.class);
170 Object v = map.get(new QName("preview-table"));
171 if (v != null)
172 if (v instanceof InputValue) {
173 m = ((InputValue<?>)v).mult(2);
174 map.put(new QName("preview-table"), m.get());
175 try {
176 v = m.get().asObject();
177 if (v instanceof String) {
178 try {
179 Table previewTable = tableRegistry.get(query((String)v)).iterator().next();
180
181
182 MutableQuery q = mutableQuery(textTransformQuery).add("braille-charset",
183 previewTable.getIdentifier());
184 if (logSelect(q, translatorRegistry).apply(NOP_LOGGER).iterator().hasNext()) {
185 q.removeAll("document-locale");
186 options = new HashMap<>(); {
187 options.putAll(TransformImpl.this.options);
188 options.put("css-block-transform",
189 blockTransformQuery != null
190 ? mutableQuery(blockTransformQuery)
191 .add("braille-charset", previewTable.getIdentifier())
192 .toString()
193 : "");
194 options.put("braille-charset", previewTable.getIdentifier());
195 }
196 }
197 } catch (NoSuchElementException e) {
198 }
199 }
200 } catch (UnsupportedOperationException e) {
201 }
202 }
203 } catch (UnsupportedOperationException e) {
204 }
205 new CxEvalBasedTransformer(
206 href,
207 null,
208 options
209 ).newStep(runtime, step, monitor, properties).transform(
210 ImmutableMap.of(
211 new QName("source"), source,
212 new QName("parameters"), paramsCopy),
213 ImmutableMap.of(
214 new QName("result"), result)
215 ).run();
216 };
217 }
218 },
219 runtime,
220 step
221 );
222 }
223
224 @Override
225 public ToStringHelper toStringHelper() {
226 return MoreObjects.toStringHelper("DotifyCSSStyledDocumentTransform$Provider$TransformImpl")
227 .add("output", output)
228 .add("textTransform", textTransformQuery);
229 }
230 }
231
232 @Reference(
233 name = "BrailleTranslatorRegistry",
234 unbind = "-",
235 service = BrailleTranslatorRegistry.class,
236 cardinality = ReferenceCardinality.MANDATORY,
237 policy = ReferencePolicy.STATIC
238 )
239 protected void bindBrailleTranslatorRegistry(BrailleTranslatorRegistry registry) {
240 translatorRegistry = registry.withContext(logger);
241 }
242
243 private BrailleTranslatorRegistry translatorRegistry;
244
245 @Reference(
246 name = "TableRegistry",
247 unbind = "-",
248 service = TableRegistry.class,
249 cardinality = ReferenceCardinality.MANDATORY,
250 policy = ReferencePolicy.STATIC
251 )
252 protected void bindTableRegistry(TableRegistry registry) {
253 tableRegistry = registry;
254 }
255
256 private TableRegistry tableRegistry;
257
258 @Override
259 public ToStringHelper toStringHelper() {
260 return MoreObjects.toStringHelper("DotifyCSSStyledDocumentTransform$Provider");
261 }
262 }
263 }