1   package org.daisy.pipeline.braille.pef.impl;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.HashMap;
7   import java.util.HashSet;
8   import java.util.List;
9   import java.util.Locale;
10  import java.util.Map;
11  import java.util.Set;
12  
13  import com.google.common.collect.ImmutableSet;
14  
15  import org.daisy.dotify.api.factory.FactoryProperties;
16  import org.daisy.dotify.api.table.Table;
17  
18  import org.daisy.pipeline.braille.common.Query;
19  import org.daisy.pipeline.braille.common.Query.Feature;
20  import org.daisy.pipeline.braille.common.Query.MutableQuery;
21  import static org.daisy.pipeline.braille.common.Query.util.mutableQuery;
22  import static org.daisy.pipeline.braille.common.util.Locales.parseLocale;
23  import org.daisy.pipeline.braille.pef.AbstractTableProvider;
24  import org.daisy.pipeline.braille.pef.TableProvider;
25  import org.daisy.pipeline.common.NormalizeLang;
26  
27  import org.osgi.service.component.annotations.Activate;
28  import org.osgi.service.component.annotations.Component;
29  import org.osgi.service.component.annotations.Reference;
30  import org.osgi.service.component.annotations.ReferenceCardinality;
31  import org.osgi.service.component.annotations.ReferencePolicy;
32  
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  /**
37   * @see <a href="../../../../../../../README.md">Documentation</a>
38   */
39  @Component(
40  	name = "org.daisy.pipeline.braille.pef.impl.LocaleTableProvider",
41  	service = {
42  		TableProvider.class
43  		// org.daisy.dotify.api.table.TableProvider.class
44  	}
45  )
46  public class LocaleBasedTableProvider extends AbstractTableProvider {
47  	
48  	private static Set<String> supportedFeatures = ImmutableSet.of("locale", "document-locale");
49  	private static Map<Locale,TableProxy> tableFromLocale = new HashMap<>();
50  	
51  	@Activate
52  	protected void init() {
53  		putTable("org_daisy.EmbosserTableProvider.TableType.CS_CZ",                   parseLocale("cs"));
54  		putTable("org_daisy.EmbosserTableProvider.TableType.DA_DK",                   parseLocale("da"));
55  		putTable("org_daisy.EmbosserTableProvider.TableType.DE_DE",                   parseLocale("de"));
56  		putTable("org.daisy.braille.impl.table.DefaultTableProvider.TableType.EN_US", parseLocale("en"));
57  		putTable("org_daisy.EmbosserTableProvider.TableType.EN_GB",                   parseLocale("en-GB"));
58  		putTable("org.daisy.braille.impl.table.DefaultTableProvider.TableType.EN_US", parseLocale("en-US"));
59  		putTable("org_daisy.EmbosserTableProvider.TableType.ES_ES_TABLE_2",           parseLocale("es"));
60  		putTable("org_daisy.EmbosserTableProvider.TableType.IT_IT_FIRENZE",           parseLocale("it"));
61  		putTable("com_braillo.BrailloTableProvider.TableType.BRAILLO_6DOT_047_01",    parseLocale("nb"));
62  		putTable("com_braillo.BrailloTableProvider.TableType.BRAILLO_6DOT_031_01",    parseLocale("nl"));
63  		putTable("com_braillo.BrailloTableProvider.TableType.BRAILLO_6DOT_047_01",    parseLocale("no"),
64  		                                                                              parseLocale("nn"),
65  		                                                                              parseLocale("nb"));
66  		putTable("com_braillo.BrailloTableProvider.TableType.BRAILLO_6DOT_046_01",    parseLocale("sv"));
67  	}
68  
69  	private void putTable(String id, Locale... locales) {
70  		for (org.daisy.dotify.api.table.TableProvider p : providers)
71  			for (FactoryProperties fp : p.list())
72  				if (fp.getIdentifier().equals(id)) {
73  					TableProxy table = null;
74  					for (Locale locale : locales) {
75  						if (table == null)
76  							table = new TableProxy(fp, p, locale);
77  						tableFromLocale.put(locale, table);
78  					}
79  					break;
80  				}
81  	}
82  
83  	private Collection<FactoryProperties> properties = null;
84  
85  	@Override
86  	public Collection<FactoryProperties> list() {
87  		if (properties == null)
88  			properties = Collections.unmodifiableCollection(new HashSet<>(tableFromLocale.values()));
89  		return properties;
90  	}
91  
92  	/**
93  	 * Recognized features:
94  	 *
95  	 * - locale: A locale that is mapped to a specific table
96  	 *     that is a sane default for that locale.
97  	 */
98  	@Override
99  	protected Iterable<Table> _get(Query query) {
100 		for (Feature feature : query)
101 			if (!supportedFeatures.contains(feature.getKey())) {
102 				logger.debug("Unsupported feature: " + feature);
103 				return empty; }
104 		Iterable<Table> table = empty;
105 		MutableQuery q = mutableQuery(query);
106 		Locale documentLocale; {
107 			try {
108 				documentLocale = q.containsKey("document-locale")
109 					? NormalizeLang.normalize(parseLocale(q.removeOnly("document-locale").getValue().get()))
110 					: null; }
111 			catch (IllegalArgumentException e) {
112 				logger.error("Invalid locale", e);
113 				documentLocale = null; }}
114 		if (q.containsKey("locale")) {
115 			Locale locale; {
116 				try {
117 					locale = NormalizeLang.normalize(parseLocale(q.removeOnly("locale").getValue().get())); }
118 				catch (IllegalArgumentException e) {
119 					logger.error("Invalid locale", e);
120 					return empty; }}
121 			if (q.isEmpty()) {
122 				TableProxy t = tableFromLocale.get(locale);
123 				if (t == null)
124 					t = tableFromLocale.get(new Locale(locale.getLanguage()));
125 				if (t != null)
126 					table = Collections.singleton(t.getTable()); }}
127 		else if (documentLocale != null && q.isEmpty()) {
128 			TableProxy t = tableFromLocale.get(documentLocale);
129 			if (t == null)
130 				t = tableFromLocale.get(new Locale(documentLocale.getLanguage()));
131 			if (t != null)
132 				table = Collections.singleton(t.getTable()); }
133 		return table;
134 	}
135 	
136 	private final static Iterable<Table> empty = Collections.<Table>emptyList();
137 	
138 	private final List<org.daisy.dotify.api.table.TableProvider> providers
139 	= new ArrayList<org.daisy.dotify.api.table.TableProvider>();
140 	
141 	@Reference(
142 		name = "TableProvider",
143 		unbind = "-",
144 		service = org.daisy.dotify.api.table.TableProvider.class,
145 		cardinality = ReferenceCardinality.MULTIPLE,
146 		policy = ReferencePolicy.STATIC
147 	)
148 	public void addTableProvider(org.daisy.dotify.api.table.TableProvider provider) {
149 		providers.add(provider);
150 	}
151 	
152 	public void removeTableProvider(org.daisy.dotify.api.table.TableProvider provider) {
153 		providers.remove(provider);
154 	}
155 	
156 	static class TableProxy implements FactoryProperties {
157 
158 		private final org.daisy.dotify.api.table.TableProvider provider;
159 		private final FactoryProperties properties;
160 		private final Locale locale;
161 		private Table table = null;
162 
163 		public TableProxy(FactoryProperties properties, org.daisy.dotify.api.table.TableProvider provider, Locale locale) {
164 			this.properties = properties;
165 			this.provider = provider;
166 			this.locale = locale;
167 		}
168 
169 		public Table getTable() {
170 			if (table == null)
171 				table = provider.newFactory(properties.getIdentifier());
172 			return table;
173 		}
174 
175 		public Locale getLocale() {
176 			return locale;
177 		}
178 
179 		@Override
180 		public String getIdentifier() {
181 			return properties.getIdentifier();
182 		}
183 
184 		@Override
185 		public String getDisplayName() {
186 			return "Default table for " + locale.getDisplayName();
187 		}
188 
189 		@Override
190 		public String getDescription() {
191 			if (getIdentifier().startsWith("org_daisy") ||
192 			    getIdentifier().startsWith("org.daisy"))
193 				return null;
194 			else
195 				return properties.getDescription();
196 		}
197 	}
198 	
199 	private static final Logger logger = LoggerFactory.getLogger(LocaleBasedTableProvider.class);
200 }