package leigh.tesseract;

import org.apache.commons.io.IOUtils;
import picocli.CommandLine;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.nio.file.Paths;
import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Application for executing mass SSH commands.
 *
 * @author Alex Leigh
 */
@CommandLine.Command(name = "tesseract", mixinStandardHelpOptions = true, version = "tesseract 1.3",
        description = "Concurrently execute SSH commands.")
public class TesseractApp implements Callable<Integer> {
    @CommandLine.Parameters(index = "0", description = "Hostgroup JSON file.")
    private String hostFile;
    @CommandLine.Parameters(index = "1", description = "Remote command to execute.")
    private String cmd;
    @CommandLine.Option(names = {"-tps", "--thread-pool-size"}, paramLabel = "NUM",
            description = "The number of concurrent SSH executors.")
    private int threadSize = 8;
    @CommandLine.Option(names = {"-out", "--output-dir"}, paramLabel = "DIR", description = "Write output to files.")
    private String outputDir;

    public static void main(String... args) {
        int exitCode = new CommandLine(new TesseractApp()).execute(args);
        System.exit(exitCode);
    }

    @Override
    public Integer call() throws Exception {
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(threadSize, threadSize,
                60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

        ResultWriter rw;

        if (outputDir != null) {
            rw = new FileResultWriter(Paths.get(outputDir));
        } else {
            rw = new JsonResultWriter();
        }

        JsonHostGroupReader hgReader = new JsonHostGroupReader();
        String hgJson = IOUtils.toString(new BufferedInputStream(new FileInputStream(hostFile)));

        Tesseract t = new Tesseract(tpe, rw, hgReader.readHostGroup(hgJson));

        t.excecute(cmd);
        tpe.shutdown();

        tpe.awaitTermination(1, TimeUnit.DAYS);

        rw.finish();
        return 0;
    }
}
