<commit_before>/*
 * Copyright 2016 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * 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 net.petrovicky.zonkybot.app;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Properties;

import net.petrovicky.zonkybot.Operations;
import net.petrovicky.zonkybot.OperationsContext;
import net.petrovicky.zonkybot.remote.Investment;
import net.petrovicky.zonkybot.strategy.InvestmentStrategy;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ZonkyBot {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZonkyBot.class);
    protected static final String ZONKY_VERSION_UNDETECTED = "UNDETECTED";
    protected static final String ZONKY_VERSION_UNKNOWN = "UNKNOWN";

    private static final Option OPTION_STRATEGY = Option.builder("s").hasArg().longOpt("strategy")
            .argName("Investment strategy").desc("Points to a file that holds the investment strategy configuration.")
            .build();
    private static final Option OPTION_USERNAME = Option.builder("u").hasArg().longOpt("username")
            .argName("Zonky username").desc("Used to connect to the Zonky server.").build();
    private static final Option OPTION_PASSWORD = Option.builder("p").hasArg().longOpt("password")
            .argName("Zonky password").desc("Used to connect to the Zonky server.").build();
    private static final Option OPTION_DRY_RUN = Option.builder("d").hasArg().optionalArg(true).
            argName("Dry run balance").longOpt("dry").desc("Simulate the investments, but never actually spend money.")
            .build();
    private static final Option OPTION_HELP = Option.builder("h").longOpt("help").argName("Show help")
            .desc("Show this help message and quit.").build();

    protected static String getZonkyBotVersion() {
        try {
            final URLClassLoader cl = (URLClassLoader) ZonkyBot.class.getClassLoader();
            final URL url = cl.findResource("META-INF/maven/net.petrovicky.zonkybot/zonkybot-app/pom.properties");
            final Properties props = new Properties();
            props.load(url.openStream());
            return props.getProperty("version", ZonkyBot.ZONKY_VERSION_UNKNOWN);
        } catch (Exception ex) {
            return ZonkyBot.ZONKY_VERSION_UNDETECTED;
        }
    }

    private static void printHelpAndExit(final Options options, final String message, final boolean exitWithError) {
        final HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("ZonkyBot", null, options, exitWithError ? "Error: " + message : message, true);
        System.exit(exitWithError ? 1 : 0);
    }

    public static void main(final String... args) {
        LOGGER.info("ZonkyBot v{} loading.", ZonkyBot.getZonkyBotVersion());
        final OptionGroup og = new OptionGroup();
        og.setRequired(true);
        og.addOption(ZonkyBot.OPTION_HELP);
        og.addOption(ZonkyBot.OPTION_STRATEGY);
        final Options options = new Options();
        options.addOptionGroup(og);
        options.addOption(ZonkyBot.OPTION_DRY_RUN);
        options.addOption(ZonkyBot.OPTION_PASSWORD);
        options.addOption(ZonkyBot.OPTION_USERNAME);

        final CommandLineParser parser = new DefaultParser();
        CommandLine cmd = null;
        try {
            cmd = parser.parse(options, args);
        } catch (final Exception ex) { // for some reason, the CLI could not be parsed
            ZonkyBot.printHelpAndExit(options, ex.getMessage(), true);
        }
        if (cmd.hasOption(ZonkyBot.OPTION_HELP.getOpt())) { // user requested help
            ZonkyBot.printHelpAndExit(options, "", false);
        }
        // standard workflow
        if (!cmd.hasOption(ZonkyBot.OPTION_USERNAME.getOpt())) {
            ZonkyBot.printHelpAndExit(options, "Username must be provided.", true);
        } else if (!cmd.hasOption(ZonkyBot.OPTION_PASSWORD.getOpt())) {
            ZonkyBot.printHelpAndExit(options, "Password must be provided.", true);
        }
        final File strategyConfig = new File(cmd.getOptionValue(ZonkyBot.OPTION_STRATEGY.getOpt()));
        if (!strategyConfig.canRead()) {
            ZonkyBot.printHelpAndExit(options, "Investment strategy file must be readable.", true);
        }
        InvestmentStrategy strategy = null;
        try {
            strategy = StrategyParser.parse(strategyConfig);
        } catch (final Exception e) {
            ZonkyBot.printHelpAndExit(options, "Failed parsing strategy: " + e.getMessage(), true);
        }
        ZonkyBot.letsGo(cmd, strategy); // and start actually working with Zonky
    }

    private static void storeInvestmentsMade(final Collection<Investment> result, final boolean dryRun) {
        final String suffix = dryRun ? "dry" : "invested";
        final LocalDateTime now = LocalDateTime.now();
        final String filename =
                "zonkybot." + DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm").format(now) + '.' + suffix;
        try (final BufferedWriter bw = new BufferedWriter(new FileWriter(new File(filename)))) {
            for (final Investment i : result) {
                bw.write(i.getLoanId() + "('" + i.getLoan().getName() + "', " + i.getLoan().getRating() + "): "
                        + i.getAmount() + " CZK");
                bw.newLine();
            }
        } catch (final IOException ex) {
            ZonkyBot.LOGGER.warn("Failed writing out the list of investments made in this session.", ex);
        }
    }<commit_msg>Add a little logging message<commit_after>/*
 * Copyright 2016 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * 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 net.petrovicky.zonkybot.app;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Properties;

import net.petrovicky.zonkybot.Operations;
import net.petrovicky.zonkybot.OperationsContext;
import net.petrovicky.zonkybot.remote.Investment;
import net.petrovicky.zonkybot.strategy.InvestmentStrategy;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ZonkyBot {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZonkyBot.class);
    protected static final String ZONKY_VERSION_UNDETECTED = "UNDETECTED";
    protected static final String ZONKY_VERSION_UNKNOWN = "UNKNOWN";

    private static final Option OPTION_STRATEGY = Option.builder("s").hasArg().longOpt("strategy")
            .argName("Investment strategy").desc("Points to a file that holds the investment strategy configuration.")
            .build();
    private static final Option OPTION_USERNAME = Option.builder("u").hasArg().longOpt("username")
            .argName("Zonky username").desc("Used to connect to the Zonky server.").build();
    private static final Option OPTION_PASSWORD = Option.builder("p").hasArg().longOpt("password")
            .argName("Zonky password").desc("Used to connect to the Zonky server.").build();
    private static final Option OPTION_DRY_RUN = Option.builder("d").hasArg().optionalArg(true).
            argName("Dry run balance").longOpt("dry").desc("Simulate the investments, but never actually spend money.")
            .build();
    private static final Option OPTION_HELP = Option.builder("h").longOpt("help").argName("Show help")
            .desc("Show this help message and quit.").build();

    protected static String getZonkyBotVersion() {
        try {
            final URLClassLoader cl = (URLClassLoader) ZonkyBot.class.getClassLoader();
            final URL url = cl.findResource("META-INF/maven/net.petrovicky.zonkybot/zonkybot-app/pom.properties");
            final Properties props = new Properties();
            props.load(url.openStream());
            return props.getProperty("version", ZonkyBot.ZONKY_VERSION_UNKNOWN);
        } catch (Exception ex) {
            return ZonkyBot.ZONKY_VERSION_UNDETECTED;
        }
    }

    private static void printHelpAndExit(final Options options, final String message, final boolean exitWithError) {
        final HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("ZonkyBot", null, options, exitWithError ? "Error: " + message : message, true);
        System.exit(exitWithError ? 1 : 0);
    }

    public static void main(final String... args) {
        LOGGER.info("ZonkyBot v{} loading.", ZonkyBot.getZonkyBotVersion());
        final OptionGroup og = new OptionGroup();
        og.setRequired(true);
        og.addOption(ZonkyBot.OPTION_HELP);
        og.addOption(ZonkyBot.OPTION_STRATEGY);
        final Options options = new Options();
        options.addOptionGroup(og);
        options.addOption(ZonkyBot.OPTION_DRY_RUN);
        options.addOption(ZonkyBot.OPTION_PASSWORD);
        options.addOption(ZonkyBot.OPTION_USERNAME);

        final CommandLineParser parser = new DefaultParser();
        CommandLine cmd = null;
        try {
            cmd = parser.parse(options, args);
        } catch (final Exception ex) { // for some reason, the CLI could not be parsed
            ZonkyBot.printHelpAndExit(options, ex.getMessage(), true);
        }
        if (cmd.hasOption(ZonkyBot.OPTION_HELP.getOpt())) { // user requested help
            ZonkyBot.printHelpAndExit(options, "", false);
        }
        // standard workflow
        if (!cmd.hasOption(ZonkyBot.OPTION_USERNAME.getOpt())) {
            ZonkyBot.printHelpAndExit(options, "Username must be provided.", true);
        } else if (!cmd.hasOption(ZonkyBot.OPTION_PASSWORD.getOpt())) {
            ZonkyBot.printHelpAndExit(options, "Password must be provided.", true);
        }
        final File strategyConfig = new File(cmd.getOptionValue(ZonkyBot.OPTION_STRATEGY.getOpt()));
        if (!strategyConfig.canRead()) {
            ZonkyBot.printHelpAndExit(options, "Investment strategy file must be readable.", true);
        }
        InvestmentStrategy strategy = null;
        try {
            strategy = StrategyParser.parse(strategyConfig);
        } catch (final Exception e) {
            ZonkyBot.printHelpAndExit(options, "Failed parsing strategy: " + e.getMessage(), true);
        }
        ZonkyBot.letsGo(cmd, strategy); // and start actually working with Zonky
    }

    private static void storeInvestmentsMade(final Collection<Investment> result, final boolean dryRun) {
        final String suffix = dryRun ? "dry" : "invested";
        final LocalDateTime now = LocalDateTime.now();
        final String filename =
                "zonkybot." + DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm").format(now) + '.' + suffix;
        try (final BufferedWriter bw = new BufferedWriter(new FileWriter(new File(filename)))) {
            for (final Investment i : result) {
                bw.write(i.getLoanId() + "('" + i.getLoan().getName() + "', " + i.getLoan().getRating() + "): "
                        + i.getAmount() + " CZK");
                bw.newLine();
            }
            LOGGER.info("Investments made by ZonkyBot in this session were stored in file '{}'.", filename);
        } catch (final IOException ex) {
            ZonkyBot.LOGGER.warn("Failed writing out the list of investments made in this session.", ex);
        }
    }
{'fraction_non_alphanumeric': 0.1116214974735875, 'fraction_numerical': 0.0018373909049150207, 'mean_word_length': 3.1868589743589744, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, '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': '3110280', 'n_tokens_mistral': 3718, 'n_tokens_neox': 3652, 'n_words': 922}