package ctbrec.variableexpansion;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;

abstract class AbstractVariableExpander {

    protected Map<String, Function<String, Optional<String>>> placeholderValueSuppliers = new HashMap<>();

    protected String fillInPlaceHolders(String input, Map<String, Function<String, Optional<String>>> placeholderValueSuppliers) {
        boolean somethingReplaced = false;
        do {
            somethingReplaced = false;
            int end = input.indexOf("}");
            if (end > 0) {
                int start = input.substring(0, end).lastIndexOf("${");
                if (start >= 0) {
                    String placeholder = input.substring(start, end + 1);
                    String placeholderName = placeholder.substring(2, placeholder.length() - 1);
                    String defaultValue = null;
                    String expression = null;
                    int questionMark = placeholder.indexOf('?');
                    if (questionMark > 0) {
                        placeholderName = placeholder.substring(2, questionMark);
                        defaultValue = placeholder.substring(questionMark + 1, placeholder.length() - 1);
                    } else {
                        defaultValue = "";
                    }
                    int bracket = placeholder.indexOf('(');
                    if (bracket > 0) {
                        placeholderName = placeholder.substring(2, bracket);
                        expression = placeholder.substring(bracket + 1, placeholder.indexOf(')', bracket));
                    }

                    final String name = placeholderName;
                    Optional<String> optionalValue = placeholderValueSuppliers.getOrDefault(name, r -> Optional.of(name)).apply(expression);
                    String value = optionalValue.orElse(defaultValue);
                    StringBuilder sb = new StringBuilder(input);
                    String output = sb.replace(start, end+1, value).toString();
                    somethingReplaced = !Objects.equals(input, output);
                    input = output;
                }
            }
        } while (somethingReplaced);
        return input;
    }

    public Set<String> getPlaceholderNames() {
        return placeholderValueSuppliers.keySet();
    }

    public Map<String, Function<String, Optional<String>>> getPlaceholderValueSuppliers() {
        return placeholderValueSuppliers;
    }
}
