17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 2009, International Business Machines Corporation and         *
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved.                                                *
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl;
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException;
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.UResourceBundle;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Calendar utilities.
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Date/time format service classes in com.ibm.icu.text packages
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * sometimes need to access calendar internal APIs.  But calendar
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * classes are in com.ibm.icu.util package, so the package local
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * cannot be used.  This class is added in com.ibm.icu.impl
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * package for sharing some calendar internal code for calendar
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and date format.
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class CalendarUtil {
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static ICUCache<String, String> CALTYPE_CACHE = new SimpleCache<String, String>();
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String CALKEY = "calendar";
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String DEFCAL = "gregorian";
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns a calendar type for the given locale.
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * When the given locale has calendar keyword, the
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * value of calendar keyword is returned.  Otherwise,
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the default calendar type for the locale is returned.
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param loc The locale
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return Calendar type string, such as "gregorian"
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static String getCalendarType(ULocale loc) {
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String calType = null;
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        calType = loc.getKeywordValue(CALKEY);
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (calType != null) {
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return calType;
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String baseLoc = loc.getBaseName();
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Check the cache
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        calType = CALTYPE_CACHE.get(baseLoc);
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (calType != null) {
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return calType;
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Canonicalize, so grandfathered variant will be transformed to keywords
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ULocale canonical = ULocale.createCanonical(loc.toString());
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        calType = canonical.getKeywordValue("calendar");
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (calType == null) {
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // When calendar keyword is not available, use the locale's
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // region to get the default calendar type
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String region = canonical.getCountry();
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (region.length() == 0) {
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ULocale fullLoc = ULocale.addLikelySubtags(canonical);
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                region = fullLoc.getCountry();
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Read supplementalData to get the default calendar type for
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // the locale's region
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            try {
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                UResourceBundle rb = UResourceBundle.getBundleInstance(
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        ICUResourceBundle.ICU_BASE_NAME,
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        "supplementalData",
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        ICUResourceBundle.ICU_DATA_CLASS_LOADER);
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                UResourceBundle calPref = rb.get("calendarPreferenceData");
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                UResourceBundle order = null;
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                try {
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    order = calPref.get(region);
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } catch (MissingResourceException mre) {
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // use "001" as fallback
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    order = calPref.get("001");
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // the first calendar type is the default for the region
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                calType = order.getString(0);
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } catch (MissingResourceException mre) {
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // fall through
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (calType == null) {
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Use "gregorian" as the last resort fallback.
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                calType = DEFCAL;
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Cache the resolved value for the next time
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CALTYPE_CACHE.put(baseLoc, calType);
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return calType;
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
101