package com.jscape.util.keystore;

import com.jscape.util.Base64Format;
import com.jscape.util.crypto.CryptoServicesProvider;
import com.jscape.util.io.ByteArrayInputStream;
import com.jscape.util.io.ByteArrayOutputStream;
import com.jscape.util.io.DataCodec;
import org.bouncycastle.util.io.pem.PemReader;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.Provider;

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

/**
 * @author Alex Usun
 */
public class PemPkcs8KeyPairCodec
        implements DataCodec<KeyPair> {

    private final Provider provider;

    public static KeyPair readValue(InputStream in, Provider provider)
            throws IOException {
        try {
            PemReader reader = new PemReader(new InputStreamReader(in, StandardCharsets.US_ASCII));
            byte[] data = reader.readPemObject().getContent();

            return Pkcs8KeyPairCodec.readValue(new ByteArrayInputStream(data), provider);
        } catch (Exception e) {
            throw ioException(e);
        }
    }

    public static void writeValue(KeyPair value, OutputStream out)
            throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        Pkcs8KeyPairCodec.writeValue(value, buffer);
        byte[] data = buffer.toByteArray();
        String base64Data = Base64Format.formatData(data, Base64Format.DEFAULT_LINE_LENGTH);
        String entryData = String.format("-----BEGIN PRIVATE KEY-----\r\n%s\r\n-----END PRIVATE KEY-----\r\n", base64Data);

        out.write(entryData.getBytes(StandardCharsets.US_ASCII));
    }

    public static PemPkcs8KeyPairCodec defaultCodec() {
        return new PemPkcs8KeyPairCodec(null);
    }

    public static PemPkcs8KeyPairCodec bcCodec() {
        return new PemPkcs8KeyPairCodec(CryptoServicesProvider.instance());
    }

    public PemPkcs8KeyPairCodec(Provider provider) {
        this.provider = provider;
    }

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

    @Override
    public void write(KeyPair value, OutputStream out)
            throws IOException {
        writeValue(value, out);
    }
}
