package com.jscape.util.keystore;

import com.jscape.util.crypto.CryptoServicesProvider;
import com.jscape.util.io.DataCodec;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.Provider;

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

/**
 * @author Alex Usun
 */
public class KeyStoreCodec
        implements DataCodec<KeyStore> {

    private final String type;
    private final String password;
    private final Provider provider;

    public static KeyStore readValue(InputStream in, String type, String password, Provider provider)
            throws IOException {
        try {
            KeyStore keyStore = provider != null ? KeyStore.getInstance(type, provider) : KeyStore.getInstance(type);
            keyStore.load(in, password.toCharArray());

            return keyStore;
        } catch (Exception e) {
            throw ioException(e);
        }
    }

    public static void writeValue(KeyStore value, String password, OutputStream out)
            throws IOException {
        try {
            value.store(out, password.toCharArray());
        } catch (Exception e) {
            throw ioException(e);
        }
    }

    public static KeyStoreCodec defaultJksCodec(String password) {
        return new KeyStoreCodec("JKS", password, null);
    }

    public static KeyStoreCodec bcJksCodec(String password) {
        return new KeyStoreCodec("JKS", password, CryptoServicesProvider.instance());
    }

    public static KeyStoreCodec defaultPkcs12Codec(String password) {
        return new KeyStoreCodec("PKCS12", password, null);
    }

    public static KeyStoreCodec bcPkcs12Codec(String password) {
        return new KeyStoreCodec("PKCS12", password, CryptoServicesProvider.instance());
    }

    public KeyStoreCodec(String type, String password, Provider provider) {
        assertNotNull(type);
        this.type = type;

        assertNotNull(password);
        this.password = password;

        this.provider = provider;
    }

    @Override
    public KeyStore read(InputStream in)
            throws IOException {
        return readValue(in, this.type, this.password, this.provider);
    }

    @Override
    public void write(KeyStore value, OutputStream out)
            throws IOException {
        writeValue(value, this.password, out);
    }
}
