package com.jscape.inet.ssh.protocol.v2.transport.keyexchange;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

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

/**
 * A component-based key exchange factory.
 *
 * @author Alex Usun
 */
public class ComponentClientKeyExchangeFactory
        implements ClientKeyExchangeFactory {

    private final Map<String, Entry> entries;

    /**
     * Creates a new factory instance.
     *
     * @param entries entries
     */
    public ComponentClientKeyExchangeFactory(Entry... entries) {
        this.entries = new LinkedHashMap<>();
        set(entries);
    }

    /**
     * Sets the factory entries.
     *
     * @param entries entries
     * @return
     */
    public ComponentClientKeyExchangeFactory set(Entry... entries) {
        for (Entry entry : entries) {
            this.entries.put(entry.name, entry);
        }

        return this;
    }

    @Override
    public List<String> keyExchanges() {
        return new ArrayList<>(this.entries.keySet());
    }

    @Override
    public ClientKeyExchange keyExchangeFor(String name) {
        Entry entry = entryFor(name);
        return entry.clientKeyExchange;
    }

    @Override
    public String toString() {
        return "CommonKeyExchangeFactory {"
                + "entries=" + this.entries
                + '}';
    }

    private Entry entryFor(String name) {
        Entry entry = this.entries.get(name);

        if (entry == null) {
            throw new IllegalArgumentException("Unsupported algorithm: " + name);
        }

        return entry;
    }

    /**
     * A factory entry.
     */
    public static class Entry {

        public final String name;
        public final ClientKeyExchange clientKeyExchange;

        /**
         * Creates a new entry instance.
         *
         * @param name a SSH algorithm name
         * @param clientKeyExchange a key exchange instance
         */
        public Entry(String name, ClientKeyExchange clientKeyExchange) {
            assertNotNull(name);
            this.name = name;

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

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