BasqueTimeZoneNameProvider.java

package dev.orne.i18n.spi.eu;

/*-
 * #%L
 * basque-locale-extension
 * %%
 * Copyright (C) 2024 - 2025 Orne Developments
 * %%
 * This program 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 3 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormatSymbols;
import java.time.ZoneId;
import java.time.zone.ZoneRulesException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.spi.TimeZoneNameProvider;

import javax.validation.constraints.NotNull;

/**
 * Basque time zone name provider.
 * 
 * @author <a href="https://github.com/ihernaez">(w) Iker Hernaez</a>
 * @version 1.0, 2024-10
 * @since 1.0
 */
public class BasqueTimeZoneNameProvider
extends TimeZoneNameProvider {

    /** The logger of the class. */
    private static final Logger LOG = Logger.getLogger(BasqueTimeZoneNameProvider.class.getName());

    /** Time zone standard name property suffix. */
    static final String STANDARD_SUFFIX = ".std";
    /** Time zone daylight saving time name property suffix. */
    static final String DAYLIGHT_SUFFIX = ".dst";
    /** Time zone long name property suffix. */
    static final String LONG_SUFFIX = ".long";

    /** The time zone names in {@code DateFormatSymbols} format. */
    private static String[][] names;
    /** The time zone aliases. */
    private final HashMap<String, String> aliases = new HashMap<>();
    /** The time zone names by zone ID. */
    private final HashMap<String, String[]> index = new HashMap<>();

    /**
     * Creates a new instance.
     */
    public BasqueTimeZoneNameProvider() {
        super();
        for (final String[] zone : getNames()) {
            index.put(zone[0], zone);
        }
        aliases.put("GMT0", "GMT");
        aliases.put("Etc/GMT0", "GMT");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getDisplayName(
            final @NotNull String id,
            final boolean daylight,
            final int style,
            final @NotNull Locale locale) {
        final String[] zone = getNames(id);
        if (zone == null) {
            return null;
        }
        if (daylight) {
            if (style == TimeZone.LONG) {
                return zone[3];
            } else {
                return zone[4];
            }
        } else {
            if (style == TimeZone.LONG) {
                return zone[1];
            } else {
                return zone[2];
            }
        }
    }

    @Override
    public String getGenericDisplayName(
            final String id,
            final int style,
            final Locale locale) {
        final String[] zone = getNames(id);
        if (zone == null || zone.length < 7) {
            return null;
        }
        if (style == TimeZone.LONG) {
            return zone[5];
        } else {
            return zone[6];
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public @NotNull Locale[] getAvailableLocales() {
        return BasqueLocaleServiceProvider.LOCALES;
    }

    /**
     * Returns The time zone names in {@code DateFormatSymbols} format.
     * 
     * @return The time zone names in {@code DateFormatSymbols} format.
     * @see DateFormatSymbols#getZoneStrings()
     */
    static synchronized @NotNull String[][] getNames() {
        if (names == null) {
            final Properties translations = new Properties();
            try (InputStream is = BasqueLocaleNameProvider.class.getResourceAsStream("timezones.properties")) {
                translations.load(is);
            } catch (final IOException e) {
                LOG.log(Level.SEVERE, "Error loading basque time zones names", e);
            }
            names = ((DateFormatSymbols) DateFormatSymbols.getInstance(Locale.ENGLISH).clone())
                    .getZoneStrings();
            for (int i = 0; i < names.length; i++) {
                final String[] zone = names[i];
                zone[1] = translations.getProperty(zone[0] + STANDARD_SUFFIX + LONG_SUFFIX, zone[1]);
                zone[2] = translations.getProperty(zone[0] + STANDARD_SUFFIX, zone[2]);
                zone[3] = translations.getProperty(zone[0] + DAYLIGHT_SUFFIX + LONG_SUFFIX, zone[3]);
                zone[4] = translations.getProperty(zone[0] + DAYLIGHT_SUFFIX, zone[4]);
                if (zone.length > 5) {
                    zone[5] = translations.getProperty(zone[0] + LONG_SUFFIX, zone[5]);
                }
                if (zone.length > 6) {
                    zone[6] = translations.getProperty(zone[0], zone[6]);
                }
            }
        }
        return names;
    }

    /**
     * Retrieves the time zone names for the specified ID, trying 
     * 
     * @param id The time zone ID.
     * @return The time zone names in {@code DateFormatSymbols} format, if found.
     */
    private String[] getNames(
            final @NotNull String id) {
        String[] zone = this.index.get(this.aliases.getOrDefault(id, id));
        if (zone == null) {
            try {
                zone = this.index.get(ZoneId.of(id).normalized().getId());
            } catch (final ZoneRulesException ignore) {
                // Ignore
            }
        }
        return zone;
    }
}