<commit_before>/*
 * Copyright 2014 <NAME>
 *
 *    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 io.github.aritzhack.aritzh;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import io.github.aritzhack.aritzh.logging.ILogger;
import io.github.aritzhack.aritzh.logging.SLF4JLogger;

import java.io.*;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Kind of {@link java.util.Properties}, but with category names, and returning {@link String}, not
 * {@link Object}
 *
 * @author <NAME>
 */
@SuppressWarnings({"UnusedDeclaration", "JavaDoc"})
public class Configuration {

    public static final Pattern CATEGORY_REGEX = Pattern.compile("^\\s*\\[(?:\\s*(?=\\w+))(.+)\\s*\\]\\s*$");// Category is trimmed, but keeps spaces in between
    public static final Pattern PROP_REGEX = Pattern.compile("^\\s*(\\w+)\\s*=(?:\\s*(?=\\w+))(.*)\\s*$");
    public static final Pattern SKIP_REGEX = Pattern.compile("(^\\s*$)|(^\\s*#.*$)"); // Empty line, or: Spaces or not, followed by # and followed by anything
    public static final ILogger logger = new SLF4JLogger(Configuration.class);

    private final File configFile;
    private final boolean compressedSpaces;
    private final Map<String, LinkedHashMap<String, String>> categories = Maps.newLinkedHashMap();

    private Configuration(File configFile, boolean compressedSpaces) {
        this.configFile = configFile;
        this.compressedSpaces = compressedSpaces;
    }

    /**
     * Loads the configuration file <br>
     * If the config file did not exist, it will be created
     * <p>
     * Equivalent to calling {@code Configuration.loadConfig(configFile, false)}
     *
     * @param configFile File to read the configuration from
     * @return A new configuration object, already parsed from {@code configFile}
     * @see Configuration#loadConfig(java.io.File, boolean)
     */
    public static Configuration loadConfig(File configFile) {
        return Configuration.loadConfig(configFile, false);
    }

    /**
     * Loads the configuration file, specifying if spaces should be compressed or not ({@code currentLine.replaceAll("\\s+", " ")})
     * If the config file did not exist, it will be created
     * Equivalent to calling {@code Configuration.loadConfig(configFile, compressedSpaces, false)}
     *
     * @param configFile       File to read the configuration from
     * @param compressedSpaces If true subsequent whitespaces will be replaced with a single one (defaults to false)
     * @return A new configuration object, already parsed, from {@code configFile}
     * @see Configuration#loadConfig(java.io.File, boolean, boolean)
     */
    public static Configuration loadConfig(File configFile, boolean compressedSpaces) {
        return Configuration.loadConfig(configFile, compressedSpaces, false);
    }

    /**
     * Loads the configuration file, specifying if spaces should be compressed or not ({@code currentLine.replaceAll("\\s+", " ")})
     * If the config file did not exist, it will be created
     *
     * @param configFile     File to read the configuration from
     * @param compressSpaces If true subsequent whitespaces will be replaced with a single one (defaults to {@code false})
     * @param verbose        Whether to log unrecognized lines or not (defaults to {@code false})
     * @return A new configuration object, already parsed, from {@code configFile}
     */
    public static Configuration loadConfig(File configFile, boolean compressSpaces, boolean verbose) {
        if (!configFile.exists()) {
            return Configuration.newConfig(configFile);
        }
        Configuration config = new Configuration(configFile, compressSpaces);
        String currentLine;

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(configFile)))) {

            String currentCategory = "";

            while ((currentLine = reader.readLine()) != null) {
                currentLine = compressSpaces ? currentLine.replaceAll("\\s+", " ").trim() : currentLine;

                Matcher m;

                if ((SKIP_REGEX.matcher(currentLine)).matches()) {
                  // Do nothing
                } else if ((m = CATEGORY_REGEX.matcher(currentLine)).matches()) {
                    currentCategory = config.addCategory(m);
                } else if ((m = PROP_REGEX.matcher(currentLine)).matches()) {
                    config.addProperty(m, currentCategory);
                } else if (verbose) {
                    Configuration.logger.d("Unknown-line: {}", currentLine);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return config;
    }

    /**
     * Creates a new empty configuration object for the specified file<commit_msg>* Extracted method that reads a config from a BufferedReader, so that it can be used with Paths too<commit_after>/*
 * Copyright 2014 <NAME>
 *
 *    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 io.github.aritzhack.aritzh;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import io.github.aritzhack.aritzh.logging.ILogger;
import io.github.aritzhack.aritzh.logging.SLF4JLogger;

import java.io.*;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Kind of {@link java.util.Properties}, but with category names, and returning {@link String}, not
 * {@link Object}
 *
 * @author <NAME>
 */
@SuppressWarnings({"UnusedDeclaration", "JavaDoc"})
public class Configuration {

    public static final Pattern CATEGORY_REGEX = Pattern.compile("^\\s*\\[(?:\\s*(?=\\w+))(.+)\\s*\\]\\s*$");// Category is trimmed, but keeps spaces in between
    public static final Pattern PROP_REGEX = Pattern.compile("^\\s*(\\w+)\\s*=(?:\\s*(?=\\w+))(.*)\\s*$");
    public static final Pattern SKIP_REGEX = Pattern.compile("(^\\s*$)|(^\\s*#.*$)"); // Empty line, or: Spaces or not, followed by # and followed by anything
    public static final ILogger logger = new SLF4JLogger(Configuration.class);

    private final File configFile;
    private final boolean compressedSpaces;
    private final Map<String, LinkedHashMap<String, String>> categories = Maps.newLinkedHashMap();

    private Configuration(File configFile, boolean compressedSpaces) {
        this.configFile = configFile;
        this.compressedSpaces = compressedSpaces;
    }

    /**
     * Loads the configuration file <br>
     * If the config file did not exist, it will be created
     * <p/>
     * Equivalent to calling {@code Configuration.loadConfig(configFile, false)}
     *
     * @param configFile File to read the configuration from
     * @return A new configuration object, already parsed from {@code configFile}
     * @see Configuration#loadConfig(java.io.File, boolean)
     */
    public static Configuration loadConfig(File configFile) {
        return Configuration.loadConfig(configFile, false);
    }

    /**
     * Loads the configuration file, specifying if spaces should be compressed or not ({@code currentLine.replaceAll("\\s+", " ")})
     * If the config file did not exist, it will be created
     * Equivalent to calling {@code Configuration.loadConfig(configFile, compressedSpaces, false)}
     *
     * @param configFile       File to read the configuration from
     * @param compressedSpaces If true subsequent whitespaces will be replaced with a single one (defaults to false)
     * @return A new configuration object, already parsed, from {@code configFile}
     * @see Configuration#loadConfig(java.io.File, boolean, boolean)
     */
    public static Configuration loadConfig(File configFile, boolean compressedSpaces) {
        return Configuration.loadConfig(configFile, compressedSpaces, false);
    }

    /**
     * Loads the configuration file, specifying if spaces should be compressed or not ({@code currentLine.replaceAll("\\s+", " ")})
     * If the config file did not exist, it will be created
     *
     * @param configFile     File to read the configuration from
     * @param compressSpaces If true subsequent whitespaces will be replaced with a single one (defaults to {@code false})
     * @param verbose        Whether to log unrecognized lines or not (defaults to {@code false})
     * @return A new configuration object, already parsed, from {@code configFile}
     */
    public static Configuration loadConfig(File configFile, boolean compressSpaces, boolean verbose) {
        if (!configFile.exists()) {
            return Configuration.newConfig(configFile);
        }

        Configuration config = new Configuration(configFile, compressSpaces);

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(configFile)))) {
            loadConfig(config, reader, compressSpaces, verbose);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return config;
    }

    public static Configuration loadConfig(final Configuration config, final BufferedReader reader, final boolean compressSpaces, final boolean verbose) {
        reader.lines().sequential().forEachOrdered(new Consumer<String>() {
            String currentCategory = "";

            @Override
            public void accept(String line) {
                line = compressSpaces ? line.replaceAll("\\s+", " ").trim() : line;

                Matcher m;

                if ((SKIP_REGEX.matcher(line)).matches()) {
                    // Do nothing
                } else if ((m = CATEGORY_REGEX.matcher(line)).matches()) {
                    currentCategory = config.addCategory(m);
                } else if ((m = PROP_REGEX.matcher(line)).matches()) {
                    config.addProperty(m, currentCategory);
                } else if (verbose) {
                    Configuration.logger.d("Unknown-line: {}", line);
                }
            }
        });
    }

    /**
     * Creates a new empty configuration object for the specified file
{'fraction_non_alphanumeric': 0.10736007051564565, 'fraction_numerical': 0.0017628911414720142, 'mean_word_length': 3.0148619957537157, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 16, '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': '983368', 'n_tokens_mistral': 3021, 'n_tokens_neox': 2927, 'n_words': 999}