package com.jscape.inet.ssh.protocol.v2.authentication;

import com.jscape.inet.ssh.protocol.v2.marshaling.MessageCodec;
import com.jscape.inet.ssh.protocol.v2.messages.UserAuthInfoRequestPrompt;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.jscape.util.Parameters.assertNotNull;

/**
 * Represents a SSH 'keyboard-interactive' authentication operation which sends pre-defined responses searching for known words in server requests.
 *
 * @author Alex Usun
 */
public class KeyboardInteractiveRegexClientAuthentication
        extends AbstractKeyboardInteractiveClientAuthentication {

    private final List<Entry> entries;

    public static KeyboardInteractiveRegexClientAuthentication defaultAuthentication(String username, List<Entry> entries) {
        return new KeyboardInteractiveRegexClientAuthentication(KeyboardInteractiveMessages.defaultMessages(), username, entries);
    }

    public static KeyboardInteractiveRegexClientAuthentication defaultAuthentication(String username, Entry... entries) {
        return new KeyboardInteractiveRegexClientAuthentication(KeyboardInteractiveMessages.defaultMessages(), username, entries);
    }

    /**
     * Creates a new operation instance.
     *
     * @param username an username
     * @param entries response entries
     */
    public KeyboardInteractiveRegexClientAuthentication(MessageCodec.Factory codecFactory, String username, List<Entry> entries) {
        super(codecFactory, username);

        assertNotNull(entries);
        this.entries = entries;
    }

    /**
     * Creates a new operation instance.
     *
     * @param username an username
     * @param entries response entries
     */
    public KeyboardInteractiveRegexClientAuthentication(MessageCodec.Factory codecFactory, String username, Entry... entries) {
        this(codecFactory, username, Arrays.<Entry>asList(entries));
    }

    @Override
    protected List<String> responsesFor(String name, String instruction, List<UserAuthInfoRequestPrompt> prompts)
            throws Exception {
        List<String> responses = new ArrayList<String>(prompts.size());

        for (UserAuthInfoRequestPrompt prompt : prompts) {
            String response = responseFor(prompt.prompt);
            responses.add(response);
        }

        return responses;
    }

    private String responseFor(String prompt)
            throws Exception {
        for (Entry entry : this.entries) {
            if (prompt.matches(entry.regex)) {
                return entry.response;
            }
        }

        throw new Exception("Unsupported user info prompt: " + prompt);
    }

    /**
     * Represents a pre-defined response.
     */
    public static class Entry {

        public final String regex;
        public final String response;

        /**
         * Creates a new entry instance.
         *
         * @param regex a request regex
         * @param response a response
         */
        public Entry(String regex, String response) {
            assertNotNull(regex);
            this.regex = regex;

            assertNotNull(response);
            this.response = response;
        }

        @Override
        public String toString() {
            return "Entry {"
                   + "regex='" + this.regex + '\''
                   + ", response='" + this.response + '\''
                   + '}';
        }
    }
}
