<commit_before>/**
 * Copyright (c) 2014-2017 by the respective copyright holders.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.eclipse.smarthome.config.core;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.smarthome.config.core.ConfigDescriptionParameter.Type;
import org.eclipse.smarthome.config.core.normalization.Normalizer;
import org.eclipse.smarthome.config.core.normalization.NormalizerFactory;
import org.eclipse.smarthome.config.core.validation.ConfigDescriptionValidator;

/**
 * This class provides some useful static methods for handling configurations
 *
 * @author <NAME> - Initial API and implementation
 * @author <NAME> - Minor changes for type normalization based on config description
 */
public class ConfigUtil {

    /**
     * normalizes the types to the ones allowed for configurations
     *
     * @param configuration
     * @return normalized configuration
     */
    public static Map<String, Object> normalizeTypes(Map<String, Object> configuration) {
        Map<String, Object> convertedConfiguration = new HashMap<String, Object>(configuration.size());
        for (Entry<String, Object> parameter : configuration.entrySet()) {
            String name = parameter.getKey();
            Object value = parameter.getValue();
            convertedConfiguration.put(name, normalizeType(value));
        }
        return convertedConfiguration;
    }

    /**
     * normalizes the type of the parameter to the one allowed for configurations
     *
     * @param value the value to return as normalized type
     *
     * @return corresponding value as a valid type
     */
    public static Object normalizeType(Object value) {
        return normalizeType(value, null);
    }

    /**
     * normalizes the type of the parameter to the one allowed for configurations
     *
     * @param value the value to return as normalized type
     *
     * @return corresponding value as a valid type
     */
    public static Object normalizeType(Object value, ConfigDescriptionParameter configDescriptionParameter) {
        if (configDescriptionParameter != null) {
            Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter);
            return normalizer.normalize(value);
        } else if (value == null || value instanceof Boolean || value instanceof String
                || value instanceof BigDecimal) {
            return value;
        } else if (value instanceof Number) {
            return new BigDecimal(value.toString());
        } else if (value instanceof Collection) {
            return normalizeCollection((Collection) value);
        }
        throw new IllegalArgumentException(
                "Invalid type '{" + value.getClass().getCanonicalName() + "}' of configuration value!");
    }

    private static Collection normalizeCollection(Collection collection) {
        if (collection.size() != 0) {
            List list = new ArrayList(collection);
            Type type = getType(list.get(0));
            for (ListIterator it = list.listIterator(); it.hasNext();) {
                Object value = it.next();
                Type valueType = getType(value);
                if (type != valueType) {
                    throw new IllegalArgumentException(
                            "Invalid configuration property. Heterogeneous collection value!");
                } else {
                    if (valueType == Type.DECIMAL && !(value instanceof BigDecimal)) {
                        it.set((new BigDecimal(value.toString())));
                    }
                }
            }
            return list;
        }
        return collection;
    }

    private static Type getType(Object value) {
        if (value instanceof String) {
            return Type.TEXT;
        } else if (value instanceof Boolean) {
            return Type.BOOLEAN;
        } else if (value instanceof Number) {
            return Type.DECIMAL;
        }
        throw new IllegalArgumentException(
                "Invalid type '{" + value.getClass().getCanonicalName() + "}' of configuration value!");
    }

    /**
     * Normalizes the given configuration according to the given config descriptions.
     *
     * By doing so, it tries to convert types on a best-effort basis. The result will contain
     * BigDecimals, Strings and Booleans wherever a conversion of similar types was possible.
     *
     * However, it does not check for general correctness of types. This can be done using the
     * {@link ConfigDescriptionValidator}.<commit_msg>small fixes normalization in ConfigUtils (#3292)<commit_after>/**
 * Copyright (c) 2014-2017 by the respective copyright holders.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.eclipse.smarthome.config.core;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.smarthome.config.core.normalization.Normalizer;
import org.eclipse.smarthome.config.core.normalization.NormalizerFactory;
import org.eclipse.smarthome.config.core.validation.ConfigDescriptionValidator;

/**
 * This class provides some useful static methods for handling configurations
 *
 * @author <NAME> - Initial API and implementation
 * @author <NAME> - Minor changes for type normalization based on config description
 */
public class ConfigUtil {

    /**
     * Normalizes the types to the ones allowed for configurations.
     *
     * @param configuration
     * @return normalized configuration
     */
    public static Map<String, Object> normalizeTypes(Map<String, Object> configuration) {
        Map<String, Object> convertedConfiguration = new HashMap<String, Object>(configuration.size());
        for (Entry<String, Object> parameter : configuration.entrySet()) {
            String name = parameter.getKey();
            Object value = parameter.getValue();
            convertedConfiguration.put(name, normalizeType(value));
        }
        return convertedConfiguration;
    }

    /**
     * Normalizes the type of the parameter to the one allowed for configurations.
     *
     * @param value the value to return as normalized type
     * @return corresponding value as a valid type
     */
    public static Object normalizeType(Object value) {
        return normalizeType(value, null);
    }

    /**
     * Normalizes the type of the parameter to the one allowed for configurations.
     *
     * @param value the value to return as normalized type
     * @return corresponding value as a valid type
     * @throws IllegalArgumentException if a invalid type has been given
     */
    public static Object normalizeType(Object value, ConfigDescriptionParameter configDescriptionParameter) {
        if (configDescriptionParameter != null) {
            Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter);
            return normalizer.normalize(value);
        } else if (value == null || value instanceof Boolean || value instanceof String
                || value instanceof BigDecimal) {
            return value;
        } else if (value instanceof Number) {
            return new BigDecimal(value.toString());
        } else if (value instanceof Collection) {
            return normalizeCollection((Collection<?>) value);
        }
        throw new IllegalArgumentException(
                "Invalid type '{" + value.getClass().getCanonicalName() + "}' of configuration value!");
    }

    /**
     * Normalizes a collection.
     *
     * @param collection the collection that entries should be normalized
     * @return a collection that contains the normalized entries
     * @throws IllegalArgumentException if the type of the normalized values differ or an invalid type has been given
     */
    private static Collection<Object> normalizeCollection(Collection<?> collection) throws IllegalArgumentException {
        if (collection.size() == 0) {
            return Collections.emptyList();
        } else {
            final List<Object> lst = new ArrayList<>(collection.size());
            for (final Object it : collection) {
                final Object normalized = normalizeType(it);
                lst.add(normalized);
                if (normalized.getClass() != lst.get(0).getClass()) {
                    throw new IllegalArgumentException(
                            "Invalid configuration property. Heterogeneous collection value!");
                }
            }
            return lst;
        }
    }

    /**
     * Normalizes the given configuration according to the given config descriptions.
     *
     * By doing so, it tries to convert types on a best-effort basis. The result will contain
     * BigDecimals, Strings and Booleans wherever a conversion of similar types was possible.
     *
     * However, it does not check for general correctness of types. This can be done using the
     * {@link ConfigDescriptionValidator}.
{'fraction_non_alphanumeric': 0.08335928578843559, 'fraction_numerical': 0.003321914253088342, 'mean_word_length': 2.7039600153787005, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3027022', 'n_tokens_mistral': 2276, 'n_tokens_neox': 2206, 'n_words': 799}