package co.arcs.groove.basking;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.internal.Lists;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.ListenableFuture;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import co.arcs.groove.basking.task.SyncTask.Outcome;

public class Cli {

    private static List<String> parseConfigFile(File file) throws IOException {
        List<String> configArgs = Lists.newArrayList();
        JsonNode root = new ObjectMapper().readTree(file);
        JsonNode numConcurrentDownloadsNode = root.get("numConcurrentDownloads");
        if (numConcurrentDownloadsNode != null) {
            configArgs.add("--num-concurrent");
            configArgs.add(numConcurrentDownloadsNode.asText());
        }
        JsonNode dryRunNode = root.get("dryRun");
        if (dryRunNode != null) {
            if (dryRunNode.asBoolean()) {
                configArgs.add("--dry-run");
            }
        }
        JsonNode syncDirectoryNode = root.get("syncDirectory");
        if (syncDirectoryNode != null) {
            configArgs.add("--sync-dir");
            configArgs.add(syncDirectoryNode.asText());
        }
        JsonNode usernameNode = root.get("username");
        if (usernameNode != null) {
            configArgs.add("--username");
            configArgs.add(usernameNode.asText());
        }
        JsonNode passwordNode = root.get("password");
        if (passwordNode != null) {
            configArgs.add("--password");
            configArgs.add(passwordNode.asText());
        }
        return configArgs;
    }

    public static void main(String[] argsArr) {

        Config config = new Config();
        JCommander jc = new JCommander(config);
        jc.setProgramName("basking");

        List<String> args = Lists.newArrayList(argsArr);

        // Attempt to read parameters from the config file
        int configFileParamIndex;
        if (((configFileParamIndex = args.indexOf(Config.CONFIG_ARG_SHORT)) > 0) || ((configFileParamIndex = args
                .indexOf(Config.CONFIG_ARG_LONG)) > 0)) {
            if (args.size() > configFileParamIndex) {
                // There's a valid config file parameter
                String configFileParamKey = args.get(configFileParamIndex);
                String configFileParamValue = args.get(configFileParamIndex + 1);
                try {
                    // Create synthetic arguments from the file
                    List<String> configFileParams = parseConfigFile(new File(configFileParamValue));

                    // Append them to the main args list. Also remove references to the config file.
                    args.remove(configFileParamKey);
                    args.remove(configFileParamValue);
                    args.addAll(configFileParams);
                } catch (IOException e) {
                    exit1(jc,
                            new ParameterException("Could not read file '" + configFileParamValue + "'."));
                    return;
                }
            }
        }

        // Parse
        try {
            jc.parse(args.toArray(new String[args.size()]));
        } catch (ParameterException e) {
            exit1(jc, e);
            return;
        }

        // Special cases
        if (config.help) {
            jc.usage();
            return;
        } else if (config.version) {
            try {
                Properties p = new Properties();
                InputStream is = Cli.class.getResourceAsStream(
                        "/META-INF/maven/co.arcs.groove/basking/pom.properties");
                p.load(is);
                String version = p.getProperty("version", null);
                System.out.println("basking v" + version);
            } catch (IOException e) {
                Throwables.propagate(e);
            }
            return;
        }

        new Runner(config).run();
    }

    private static void exit1(JCommander jc, Exception e1) {
        System.err.println(e1.getMessage());
        jc.usage();
        System.exit(1);
    }

    private static class Runner {

        private final Config config;

        public Runner(Config config) {
            this.config = config;
        }

        void run() {
            // Disable other logging
            Logger rootLogger = Logger.getLogger("");
            rootLogger.removeHandler(rootLogger.getHandlers()[0]);

            SyncService syncService = new SyncService();

            ConsoleLogger consoleLogger = new ConsoleLogger();
            syncService.getEventBus().register(consoleLogger);

            ListenableFuture<Outcome> serviceOutcome = syncService.start(config);

            try {
                Outcome outcome = serviceOutcome.get();
                if (outcome.getFailedToDownload() > 0) {
                    System.exit(1);
                }
            } catch (Throwable t) {
                System.exit(1);
            }
        }
    }
}

@@ -2277,16 +2277,17 @@
 HORT)) %3E
+=
  0) %7C%7C (
@@ -2366,16 +2366,17 @@
 LONG)) %3E
+=
  0)) %7B%0A 

Fix bug where config file parameter ignored if first parameter.