/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.sling.i18n.impl;

import static org.apache.sling.i18n.impl.JcrResourceBundle.PROP_BASENAME;
import static org.apache.sling.i18n.impl.JcrResourceBundle.PROP_LANGUAGE;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.regex.Pattern;

import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.resource.observation.ExternalResourceChangeListener;
import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.apache.sling.i18n.ResourceBundleProvider;
import org.apache.sling.serviceusermapping.ServiceUserMapped;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The <code>JcrResourceBundleProvider</code> implements the
 * <code>ResourceBundleProvider</code> interface creating
 * <code>ResourceBundle</code> instances from resources stored in the
 * repository.
 */
@Component(service = {ResourceBundleProvider.class, ResourceChangeListener.class},
    property = {
            Constants.SERVICE_DESCRIPTION + "=Apache Sling I18n Resource Bundle Provider",
            Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
            ResourceChangeListener.PATHS + "=/"
    })
@Designate(ocd = JcrResourceBundleProvider.Config.class)
public class JcrResourceBundleProvider implements ResourceBundleProvider, ResourceChangeListener, ExternalResourceChangeListener {

    /**
     * A regular expression pattern matching all custom country codes.
     * @see <a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#User-assigned_code_elements">User-assigned code elements</a>
     */
    private static final Pattern USER_ASSIGNED_COUNTRY_CODES_PATTERN = Pattern.compile("aa|q[m-z]|x[a-z]|zz");

    @ObjectClassDefinition(name ="Apache Sling I18N Resource Bundle Provider",
            description ="ResourceBundleProvider service which loads the messages "+
                 "from the repository. If the user name field is left empty, the provider will "+
                 "log into the repository as the administrative user. Otherwise the given user "+
                 "name and password are used to access the repository. Failing to access the "+
                 "repository, effectively disables the provider.")
    public @interface Config {

        @AttributeDefinition(name = "Default Locale",
            description = "The default locale to assume if none can be "+
                 "resolved otherwise. This value must be in the form acceptable to the "+
                 "java.util.Locale class.")
        String locale_default() default "en";

        @AttributeDefinition(name = "Preload Bundles",
                description = "Whether or not to eagerly load the resource bundles "+
                    "on bundle start or a cache invalidation.")
        boolean preload_bundles() default false;

        @AttributeDefinition(name = "Invalidation Delay",
                description = "In case of dictionary change events the cached "+
                        "resource bundle becomes invalid after the given delay (in ms). ")
        long invalidation_delay() default 5000;
    }

    @Reference
    private Scheduler scheduler;

    /** job names of scheduled jobs for reloading individual bundles */
    private final Collection<String> scheduledJobNames = Collections.synchronizedList(new ArrayList<String>()) ;

    /** default log */
    private final Logger log = LoggerFactory.getLogger(getClass());

    @Reference
    private ResourceResolverFactory resourceResolverFactory;

    @Reference
    private ServiceUserMapped serviceUserMapped;

    /**
     * The default Locale as configured with the <i>locale.default</i>
     * configuration property. This defaults to <code>Locale.ENGLISH</code> if
     * the configuration property is not set.
     */
    private volatile Locale defaultLocale = Locale.ENGLISH;

    /**
     * Map of cached resource bundles indexed by a key combined of the base name
     * and <code>Locale</code> used to load and identify the <code>ResourceBundle</code>.
     */
    private final ConcurrentHashMap<Key, JcrResourceBundle> resourceBundleCache = new ConcurrentHashMap<>();

    private final ConcurrentHashMap<Key, Semaphore> loadingGuards = new ConcurrentHashMap<>();

    /**
     * paths from which JCR resource bundles have been loaded
     */
    private final Set<String> languageRootPaths = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());

    /**
     * Return root resource bundle as created on-demand by
     * {@link #getRootResourceBundle()}.
     */
    private volatile ResourceBundle rootResourceBundle;

    private volatile BundleContext bundleContext;

    /**
     * Each ResourceBundle is registered as a service. Each registration is stored in this map with the locale & base name used as a key.
     */
    private final Map<Key, ServiceRegistration<ResourceBundle>> bundleServiceRegistrations = new HashMap<>();

    private boolean preloadBundles;

    private long invalidationDelay;

    private ResourceResolver createResourceResolver() throws LoginException {
        return resourceResolverFactory.getServiceResourceResolver(null);
    }

    // ---------- ResourceBundleProvider ---------------------------------------

    /**
     * Returns the configured default <code>Locale</code> which is used as a
     * fallback for {@link #getResourceBundle(Locale)} and also as the basis for
     * any messages requested from resource bundles.
     */
    @Override
    public Locale getDefaultLocale() {
        return defaultLocale;
    }

    /**
     * Returns the <code>ResourceBundle</code> for the given
     * <code>locale</code>.
     *
     * @param locale The <code>Locale</code> for which to return the resource
     *            bundle. If this is <code>null</code> the configured
     *            {@link #getDefaultLocale() default locale} is assumed.
     * @return The <code>ResourceBundle</code> for the given locale.
     * @throws MissingResourceException If the <code>ResourceResolver</code>
     *             is not available to access the resources.
     */
    @Override
    public ResourceBundle getResourceBundle(final Locale locale) {
        return getResourceBundle(null, locale);
    }

    @Override
    public ResourceBundle getResourceBundle(final String baseName, Locale locale) {
        if (locale == null) {
            locale = defaultLocale;
        }

        return getResourceBundleInternal(null, baseName, locale);
    }

    // ---------- ResourceChangeListener ------------------------------------------------

    private static final class ChangeStatus {
        public ResourceResolver resourceResolver;
        public boolean reloadAll = false;
        public final Set<JcrResourceBundle> reloadBundles = new HashSet<>();
    }

    @Override
    public void onChange(final List<ResourceChange> changes) {
        final ChangeStatus status = new ChangeStatus();
        try {
            for (final ResourceChange change : changes) {
                this.onChange(status, change);
                // if we need to reload all, we can skip all other events
                if ( status.reloadAll ) {
                    break;
                }
            }
            if ( status.reloadAll ) {
                this.scheduleReloadBundles(true);
            } else {
                for(final JcrResourceBundle bundle : status.reloadBundles ) {
                    this.scheduleReloadBundle(bundle);
                }
            }
        } catch ( final LoginException le) {
            log.error("Unable to get service resource resolver.", le);
        } finally {
            if ( status.resourceResolver != null ) {
                status.resourceResolver.close();
            }
        }
    }

    private void onChange(final ChangeStatus status, final ResourceChange change)
    throws LoginException {
        log.debug("onChange: Detecting change {} for path '{}'", change.getType(), change.getPath());

        // if this change was on languageRootPath level this might change basename and locale as well, therefore
        // invalidate everything
        if (languageRootPaths.contains(change.getPath())) {
            log.debug(
                    "onChange: Detected change of cached language root '{}', removing all cached ResourceBundles",
                    change.getPath());
            status.reloadAll = true;
        } else {
            for (final String root : languageRootPaths) {
                if (change.getPath().startsWith(root)) {
                    // figure out which JcrResourceBundles from the cached ones is affected
                    for (JcrResourceBundle bundle : resourceBundleCache.values()) {
                        if (bundle.getLanguageRootPaths().contains(root)) {
                            // reload it
                            log.debug("onChange: Resource changes below '{}', reloading ResourceBundle '{}'",
                                    root, bundle);
                            status.reloadBundles.add(bundle);
                        }
                    }
                }
            }

            // may be a completely new dictionary
            if ( status.resourceResolver == null ) {
                status.resourceResolver = createResourceResolver() ;
            }
            if (isDictionaryResource(status.resourceResolver, change)) {
                status.reloadAll = true;
            }
        }
    }


    private boolean isDictionaryResource(final ResourceResolver resolver, final ResourceChange change) {
        // language node changes happen quite frequently (https://issues.apache.org/jira/browse/SLING-2881)
        // therefore only consider changes either for sling:MessageEntry's
        // or for JSON dictionaries
        // get valuemap
        final Resource resource = resolver.getResource(change.getPath());
        if (resource == null) {
            log.trace("Could not get resource for '{}' for event {}", change.getPath(), change.getType());
            return false;
        }
        if ( resource.getResourceType() == null ) {
            return false;
        }
        if (resource.isResourceType(JcrResourceBundle.RT_MESSAGE_ENTRY)) {
            log.debug("Found new dictionary entry: New {} resource in '{}' detected", JcrResourceBundle.RT_MESSAGE_ENTRY, change.getPath());
            return true;
        }
        final ValueMap valueMap = resource.getValueMap();
        // FIXME: derivatives from mix:Message are not detected
        if (hasMixin(valueMap, JcrResourceBundle.MIXIN_MESSAGE)) {
            log.debug("Found new dictionary entry: New {} resource in '{}' detected", JcrResourceBundle.MIXIN_MESSAGE, change.getPath());
            return true;
        }
        if (change.getPath().endsWith(".json")) {
            // check for mixin
            if (hasMixin(valueMap, JcrResourceBundle.MIXIN_LANGUAGE)) {
                log.debug("Found new dictionary: New {} resource in '{}' detected", JcrResourceBundle.MIXIN_LANGUAGE, change.getPath());
                return true;
            }
        }
        return false;
    }

    private boolean hasMixin(ValueMap valueMap, String mixin) {
        final String[] mixins = valueMap.get(JcrResourceBundle.PROP_MIXINS, String[].class);
        if ( mixins != null ) {
            for(final String m : mixins) {
                if (mixin.equals(m) ) {
                    return true;
                }
            }
        }
        return false;
    }

    private void scheduleReloadBundles(final boolean withDelay) {
        // cancel all reload individual bundle jobs!
        synchronized(scheduledJobNames) {
            for (String scheduledJobName : scheduledJobNames) {
                scheduler.unschedule(scheduledJobName);
            }
        }
        scheduledJobNames.clear();
        // defer this job
        final ScheduleOptions options;
        if (withDelay) {
            options = scheduler.AT(new Date(System.currentTimeMillis() + invalidationDelay));
        } else {
            options = scheduler.NOW();
        }
        options.name("ResourceBundleProvider: reload all resource bundles");
        scheduler.schedule(new Runnable() {
            @Override
            public void run() {
                log.info("Reloading all resource bundles");
                clearCache();
                preloadBundles();
            }
        }, options);
    }

    private void scheduleReloadBundle(final JcrResourceBundle bundle) {
        final Key key = new Key(bundle.getBaseName(), bundle.getLocale());

        // defer this job
        ScheduleOptions options = scheduler.AT(new Date(System.currentTimeMillis() + invalidationDelay));
        final String jobName = "ResourceBundleProvider: reload bundle with key " + key.toString();
        scheduledJobNames.add(jobName);
        options.name(jobName);
        scheduler.schedule(new Runnable() {
            @Override
            public void run() {
                reloadBundle(key);
                scheduledJobNames.remove(jobName);
            }
        }, options);
    }

    void reloadBundle(final Key key) {
        // remove bundle from cache
        resourceBundleCache.remove(key);
        log.info("Reloading resource bundle for {}", key);
        // unregister bundle
        ServiceRegistration<ResourceBundle> serviceRegistration = null;
        synchronized (this) {
            serviceRegistration = bundleServiceRegistrations.remove(key);
        }
        if (serviceRegistration != null) {
            serviceRegistration.unregister();
        } else {
            log.warn("Could not find resource bundle service for {}", key);
        }

        Collection<JcrResourceBundle> dependentBundles = new ArrayList<>();
        // this bundle might be a parent of a cached bundle -> invalidate those dependent bundles as well
        for (JcrResourceBundle bundle : resourceBundleCache.values()) {
            if (bundle.getParent() instanceof JcrResourceBundle) {
                JcrResourceBundle parentBundle = (JcrResourceBundle) bundle.getParent();
                Key parentKey = new Key(parentBundle.getBaseName(), parentBundle.getLocale());
                if (parentKey.equals(key)) {
                    log.debug("Also invalidate dependent bundle {} which has bundle {} as parent", bundle, parentBundle);
                    dependentBundles.add(bundle);
                }
            }
        }
        for (JcrResourceBundle dependentBundle : dependentBundles) {
            reloadBundle(new Key(dependentBundle.getBaseName(), dependentBundle.getLocale()));
        }

        if (preloadBundles) {
            // reload the bundle from the repository (will also fill cache and register as a service)
            getResourceBundle(key.baseName, key.locale);
        }
    }

    // ---------- SCR Integration ----------------------------------------------

    /**
     * Activates and configures this component with the repository access
     * details and the default locale to use
     * @throws LoginException
     */
    @Activate
    protected void activate(final BundleContext context, final Config config) throws LoginException {
        final String localeString = config.locale_default();
        this.defaultLocale = toLocale(localeString);
        this.preloadBundles = config.preload_bundles();

        this.bundleContext = context;
        this.invalidationDelay = config.invalidation_delay();
        if (this.resourceResolverFactory != null) { // this is only null during test execution!
            scheduleReloadBundles(false);
        }

    }

    @Deactivate
    protected void deactivate() {
        clearCache();
        this.bundleContext = null;
    }

    // ---------- internal -----------------------------------------------------

    /**
     * Internal implementation of the {@link #getResourceBundle(Locale)} method
     * employing the cache of resource bundles. Creates the bundle if not
     * already cached.
     *
     * @throws MissingResourceException If the resource bundles needs to be
     *             created and the <code>ResourceResolver</code> is not
     *             available to access the resources.
     */
    private ResourceBundle getResourceBundleInternal(ResourceResolver optionalResolver, final String baseName, final Locale locale) {
        final Key key = new Key(baseName, locale);
        JcrResourceBundle resourceBundle = resourceBundleCache.get(key);
        if (resourceBundle != null) {
            log.debug("getResourceBundleInternal({}): got cache hit on first try", key);
        } else {
            if (loadingGuards.get(key) == null) {
                loadingGuards.putIfAbsent(key, new Semaphore(1));
            }
            final Semaphore loadingGuard = loadingGuards.get(key);
            try {
                loadingGuard.acquire();
                resourceBundle = resourceBundleCache.get(key);
                if (resourceBundle != null) {
                    log.debug("getResourceBundleInternal({}): got cache hit on second try", key);
                } else {
                    log.debug("getResourceBundleInternal({}): reading from Repository", key);
                    ResourceResolver localResolver = null;
                    try  {
                        if ( optionalResolver == null ) {
                            localResolver = createResourceResolver();
                            optionalResolver = localResolver;
                        }

                        resourceBundle = createResourceBundle(optionalResolver, key.baseName, key.locale);
                        resourceBundleCache.put(key, resourceBundle);
                        registerResourceBundle(key, resourceBundle);
                    } catch ( final LoginException le) {
                        throw (MissingResourceException)new MissingResourceException("Unable to create service resource resolver",
                                baseName,
                                locale.toString()).initCause(le);
                    } finally {
                        if ( localResolver != null ) {
                            localResolver.close();
                        }
                    }
                }
            } catch (InterruptedException e) {
                Thread.interrupted();
            } finally {
                loadingGuard.release();
            }
        }
        log.trace("getResourceBundleInternal({}) ==> {}", key, resourceBundle);
        return resourceBundle;
    }

    private void registerResourceBundle(Key key, JcrResourceBundle resourceBundle) {
        Dictionary<String, Object> serviceProps = new Hashtable<>();
        if (key.baseName != null) {
            serviceProps.put("baseName", key.baseName);
        }
        serviceProps.put("locale", key.locale.toString());
        ServiceRegistration<ResourceBundle> serviceReg = bundleContext.registerService(ResourceBundle.class,
                resourceBundle, serviceProps);
        synchronized (this) {
            bundleServiceRegistrations.put(key, serviceReg);
        }

        // register language root paths
        final Set<String> languageRoots = resourceBundle.getLanguageRootPaths();
        this.languageRootPaths.addAll(languageRoots);

        log.debug("registerResourceBundle({}, ...): added service registration and language roots {}", key, languageRoots);
        log.info("Currently loaded dictionaries across all locales: {}", languageRootPaths);
    }

    /**
     * Creates the resource bundle for the give locale.
     *
     * @throws MissingResourceException If the <code>ResourceResolver</code>
     *             is not available to access the resources.
     */
    private JcrResourceBundle createResourceBundle(final ResourceResolver resolver, final String baseName, final Locale locale) {
        final JcrResourceBundle bundle = new JcrResourceBundle(locale, baseName, resolver);

        // set parent resource bundle
        Locale parentLocale = getParentLocale(locale);
        if (parentLocale != null) {
            bundle.setParent(getResourceBundleInternal(resolver, baseName, parentLocale));
        } else {
            bundle.setParent(getRootResourceBundle());
        }

        return bundle;
    }

    /**
     * Returns the parent locale of the given locale. The parent locale is the
     * locale of a locale is defined as follows:
     * <ol>
     * <li>If the locale has an variant, the parent locale is the locale with
     * the same language and country without the variant.</li>
     * <li>If the locale has no variant but a country, the parent locale is the
     * locale with the same language but neither country nor variant.</li>
     * <li>If the locale has no country and not variant and whose language is
     * different from the language of the the configured default locale, the
     * parent locale is the configured default locale.</li>
     * <li>Otherwise there is no parent locale and <code>null</code> is
     * returned.</li>
     * </ol>
     */
    private Locale getParentLocale(Locale locale) {
        if (locale.getVariant().length() != 0) {
            return new Locale(locale.getLanguage(), locale.getCountry());
        } else if (locale.getCountry().length() != 0) {
            return new Locale(locale.getLanguage());
        } else if (!locale.getLanguage().equals(defaultLocale.getLanguage())) {
            return defaultLocale;
        }

        // no more parents
        return null;
    }

    /**
     * Returns a ResourceBundle which is used as the root resource bundle, that
     * is the ultimate parent:
     * <ul>
     * <li><code>getLocale()</code> returns Locale("", "", "")</li>
     * <li><code>handleGetObject(String key)</code> returns the <code>key</code></li>
     * <li><code>getKeys()</code> returns an empty enumeration.
     * </ul>
     *
     * @return The root resource bundle
     */
    private ResourceBundle getRootResourceBundle() {
        if (rootResourceBundle == null) {
            rootResourceBundle = new RootResourceBundle();
        }
        return rootResourceBundle;
    }

    private void clearCache() {
        resourceBundleCache.clear();
        languageRootPaths.clear();

        final List<ServiceRegistration<ResourceBundle>> regs;
        synchronized (this) {
            regs = new ArrayList<>(bundleServiceRegistrations.values());
            bundleServiceRegistrations.clear();
        }
        for (final ServiceRegistration<ResourceBundle> serviceReg : regs) {
            serviceReg.unregister();
        }
    }

    private void preloadBundles() {
        if (preloadBundles) {
            try ( final ResourceResolver resolver = createResourceResolver() ) {
                final Iterator<Map<String, Object>> bundles = resolver.queryResources(
                    JcrResourceBundle.QUERY_LANGUAGE_ROOTS, "xpath");
                final Set<Key> usedKeys = new HashSet<>();
                while (bundles.hasNext()) {
                    final Map<String,Object> bundle = bundles.next();
                    if (bundle.containsKey(PROP_LANGUAGE)) {
                        final Locale locale = toLocale(bundle.get(PROP_LANGUAGE).toString());
                        String baseName = null;
                        if (bundle.containsKey(PROP_BASENAME)) {
                            baseName = bundle.get(PROP_BASENAME).toString();
                        }
                        final Key key = new Key(baseName, locale);
                        if (usedKeys.add(key)) {
                            getResourceBundleInternal(resolver, baseName, locale);
                        }
                    }
                }
            } catch ( final LoginException le) {
                log.error("Unable to create service user resource resolver.", le);
            }
        }
    }

    /**
     * Converts the given <code>localeString</code> to a valid
     * <code>java.util.Locale</code>. It must either be in the format specified by
     * {@link Locale#toString()} or in <a href="https://tools.ietf.org/html/bcp47">BCP 47 format</a>
     * If the locale string is <code>null</code> or empty, the platform default locale is assumed. If
     * the localeString matches any locale available per default on the
     * platform, that platform locale is returned. Otherwise the localeString is
     * parsed and the language and country parts are compared against the
     * languages and countries provided by the platform. Any unsupported
     * language or country is replaced by the platform default language and
     * country.
     * @param localeString the locale as string
     * @return the {@link Locale} being generated from the {@code localeString}
     */
    static Locale toLocale(String localeString) {
        if (localeString == null || localeString.length() == 0) {
            return Locale.getDefault();
        }
        // support BCP 47 compliant strings as well (using a different separator "-" instead of "_")
        localeString = localeString.replaceAll("-", "_");

        // check language and country
        final String[] parts = localeString.split("_");
        if (parts.length == 0) {
            return Locale.getDefault();
        }

        // at least language is available
        String lang = parts[0];
        boolean isValidLanguageCode = false;
        String[] langs = Locale.getISOLanguages();
        for (int i = 0; i < langs.length; i++) {
            if (langs[i].equalsIgnoreCase(lang)) {
                isValidLanguageCode = true;
                break;
            }
        }
        if (!isValidLanguageCode) {
            lang = Locale.getDefault().getLanguage();
        }

        // only language
        if (parts.length == 1) {
            return new Locale(lang);
        }

        // country is also available
        String country = parts[1];
        boolean isValidCountryCode = false;
        // allow user-assigned codes (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#User-assigned_code_elements)
        if (USER_ASSIGNED_COUNTRY_CODES_PATTERN.matcher(country.toLowerCase()).matches()) {
            isValidCountryCode = true;
        } else {
            String[] countries = Locale.getISOCountries();
            for (int i = 0; i < countries.length; i++) {
                if (countries[i].equalsIgnoreCase(country)) {
                    isValidCountryCode = true; // signal ok
                    break;
                }
            }
        }
        if (!isValidCountryCode) {
            country = Locale.getDefault().getCountry();
        }

        // language and country
        if (parts.length == 2) {
            return new Locale(lang, country);
        }

        // language, country and variant
        return new Locale(lang, country, parts[2]);
    }

    //---------- internal class

    /**
     * The <code>Key</code> class encapsulates the base name and Locale in a
     * single object that can be used as the key in a <code>HashMap</code>.
     */
    protected static final class Key {

        final String baseName;

        final Locale locale;

        // precomputed hash code, because this will always be used due to
        // this instance being used as a key in a HashMap.
        private final int hashCode;

        Key(final String baseName, final Locale locale) {

            int hc = 0;
            if (baseName != null) {
                hc += 17 * baseName.hashCode();
            }
            if (locale != null) {
                hc += 13 * locale.hashCode();
            }

            this.baseName = baseName;
            this.locale = locale;
            this.hashCode = hc;
        }

        @Override
        public int hashCode() {
            return hashCode;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            } else if (obj instanceof Key) {
                Key other = (Key) obj;
                return equals(this.baseName, other.baseName)
                    && equals(this.locale, other.locale);
            }

            return false;
        }

        private static boolean equals(Object o1, Object o2) {
            if (o1 == null) {
                if (o2 != null) {
                    return false;
                }
            } else if (!o1.equals(o2)) {
                return false;
            }
            return true;
        }

        @Override
        public String toString() {
            return "Key(" + baseName + ", " + locale + ")";
        }
    }
}
