/* UtilLib - Copyright (c) 2008-2023 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.localisation;

import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import net.mapeadores.util.text.StringUtils;


/**
 *
 * @author Vincent Calame
 */
public class BundleMessageLocalisation implements MessageLocalisation {

    private final static ConcurrentMap<CacheKey, BundleMessageLocalisation> localisationMap = new ConcurrentHashMap<CacheKey, BundleMessageLocalisation>();
    private final ResourceBundle resourceBundle;

    private BundleMessageLocalisation(ResourceBundle resourceBundle) {
        this.resourceBundle = resourceBundle;
    }

    @Override
    public String toString(String messageKey) {
        if (messageKey.isEmpty()) {
            return "";
        }
        try {
            messageKey = LocalisationUtils.cleanMessageKey(messageKey);
            return resourceBundle.getString(messageKey);
        } catch (MissingResourceException mre) {
            return null;
        }
    }

    @Override
    public String toString(Message message) {
        String messageKey = message.getMessageKey();
        if (messageKey.isEmpty()) {
            return LocalisationUtils.joinValues(message);
        }
        try {
            String messageString = resourceBundle.getString(LocalisationUtils.cleanMessageKey(messageKey));
            return StringUtils.formatMessage(messageString, message.getMessageValues(), resourceBundle.getLocale());
        } catch (MissingResourceException mre) {
            return null;
        } catch (StringUtils.FormatException fe) {
            return "[" + messageKey + "] " + fe.getMessage();
        }
    }

    @Override
    public boolean containsKey(String messageKey) {
        try {
            messageKey = LocalisationUtils.cleanMessageKey(messageKey);
            resourceBundle.getString(messageKey);
            return true;
        } catch (MissingResourceException mre) {
            return false;
        }
    }

    public ResourceBundle getResourceBundle() {
        return resourceBundle;
    }

    public static BundleMessageLocalisation getInstance(String baseName, Locale locale, ClassLoader classLoader) {
        CacheKey cacheKey = new CacheKey(baseName, locale);
        BundleMessageLocalisation messageLocalisation = localisationMap.get(cacheKey);
        if (messageLocalisation == null) {
            ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName, locale, classLoader);
            messageLocalisation = new BundleMessageLocalisation(resourceBundle);
            localisationMap.put(cacheKey, messageLocalisation);
        }
        return messageLocalisation;
    }


    private static final class CacheKey {

        private final String name;
        private final Locale locale;
        private int hashCodeCache;

        private CacheKey(String baseName, Locale locale) {
            this.name = baseName;
            this.locale = locale;
            calculateHashCode();
        }

        @Override
        public boolean equals(Object other) {
            if (other == null) {
                return false;
            }
            if (this == other) {
                return true;
            }
            if (this.getClass() != other.getClass()) {
                return false;
            }
            CacheKey otherEntry = (CacheKey) other;
            if (hashCodeCache != otherEntry.hashCodeCache) {
                return false;
            }
            if (!name.equals(otherEntry.name)) {
                return false;
            }
            if (!locale.equals(otherEntry.locale)) {
                return false;
            }
            return true;
        }

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

        @Override
        public String toString() {
            String l = locale.toString();
            if (l.length() == 0) {
                if (locale.getVariant().length() != 0) {
                    l = "__" + locale.getVariant();
                } else {
                    l = "\"\"";
                }
            }
            return "CacheKey[" + name + ", lc=" + l + "]";
        }

        private void calculateHashCode() {
            hashCodeCache = name.hashCode() << 3;
            hashCodeCache ^= locale.hashCode();
        }

    }

}
