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