# RuleParameters.java

    package org.thewonderlemming.c4plantuml.linter.rules;

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

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    /**
     * A container for settings to control the behavior of a {@link AbstractLintingRule}.
     *
     * @author thewonderlemming
     *
     */
    public class RuleParameters {

        /**
         * A part of the {@link RuleParameters} builder.
         *
         * @author thewonderlemming
         *
         */
        public static interface AddParameter {

            /**
             * Creates a new parameter and adds it to the current parameters list in the builder.
             * <p>
             * It another parameter exists with the same name, then its value will be replaced with the new one.
             *
             * @param name the name of the new parameter.
             * @param value the value of the new parameter.
             * @return the current instance of {@link AddParameter} to allow method chaining.
             */
            AddParameter addParameter(final String name, final String value);

            /**
             * Creates a collection parameters and adds them to the current parameters list in the builder.
             * <p>
             * It another parameter exists with the same name as one of the new parameters, then its value will be replaced
             * with the new value.
             *
             * @param values a {@link Map} of parameters to create and to add to the new instance.
             * @return the current instance of {@link AddParameter} to allow method chaining.
             */
            default AddParameter addParameters(final Map<String, String> values) {

                if (null != values) {
                    values.forEach(this::addParameter);
                }

                return this;
            }

            /**
             * Builds the new {@link RuleParameters} instance and returns it.
             *
             * @return the newly built instance.
             */
            RuleParameters build();
        }

        private static final Logger LOGGER = LoggerFactory.getLogger(RuleParameters.class);

        private final Map<String, String> parameters = new HashMap<>();

        /**
         * Returns a fluent builder instance to the {@link RuleParameters} class.
         *
         * @return a new builder instance for {@link RuleParameters}.
         */
        public static AddParameter builder() {

            return new AddParameter() {

                private final Map<String, String> parameters = new HashMap<>();

                @Override
                public AddParameter addParameter(final String name, final String value) {

                    this.parameters.put(name, value);
                    return this;
                }

                @Override
                public RuleParameters build() {
                    return new RuleParameters(parameters);
                }
            };
        }

        private RuleParameters(final Map<String, String> parameters) {
            this.parameters.putAll(parameters);
        }

        /**
         * Retrieves a parameter value by its name.
         *
         * @param parameterName the name of the parameter to retrieve value from.
         * @return an {@link Optional} of the value if found, or empty else.
         */
        public Optional<String> getParameter(final String parameterName) {
            return Optional.ofNullable(this.parameters.get(parameterName));
        }

        /**
         * Retrieves a {@link Boolean} parameter value by its name.
         *
         * @param parameterName parameterName the name of the parameter to retrieve value from.
         * @return an {@link Optional} of the value if found, or empty else.
         */
        public Optional<Boolean> getParameterAsBoolean(final String parameterName) {

            return this.getParameterAsType(parameterName, Boolean.class, value -> {

                if (!value.equalsIgnoreCase("true") && !value.equalsIgnoreCase("false")) {

                    LOGGER.error("Error while parsing parameter {} as boolean: got {}", parameterName, value);
                    return Optional.empty();
                }

                return Optional.ofNullable(Boolean.valueOf(value));
            });
        }

        /**
         * Retrieves an {@link Integer} parameter value by its name.
         *
         * @param parameterName parameterName the name of the parameter to retrieve value from.
         * @return an {@link Optional} of the value if found, or empty else.
         */
        public Optional<Integer> getParameterAsInteger(final String parameterName) {

            return this.getParameterAsType(parameterName, Integer.class, value -> {

                try {

                    final Integer valueAsInt = Integer.parseInt(value);
                    return Optional.ofNullable(valueAsInt);

                } catch (final NumberFormatException e) {
                    LOGGER.error("Error while parsing parameter {} as integer: {}", parameterName, e.getMessage(), e);
                }

                return Optional.empty();
            });
        }

        /**
         * Retrieves a {@link Long} parameter value by its name.
         *
         * @param parameterName parameterName the name of the parameter to retrieve value from.
         * @return an {@link Optional} of the value if found, or empty else.
         */
        public Optional<Long> getParameterAsLong(final String parameterName) {

            return this.getParameterAsType(parameterName, Long.class, value -> {

                try {

                    final Long valueAsLong = Long.parseLong(value);
                    return Optional.ofNullable(valueAsLong);

                } catch (final NumberFormatException e) {
                    LOGGER.error("Error while parsing parameter {} as long: {}", parameterName, e.getMessage(), e);
                }

                return Optional.empty();
            });
        }

        /**
         * Retrieves a parameter value by its name and casts it to the given type {@code <T>}.
         *
         * @param parameterName parameterName the name of the parameter to retrieve value from.
         * @param typeClass the type to which you want to cast the value to.
         * @param typeConverter the converter function used to cast the parameter value.
         * @param <T> the type to which you want to cast the value.
         * @return an {@link Optional} of the value if found, or empty else.
         */
        public <T> Optional<T> getParameterAsType(final String parameterName, final Class<T> typeClass,
            final Function<String, Optional<T>> typeConverter) {

            final Optional<String> valueAsString = this.getParameter(parameterName);
            return valueAsString.isPresent() ? typeConverter.apply(valueAsString.get()) : Optional.empty();
        }
    }