// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.feed.client;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.nio.file.Path;
import java.util.Properties;

/**
 * Main method for CLI interface
 *
 * @author bjorncs
 */
public class CliClient {

    private final PrintStream systemOut;
    private final PrintStream systemError;
    private final InputStream systemIn;
    private final Properties systemProperties;

    private CliClient(PrintStream systemOut, PrintStream systemError, InputStream systemIn, Properties systemProperties) {
        this.systemOut = systemOut;
        this.systemError = systemError;
        this.systemIn = systemIn;
        this.systemProperties = systemProperties;
    }

    public static void main(String[] args) {
        CliClient client = new CliClient(System.out, System.err, System.in, System.getProperties());
        int exitCode = client.run(args);
        System.exit(exitCode);
    }

    private int run(String[] rawArgs) {
        try {
            CliArguments cliArgs = CliArguments.fromRawArgs(rawArgs);
            if (cliArgs.helpSpecified()) {
                cliArgs.printHelp(systemOut);
                return 0;
            }
            if (cliArgs.versionSpecified()) {
                systemOut.println(Vespa.VERSION);
                return 0;
            }
            FeedClient feedClient = createFeedClient(cliArgs);
            return 0;
        } catch (CliArguments.CliArgumentsException | IOException e) {
            return handleException(e);
        }
    }

    private static FeedClient createFeedClient(CliArguments cliArgs) throws CliArguments.CliArgumentsException, IOException {
        FeedClientBuilder builder = FeedClientBuilder.create(cliArgs.endpoint());
        cliArgs.connections().ifPresent(builder::setMaxConnections);
        cliArgs.maxStreamsPerConnection().ifPresent(builder::setMaxConnections);
        if (cliArgs.sslHostnameVerificationDisabled()) {
            builder.setHostnameVerifier(AcceptAllHostnameVerifier.INSTANCE);
        }
        CliArguments.CertificateAndKey certificateAndKey = cliArgs.certificateAndKey().orElse(null);
        Path caCertificates = cliArgs.caCertificates().orElse(null);
        if (certificateAndKey != null || caCertificates != null) {
            SslContextBuilder sslContextBuilder = new SslContextBuilder();
            if (certificateAndKey != null) {
                sslContextBuilder.withCertificateAndKey(certificateAndKey.certificateFile, certificateAndKey.privateKeyFile);
            }
            if (caCertificates != null) {
                sslContextBuilder.withCaCertificates(caCertificates);
            }
            builder.setSslContext(sslContextBuilder.build());
        }
        cliArgs.headers().forEach(builder::addRequestHeader);
        return builder.build();
    }

    private int handleException(Exception e) { return handleException(e.getMessage(), e); }

    private int handleException(String message, Exception exception) {
        systemError.println(message);
        if (debugMode()) {
            exception.printStackTrace(systemError);
        }
        return 1;
    }

    private boolean debugMode() {
        return Boolean.parseBoolean(systemProperties.getProperty("VESPA_DEBUG", Boolean.FALSE.toString()));
    }

    private static class AcceptAllHostnameVerifier implements HostnameVerifier {
        static final AcceptAllHostnameVerifier INSTANCE = new AcceptAllHostnameVerifier();
        @Override public boolean verify(String hostname, SSLSession session) { return true; }
    }
}

@@ -205,24 +205,60 @@
 SSLSession;%0A
+import java.io.BufferedInputStream;%0A
 import java.
@@ -269,24 +269,24 @@
 OException;%0A
-
 import java.
@@ -321,32 +321,60 @@
 io.PrintStream;%0A
+import java.nio.file.Files;%0A
 import java.nio.
@@ -1595,58 +1595,163 @@
     
-FeedClient feedClient = createFeedClient(cliArgs);
+try (InputStream in = createFeedInputStream(cliArgs); JsonStreamFeeder feeder = createJsonFeeder(cliArgs)) %7B%0A                feeder.feed(in);%0A            %7D
 %0A   
@@ -3151,24 +3151,24 @@
 estHeader);%0A
-
         retu
@@ -3186,32 +3186,809 @@
 build();%0A    %7D%0A%0A
+    private static JsonStreamFeeder createJsonFeeder(CliArguments cliArgs) throws CliArguments.CliArgumentsException, IOException %7B%0A        FeedClient feedClient = createFeedClient(cliArgs);%0A        JsonStreamFeeder.Builder builder = JsonStreamFeeder.builder(feedClient);%0A        cliArgs.timeout().ifPresent(builder::withTimeout);%0A        cliArgs.route().ifPresent(builder::withRoute);%0A        cliArgs.traceLevel().ifPresent(builder::withTracelevel);%0A        return builder.build();%0A    %7D%0A%0A    private InputStream createFeedInputStream(CliArguments cliArgs) throws CliArguments.CliArgumentsException, IOException %7B%0A        return new BufferedInputStream(%0A                cliArgs.readFeedFromStandardInput() ? systemIn : Files.newInputStream(cliArgs.inputFile().get()));%0A    %7D%0A%0A
     private int 

Use JsonStreamFeeder to feed documents from CliClient