/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore.PasswordProtection;
import java.security.PrivateKey;
import java.util.List;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.scytl.keystore.ScytlKeyStoreServiceAPI;
import com.scytl.cryptolib.scytl.keystore.cryptoapi.CryptoAPIScytlKeyStore;
import com.scytl.cryptolib.scytl.keystore.service.ScytlKeyStoreService;
import com.scytl.products.ov.config.exceptions.ConfigurationEngineException;

/**
 * A utility class for keystores management
 */
public class KeyStoreReader {

    private final ScytlKeyStoreServiceAPI _storesService;

    /**
     * Provides functionality for extracting data from a {@link CryptoAPIKeyStore}.
     * 
     * @throws GeneralCryptoLibException failed to create key store reader 
     */
    public KeyStoreReader() throws GeneralCryptoLibException {

        _storesService = new ScytlKeyStoreService();
    }

    /**
     * Extracts a {@link PrivateKey} from the keystore at the path {@code servicesKeyStorePath}, using a password read
     * from the file {@link passwordPath}.
     *
     * @param pathAndFilenameOfKeystore
     *            the path of the keystore.
     * @param pathAndFilenameOfPasswordFile
     *            the path of the file containing the password that can be used to open the keystore.
     * @param passwordTag
     *            the tag that is associated with the password within the file {@code pathAndFilenameOfPasswordFile}.
     * @param alias
     *            the alias that is associated with the private key in the keystore.
     * @return The extracted private key.
     * @throws IOException
     * @throws GeneralCryptoLibException
     */
    public PrivateKey getPrivateKey(final Path pathAndFilenameOfKeystore, final Path pathAndFilenameOfPasswordFile,
            final String passwordTag, final String alias) throws ConfigurationEngineException {

        try ( final InputStream in = new FileInputStream(pathAndFilenameOfKeystore.toFile())) {
            final char[] password = getPasswordFromFile(pathAndFilenameOfPasswordFile, passwordTag);
            final CryptoAPIScytlKeyStore ks = _storesService.loadKeyStore(in, new PasswordProtection(password));
            return ks.getPrivateKeyEntry(alias, password);
        } catch (IOException | GeneralCryptoLibException e) {
            throw new ConfigurationEngineException(e);
        }

    }

    private char[] getPasswordFromFile(final Path path, final String name)
            throws IOException, ConfigurationEngineException {

        final List<String> lines = Files.readAllLines(path);
        String password = null;

        for (final String line : lines) {
            final String[] splittedLine = line.split(",");

            if (splittedLine[0].equals(name)) {
                password = splittedLine[1];
            }
        }

        if (password == null) {
            throw new ConfigurationEngineException("The passwords file does not contain a password for " + name);
        }

        return password.toCharArray();
    }

    public static String toString(final CryptoAPIScytlKeyStore keyStore, final char[] password) {

        try {
            final byte[] keyStoreJSONBytes = keyStore.toJSON(password).getBytes(StandardCharsets.UTF_8);
            return new String(java.util.Base64.getEncoder().encode(keyStoreJSONBytes), StandardCharsets.UTF_8);

        } catch (GeneralCryptoLibException e) {
            throw new ConfigurationEngineException(
                "Exception while obtaining string representation of keystore: " + e.getMessage(), e);
        }
    }
}
