package com.jscape.inet.ssh.protocol.v2.marshaling.algorithms;

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 compression factory.
 *
 * @author Alex Usun
 */
public class ComponentCompressionFactory
        implements CompressionFactory {

    private final Map<String, Entry> entries;

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

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

        return this;
    }

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

    @Override
    public Compression clientToServerCompressionFor(String name, Mode mode)
            throws OperationException {
        Entry entry = entryFor(name);
        return entry.clientToServerCompressionFor(mode);
    }

    @Override
    public Compression serverToClientCompressionFor(String name, Mode mode)
            throws OperationException {
        Entry entry = entryFor(name);
        return entry.serverToClientCompressionFor(mode);
    }

    @Override
    public String toString() {
        return "ComponentCompressionFactory {"
                + "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;
    }

    /**
     * An algorithm entry.
     */
    public abstract static class Entry {

        public static final ComponentCompressionFactory.Entry NONE = new ComponentCompressionFactory.Entry("none") {

            @Override
            public Compression clientToServerCompressionFor(CompressionFactory.Mode mode) {
                return Compression.NULL;
            }

            @Override
            public Compression serverToClientCompressionFor(CompressionFactory.Mode mode) {
                return Compression.NULL;
            }
        };

        public final String name;

        /**
         * Creates a new algorithm entry.
         *
         * @param name a SSH algorithm name
         */
        protected Entry(String name) {
            assertNotNull(name);
            this.name = name;
        }

        public abstract Compression clientToServerCompressionFor(Mode mode);

        public abstract Compression serverToClientCompressionFor(Mode mode);
    }

}
