/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2021 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed 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.jboss.installer.core.i18n;

import org.jboss.installer.core.LanguageUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Provides operations to access translated text for Installer.
 *
 */
public class DefaultLanguageUtils implements LanguageUtils {

    private ResourceBundle bundle;

    private DefaultLanguageUtils(ResourceBundle bundle) {
        this.bundle = bundle;
    }

    public static DefaultLanguageUtils.Builder builder() {
        return new Builder();
    }

    @Override
    public String getString(String key) {
        String message = bundle.getString(key);
        Pattern expr = Pattern.compile("(\\$\\{[^\\$]*\\})");
        Matcher matcher = expr.matcher(message);

        if (!matcher.find()) {
            return message;
        }

        List<String> expressions = new ArrayList<>();
        String replaced = matcher.replaceAll(match -> {
            expressions.add(match.group(1));
            return "%s";
        });

        return evaluate(replaced, expressions.toArray(new String[0]));
    }

    @Override
    public String getString(String key, String... params) {
        return evaluate(getString(key), params);
    }

    private String evaluate(String message, String... params) {
        String[] evaluated = evaluateParams(params);
        return String.format(message, evaluated);
    }

    private String[] evaluateParams(String[] params) {
        String[] result = new String[params.length];
        for (int i = 0; i < params.length; i++) {
            String param = params[i];
            if (param.startsWith("${") && param.endsWith("}") && param.length() > 3) {
                try {
                    result[i] = getString(param.substring(2, param.length() - 1));
                } catch (MissingResourceException e) {
                    result[i] = param;
                }
            } else {
                result[i] = param;
            }
        }
        return result;
    }

    @Override
    public boolean hasString(String key) {
        return bundle.containsKey(key);
    }

    @Override
    public Locale getLocale() {
        return bundle.getLocale();
    }

    public static class Builder {
        private Locale locale;
        /**
         * loads translations for given locale. Throws {@code IllegalStateException} if called multiple times.
         *
         * @param locale
         */
        public Builder setLocale(Locale locale) {
            this.locale = locale;
            return this;
        }

        public LanguageUtils build() {
            ResourceBundle bundle = ResourceBundle.getBundle(I18N_BUNDLE, locale);
            return new DefaultLanguageUtils(bundle);
        }
    }
}
