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

import com.jscape.util.crypto.CryptoServicesProvider;

import java.security.Provider;

/**
 * Client key exchanges.
 *
 * @author Alex Usun
 */
public class ClientKeyExchanges {

    public static final Entry DH_GROUP1_SHA1 = new Entry("diffie-hellman-group1-sha1", DiffieHellmanClientKeyExchange.group1Sha1(true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group1Sha1(true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group1Sha1(true, provider)));
        }
    };
    public static final Entry DH_GROUP1_SHA1_DISABLED_SIGNATURE_VERIFICATION = new Entry("diffie-hellman-group1-sha1", DiffieHellmanClientKeyExchange.group1Sha1(false, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group1Sha1(false, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group1Sha1(false, provider)));
        }
    };
    public static final Entry DH_GROUP14_SHA1 = new Entry("diffie-hellman-group14-sha1", DiffieHellmanClientKeyExchange.group14Sha1(true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group14Sha1(true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group14Sha1(true, provider)));
        }
    };
    public static final Entry DH_GROUP14_SHA1_DISABLED_SIGNATURE_VERIFICATION = new Entry("diffie-hellman-group14-sha1", DiffieHellmanClientKeyExchange.group14Sha1(false, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group14Sha1(false, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group14Sha1(false, provider)));
        }
    };
    public static final Entry DH_GROUP14_SHA256 = new Entry("diffie-hellman-group14-sha256", DiffieHellmanClientKeyExchange.group14Sha256(true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group14Sha256(true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group14Sha256(true, provider)));
        }
    };
    public static final Entry DH_GROUP15_SHA512 = new Entry("diffie-hellman-group15-sha512", DiffieHellmanClientKeyExchange.group15Sha512(true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group15Sha512(true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group15Sha512(true, provider)));
        }
    };
    public static final Entry DH_GROUP16_SHA512 = new Entry("diffie-hellman-group16-sha512", DiffieHellmanClientKeyExchange.group16Sha512(true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group16Sha512(true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group16Sha512(true, provider)));
        }
    };
    public static final Entry DH_GROUP17_SHA512 = new Entry("diffie-hellman-group17-sha512", DiffieHellmanClientKeyExchange.group17Sha512(true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group17Sha512(true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group17Sha512(true, provider)));
        }
    };
    public static final Entry DH_GROUP18_SHA512 = new Entry("diffie-hellman-group18-sha512", DiffieHellmanClientKeyExchange.group18Sha512(true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group18Sha512(true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanClientKeyExchange.group18Sha512(true, provider)));
        }
    };
    public static final Entry DH_GROUP_SHA1 = new Entry("diffie-hellman-group-exchange-sha1", DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA1", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA1", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA1", true, provider)));
        }
    };
    public static final Entry DH_GROUP_SHA1_DISABLED_SIGNATURE_VERIFICATION = new Entry("diffie-hellman-group-exchange-sha1", DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA1", false, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA1", false, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA1", false, provider)));
        }
    };
    public static final Entry DH_GROUP_SHA256 = new Entry("diffie-hellman-group-exchange-sha256", DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA256", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA256", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA256", true, provider)));
        }
    };
    public static final Entry DH_GROUP_SHA256_DISABLED_SIGNATURE_VERIFICATION = new Entry("diffie-hellman-group-exchange-sha256", DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA256", false, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA256", false, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, DiffieHellmanGroupClientKeyExchange.defaultExchange("SHA256", false, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_P_256 = new Entry("ecdh-sha2-nistp256", new EcDiffieHellmanClientKeyExchange("nistp256", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("nistp256", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("nistp256", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_P_384 = new Entry("ecdh-sha2-nistp384", new EcDiffieHellmanClientKeyExchange("nistp384", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("nistp384", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("nistp384", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_P_521 = new Entry("ecdh-sha2-nistp521", new EcDiffieHellmanClientKeyExchange("nistp521", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("nistp521", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("nistp521", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_K_163 = new Entry("ecdh-sha2-1.3.132.0.1", new EcDiffieHellmanClientKeyExchange("1.3.132.0.1", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.1", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.1", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_P_192 = new Entry("ecdh-sha2-1.2.840.10045.3.1.1", new EcDiffieHellmanClientKeyExchange("1.2.840.10045.3.1.1", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.2.840.10045.3.1.1", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.2.840.10045.3.1.1", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_P_224 = new Entry("ecdh-sha2-1.3.132.0.33", new EcDiffieHellmanClientKeyExchange("1.3.132.0.33", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.33", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.33", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_K_233 = new Entry("ecdh-sha2-1.3.132.0.26", new EcDiffieHellmanClientKeyExchange("1.3.132.0.26", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.26", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.26", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_B_233 = new Entry("ecdh-sha2-1.3.132.0.27", new EcDiffieHellmanClientKeyExchange("1.3.132.0.27", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.27", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.27", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_K_283 = new Entry("ecdh-sha2-1.3.132.0.16", new EcDiffieHellmanClientKeyExchange("1.3.132.0.16", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.16", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.16", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_K_409 = new Entry("ecdh-sha2-1.3.132.0.36", new EcDiffieHellmanClientKeyExchange("1.3.132.0.36", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.36", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.36", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_B_409 = new Entry("ecdh-sha2-1.3.132.0.37", new EcDiffieHellmanClientKeyExchange("1.3.132.0.37", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.37", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.37", true, provider)));
        }
    };
    public static final Entry ECDH_SHA2_NIST_T_571 = new Entry("ecdh-sha2-1.3.132.0.38", new EcDiffieHellmanClientKeyExchange("1.3.132.0.38", true, CryptoServicesProvider.instance())) {
        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.38", true, provider)));
        }

        @Override
        public ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider) {
            return factory.set(new ComponentClientKeyExchangeFactory.Entry(this.name, new EcDiffieHellmanClientKeyExchange("1.3.132.0.38", true, provider)));
        }
    };

    public static final Entry[] ALL = {
            DH_GROUP1_SHA1,
            DH_GROUP14_SHA1,
            DH_GROUP14_SHA256,
            DH_GROUP15_SHA512,
            DH_GROUP16_SHA512,
            DH_GROUP17_SHA512,
            DH_GROUP18_SHA512,
            DH_GROUP_SHA1,
            DH_GROUP_SHA256,
            ECDH_SHA2_NIST_P_256,
            ECDH_SHA2_NIST_P_384,
            ECDH_SHA2_NIST_P_521,
            ECDH_SHA2_NIST_K_163,
            ECDH_SHA2_NIST_P_192,
            ECDH_SHA2_NIST_P_224,
            ECDH_SHA2_NIST_K_233,
            ECDH_SHA2_NIST_B_233,
            ECDH_SHA2_NIST_K_283,
            ECDH_SHA2_NIST_K_409,
            ECDH_SHA2_NIST_B_409,
            ECDH_SHA2_NIST_T_571,
    };

    public static final Entry[] ALL_DISABLED_SIGNATURE_VERIFICATION = {
            DH_GROUP1_SHA1_DISABLED_SIGNATURE_VERIFICATION,
            DH_GROUP14_SHA1_DISABLED_SIGNATURE_VERIFICATION,
            DH_GROUP_SHA1_DISABLED_SIGNATURE_VERIFICATION,
            DH_GROUP_SHA256_DISABLED_SIGNATURE_VERIFICATION,
    };

    public static ComponentClientKeyExchangeFactory init(ComponentClientKeyExchangeFactory factory, Entry... entries) {
        return init(factory, CryptoServicesProvider.instance(), entries);
    }

    public static ComponentClientKeyExchangeFactory init(ComponentClientKeyExchangeFactory factory, String provider, Entry... entries) {
        for (Entry entry : entries) {
            entry.update(factory, provider);
        }

        return factory;
    }

    public static ComponentClientKeyExchangeFactory init(ComponentClientKeyExchangeFactory factory, Provider provider, Entry... entries) {
        for (Entry entry : entries) {
            entry.update(factory, provider);
        }

        return factory;
    }

    /**
     * Setups required key exchange algorithms.
     *
     * @param factory a factory
     *
     * @return a factory
     */
    public static ComponentClientKeyExchangeFactory initRequired(ComponentClientKeyExchangeFactory factory) {
        return initRequired(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initRequiredDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory) {
        return initRequiredDisabledSignatureVerification(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initRequired(ComponentClientKeyExchangeFactory factory, String provider) {
        return init(factory,
                    provider,
                    DH_GROUP1_SHA1,
                    DH_GROUP14_SHA1,
                    ECDH_SHA2_NIST_P_256,
                    ECDH_SHA2_NIST_P_384,
                    ECDH_SHA2_NIST_P_521);
    }

    public static ComponentClientKeyExchangeFactory initRequiredDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, String provider) {
        return init(factory,
                    provider,
                    DH_GROUP1_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP14_SHA1_DISABLED_SIGNATURE_VERIFICATION);
    }

    public static ComponentClientKeyExchangeFactory initRequired(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return init(factory,
                    provider,
                    DH_GROUP1_SHA1,
                    DH_GROUP14_SHA1,
                    ECDH_SHA2_NIST_P_256,
                    ECDH_SHA2_NIST_P_384,
                    ECDH_SHA2_NIST_P_521);
    }

    public static ComponentClientKeyExchangeFactory initRequiredDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return init(factory,
                    provider,
                    DH_GROUP1_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP14_SHA1_DISABLED_SIGNATURE_VERIFICATION);
    }

    /**
     * Setups optional key exchange algorithms.
     *
     * @param factory a factory
     *
     * @return a factory
     */
    public static ComponentClientKeyExchangeFactory initOptional(ComponentClientKeyExchangeFactory factory) {
        return initOptional(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initOptionalDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory) {
        return initOptionalDisabledSignatureVerification(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initOptional(ComponentClientKeyExchangeFactory factory, String provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA1,
                    DH_GROUP_SHA256,
                    ECDH_SHA2_NIST_K_163,
                    ECDH_SHA2_NIST_P_192,
                    ECDH_SHA2_NIST_P_224,
                    ECDH_SHA2_NIST_K_233,
                    ECDH_SHA2_NIST_B_233,
                    ECDH_SHA2_NIST_K_283,
                    ECDH_SHA2_NIST_K_409,
                    ECDH_SHA2_NIST_B_409,
                    ECDH_SHA2_NIST_T_571);
    }

    public static ComponentClientKeyExchangeFactory initOptionalDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, String provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP_SHA256_DISABLED_SIGNATURE_VERIFICATION);
    }

    public static ComponentClientKeyExchangeFactory initOptional(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA1,
                    DH_GROUP_SHA256,
                    ECDH_SHA2_NIST_K_163,
                    ECDH_SHA2_NIST_P_192,
                    ECDH_SHA2_NIST_P_224,
                    ECDH_SHA2_NIST_K_233,
                    ECDH_SHA2_NIST_B_233,
                    ECDH_SHA2_NIST_K_283,
                    ECDH_SHA2_NIST_K_409,
                    ECDH_SHA2_NIST_B_409,
                    ECDH_SHA2_NIST_T_571);
    }

    public static ComponentClientKeyExchangeFactory initOptionalDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP_SHA256_DISABLED_SIGNATURE_VERIFICATION);
    }

    /**
     * Setups all implemented key exchange algorithms.
     *
     * @param factory a factory
     *
     * @return a factory
     */
    public static ComponentClientKeyExchangeFactory initAll(ComponentClientKeyExchangeFactory factory) {
        return initAll(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initAllDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory) {
        return initAllDisabledSignatureVerification(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initAll(ComponentClientKeyExchangeFactory factory, String provider) {
        return initOptional(initRequired(factory, provider), provider);
    }

    public static ComponentClientKeyExchangeFactory initAllDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, String provider) {
        return initOptionalDisabledSignatureVerification(initRequiredDisabledSignatureVerification(factory, provider), provider);
    }

    public static ComponentClientKeyExchangeFactory initAll(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return initOptional(initRequired(factory, provider), provider);
    }

    public static ComponentClientKeyExchangeFactory initAllDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return initOptionalDisabledSignatureVerification(initRequiredDisabledSignatureVerification(factory, provider), provider);
    }

    public static ComponentClientKeyExchangeFactory initAllClient(ComponentClientKeyExchangeFactory factory) {
        return initAllClient(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initAllClientDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory) {
        return initAllClientDisabledSignatureVerification(factory, CryptoServicesProvider.instance());
    }

    public static ComponentClientKeyExchangeFactory initAllClient(ComponentClientKeyExchangeFactory factory, String provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA256,
                    DH_GROUP_SHA1,
                    DH_GROUP14_SHA1,
                    DH_GROUP14_SHA256,
                    DH_GROUP15_SHA512,
                    DH_GROUP16_SHA512,
                    DH_GROUP17_SHA512,
                    DH_GROUP18_SHA512,
                    DH_GROUP1_SHA1,
                    ECDH_SHA2_NIST_P_256,
                    ECDH_SHA2_NIST_P_384,
                    ECDH_SHA2_NIST_P_521,
                    ECDH_SHA2_NIST_K_163,
                    ECDH_SHA2_NIST_P_192,
                    ECDH_SHA2_NIST_P_224,
                    ECDH_SHA2_NIST_K_233,
                    ECDH_SHA2_NIST_B_233,
                    ECDH_SHA2_NIST_K_283,
                    ECDH_SHA2_NIST_K_409,
                    ECDH_SHA2_NIST_B_409,
                    ECDH_SHA2_NIST_T_571);
    }

    public static ComponentClientKeyExchangeFactory initAllClientDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, String provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA256_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP14_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP1_SHA1_DISABLED_SIGNATURE_VERIFICATION);
    }

    public static ComponentClientKeyExchangeFactory initAllClient(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA256,
                    DH_GROUP_SHA1,
                    DH_GROUP14_SHA1,
                    DH_GROUP14_SHA256,
                    DH_GROUP15_SHA512,
                    DH_GROUP16_SHA512,
                    DH_GROUP17_SHA512,
                    DH_GROUP18_SHA512,
                    DH_GROUP1_SHA1,
                    ECDH_SHA2_NIST_P_256,
                    ECDH_SHA2_NIST_P_384,
                    ECDH_SHA2_NIST_P_521,
                    ECDH_SHA2_NIST_K_163,
                    ECDH_SHA2_NIST_P_192,
                    ECDH_SHA2_NIST_P_224,
                    ECDH_SHA2_NIST_K_233,
                    ECDH_SHA2_NIST_B_233,
                    ECDH_SHA2_NIST_K_283,
                    ECDH_SHA2_NIST_K_409,
                    ECDH_SHA2_NIST_B_409,
                    ECDH_SHA2_NIST_T_571);
    }

    public static ComponentClientKeyExchangeFactory initAllClientDisabledSignatureVerification(ComponentClientKeyExchangeFactory factory, Provider provider) {
        return init(factory,
                    provider,
                    DH_GROUP_SHA256_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP14_SHA1_DISABLED_SIGNATURE_VERIFICATION,
                    DH_GROUP1_SHA1_DISABLED_SIGNATURE_VERIFICATION);
    }

    private ClientKeyExchanges() {
        // empty
    }

    public abstract static class Entry
            extends ComponentClientKeyExchangeFactory.Entry {

        public Entry(String name, ClientKeyExchange clientKeyExchange) {
            super(name, clientKeyExchange);
        }

        public abstract ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, String provider);

        public abstract ComponentClientKeyExchangeFactory update(ComponentClientKeyExchangeFactory factory, Provider provider);
    }
}
