/*
* -----------------------------------------------------------------------
* Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/>
* -----------------------------------------------------------------------
* This file (GenericTextProviderSPI.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see <http://www.gnu.org/licenses/>.
* -----------------------------------------------------------------------
*/
package net.time4j.calendar.service;
import net.time4j.format.OutputContext;
import net.time4j.format.TextProvider;
import net.time4j.format.TextWidth;
import net.time4j.i18n.IsoTextProviderSPI;
import net.time4j.i18n.UTF8ResourceControl;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
/**
* <p>{@code ServiceProvider}-implementation for accessing localized calendrical
* names in any calendar (but not ISO-8601). </p>
*
* <p>The underlying properties files are located in the folder
* "calendar" relative to class path and are encoded in UTF-8.
* The basic bundle name corresponds to the choosen calendar type. </p>
*
* @author Meno Hochschild
*/
public final class GenericTextProviderSPI
implements TextProvider {
//~ Statische Felder/Initialisierungen --------------------------------
private static final String[] EMPTY_STRINGS = new String[0];
private static final Set<String> LANGUAGES;
private static final Set<Locale> LOCALES;
private static final ResourceBundle.Control CONTROL;
static {
CONTROL =
new UTF8ResourceControl() {
protected String getModuleName() {
return "calendar";
}
protected Class<?> getModuleRef() {
return GenericTextProviderSPI.class;
}
};
ResourceBundle rb =
ResourceBundle.getBundle(
"names/generic",
Locale.ROOT,
getDefaultLoader(),
CONTROL);
String[] languages = rb.getString("languages").split(" ");
Set<String> tmp = new HashSet<>();
Collections.addAll(tmp, languages);
tmp.add("");
LANGUAGES = Collections.unmodifiableSet(tmp);
Set<Locale> locs = new HashSet<>();
for (String lang : LANGUAGES) {
if (lang.isEmpty()) {
locs.add(Locale.ROOT);
} else {
locs.add(new Locale(lang));
}
}
LOCALES = Collections.unmodifiableSet(locs);
}
//~ Konstruktoren -----------------------------------------------------
/** For {@code java.util.ServiceLoader}. */
public GenericTextProviderSPI() {
super();
}
//~ Methoden ----------------------------------------------------------
@Override
public String[] getSupportedCalendarTypes() {
return new String[] { "buddhist", "coptic", "ethiopic", "generic", "islamic", "persian", "roc" };
}
@Override
public Locale[] getAvailableLocales() {
return LOCALES.toArray(new Locale[LOCALES.size()]);
}
@Override
public String[] months(
String calendarType,
Locale locale,
TextWidth tw,
OutputContext oc,
boolean leapForm
) {
if (calendarType.equals("roc") || calendarType.equals("buddhist")) {
TextProvider p = new IsoTextProviderSPI();
return p.months(calendarType, locale, tw, oc, leapForm);
}
ResourceBundle rb = getBundle(calendarType, locale);
if (tw == TextWidth.SHORT) {
tw = TextWidth.ABBREVIATED;
}
String key = getKey(rb, "MONTH_OF_YEAR");
String[] names = lookupBundle(rb, countOfMonths(calendarType), key, tw, oc, leapForm, 1);
// fallback rules as found in CLDR-root-properties via alias paths
if (names == null) {
if (oc == OutputContext.STANDALONE) {
if (tw != TextWidth.NARROW) {
names = months(calendarType, locale, tw, OutputContext.FORMAT, leapForm);
}
} else {
if (tw == TextWidth.ABBREVIATED) {
names = months(calendarType, locale, TextWidth.WIDE, OutputContext.FORMAT, leapForm);
} else if (tw == TextWidth.NARROW) {
names = months(calendarType, locale, tw, OutputContext.STANDALONE, leapForm);
}
}
}
if (names == null) {
throw new MissingResourceException(
"Cannot find calendar month.",
GenericTextProviderSPI.class.getName(),
locale.toString());
}
return names;
}
@Override
public String[] quarters(
String calendarType,
Locale locale,
TextWidth tw,
OutputContext oc
) {
return EMPTY_STRINGS;
}
@Override
public String[] weekdays(
String calendarType,
Locale locale,
TextWidth tw,
OutputContext oc
) {
return EMPTY_STRINGS;
}
@Override
public String[] eras(
String calendarType,
Locale locale,
TextWidth tw
) {
ResourceBundle rb = getBundle(calendarType, locale);
if (tw == TextWidth.SHORT) {
tw = TextWidth.ABBREVIATED;
}
String key = getKey(rb, "ERA");
String[] names = lookupBundle(rb, countOfEras(calendarType), key, tw, OutputContext.FORMAT, false, 0);
if ((names == null) && (tw != TextWidth.ABBREVIATED)) {
names = eras(calendarType, locale, TextWidth.ABBREVIATED);
}
if (names == null) {
throw new MissingResourceException(
"Cannot find calendar resource for era.",
GenericTextProviderSPI.class.getName(),
locale.toString());
}
return names;
}
@Override
public String[] meridiems(
String calendarType,
Locale locale,
TextWidth tw
) {
return EMPTY_STRINGS;
}
@Override
public ResourceBundle.Control getControl() {
return CONTROL;
}
@Override
public String toString() {
return "GenericTextProviderSPI";
}
/**
* <p>Gets a resource bundle for given calendar type and locale. </p>
*
* @param calendarType calendar type (usually non-gregorian)
* @param desired locale (language and/or country)
* @return {@code ResourceBundle}
* @since 3.10/4.7
*/
static ResourceBundle getBundle(
String calendarType,
Locale desired
) {
return ResourceBundle.getBundle(
"names/" + calendarType,
LANGUAGES.contains(desired.getLanguage()) ? desired : Locale.ROOT,
getDefaultLoader(),
CONTROL);
}
private static String[] lookupBundle(
ResourceBundle rb,
int len,
String elementName,
TextWidth tw,
OutputContext oc,
boolean leapForm,
int baseIndex
) {
String[] names = new String[len];
boolean shortKey = (elementName.length() == 1);
for (int i = 0; i < len; i++) {
StringBuilder b = new StringBuilder();
b.append(elementName);
b.append('(');
if (shortKey) {
char c = tw.name().charAt(0);
if (oc != OutputContext.STANDALONE) {
c = Character.toLowerCase(c);
}
b.append(c);
} else {
b.append(tw.name());
if (oc == OutputContext.STANDALONE) {
b.append('|');
b.append(oc.name());
}
if (leapForm) {
b.append('|');
b.append("LEAP");
}
}
b.append(')');
b.append('_');
b.append(i + baseIndex);
String key = b.toString();
if (rb.containsKey(key)) {
names[i] = rb.getString(key);
} else {
return null;
}
}
return names;
}
private static String getKey(
ResourceBundle bundle,
String elementName
) {
if (
bundle.containsKey("useShortKeys")
&& "true".equals(bundle.getString("useShortKeys"))
) {
return elementName.substring(0, 1);
}
return elementName;
}
private static ClassLoader getDefaultLoader() {
return GenericTextProviderSPI.class.getClassLoader();
}
private static int countOfMonths(String ct) {
return ((ct.equals("coptic") || ct.equals("ethiopic") || ct.equals("generic")) ? 13 : 12);
}
private static int countOfEras(String ct) {
return ((ct.equals("ethiopic") || ct.equals("generic") || ct.equals("roc") || ct.equals("buddhist")) ? 2 : 1);
}
}