package ee.shy.core;

import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
import com.pastdev.jsch.DefaultSessionFactory;

import java.io.Console;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.util.Collections;
import java.util.Map;

/**
 * Repository accessed over a SSH connection using SFTP.
 */
public class SshRepository extends Repository {
    private final FileSystem fileSystem;

    /**
     * Constructs a new SSH repository class.
     * @param fileSystem SSH FileSystem for repository.
     */
    private SshRepository(FileSystem fileSystem) throws IOException {
        super(fileSystem.getPath(""));
        this.fileSystem = fileSystem;
    }

    /**
     * Connects to a remote SSH repository.
     * @param remoteUri URI to SSH repository
     * @return a Repository object if remote repository was found
     * @throws IOException
     * @throws URISyntaxException
     */
    public static SshRepository newRemote(URI remoteUri) throws IOException, URISyntaxException {
        if (!"ssh".equals(remoteUri.getScheme()))
            throw new RuntimeException("URI must have 'ssh' scheme"); // TODO: 22.04.16 throw better exception

        DefaultSessionFactory sessionFactory = new DefaultSessionFactory();

        Map<String, Object> environment = Collections.singletonMap("defaultSessionFactory", sessionFactory);

        // TODO: 21.04.16 allow password user input and keyboard-interactive
        sessionFactory.setUserInfo(new ConsoleUserInfo());
        sessionFactory.setConfig("server_host_key", "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss"); // OpenSSH algorithm order for better known_hosts compatibility
        sessionFactory.setConfig("HashKnownHosts", "yes"); // only applies to adding hosts

        URI uri = new URI("ssh.unix", remoteUri.getUserInfo(), remoteUri.getHost(), remoteUri.getPort(), remoteUri.getPath(), remoteUri.getQuery(), remoteUri.getFragment());
        return new SshRepository(FileSystems.newFileSystem(uri, environment));
    }

    @Override
    public void close() throws IOException {
        fileSystem.close();
    }

    private static class ConsoleUserInfo implements UserInfo, UIKeyboardInteractive {
        private Console console = System.console();

        private String passphrase;
        private String password;

        @Override
        public String getPassphrase() {
            return passphrase;
        }

        @Override
        public String getPassword() {
            return password;
        }

        @Override
        public boolean promptPassword(String message) {
            System.out.println(message + ": ");

            char[] password = console.readPassword();
            if (password == null)
                return false;

            this.password = new String(password);
            return true;
        }

        @Override
        public boolean promptPassphrase(String message) {
            System.out.println(message + ": ");

            char[] passphrase = console.readPassword();
            if (passphrase == null)
                return false;

            this.passphrase = new String(passphrase);
            return true;
        }

        @Override
        public boolean promptYesNo(String message) {
            System.out.println(message + ": ");
            return console.readLine().trim().toLowerCase().startsWith("y"); // y or yes
        }

        @Override
        public void showMessage(String message) {
            System.out.println(message);
        }

        @Override
        public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
            System.out.println(instruction);

            String[] answers = new String[prompt.length];
            for (int i = 0; i < prompt.length; i++) {
                System.out.println(prompt[i] + ": ");

                String answer;
                if (echo[i]) {
                    answer = console.readLine();
                    if (answer == null)
                        return null;
                }
                else {
                    char[] answerChars = console.readPassword();
                    if (answerChars == null)
                        return null;
                    answer = new String(answerChars);
                }
                answers[i] = answer;
            }
            return answers;
        }
    }
}

@@ -1482,85 +1482,8 @@
 );%0A%0A
-        // TODO: 21.04.16 allow password user input and keyboard-interactive%0A
     
@@ -1533,24 +1533,24 @@
 serInfo());%0A
+
         sess
@@ -2661,57 +2661,8 @@
 ) %7B%0A
-            System.out.println(message + %22: %22);%0A%0A
     
@@ -2700,32 +2700,46 @@
 le.readPassword(
+message + %22: %22
 );%0A            i
@@ -2956,57 +2956,8 @@
 ) %7B%0A
-            System.out.println(message + %22: %22);%0A%0A
     
@@ -2997,32 +2997,46 @@
 le.readPassword(
+message + %22: %22
 );%0A            i
@@ -3263,33 +3263,47 @@
        S
-ystem.out.println
+tring choice = console.readLine
 (message
@@ -3332,33 +3332,39 @@
 return c
-onsole.readLine()
+hoice != null && choice
 .trim().
@@ -3497,34 +3497,30 @@
         
-System.out
+console
 .print
-ln
+f
 (message
@@ -3701,34 +3701,30 @@
         
-System.out
+console
 .print
-ln
+f
 (instruc
@@ -3847,63 +3847,8 @@
 ) %7B%0A
-                System.out.println(prompt%5Bi%5D + %22: %22);%0A%0A
     
@@ -3951,16 +3951,32 @@
 eadLine(
+prompt%5Bi%5D + %22: %22
 );%0A     
@@ -4084,24 +4084,24 @@
      else %7B%0A
-
             
@@ -4150,16 +4150,32 @@
 assword(
+prompt%5Bi%5D + %22: %22
 );%0A     

Simplify ConsoleUserInfo outputting