/*
 * 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.config.commands.electionevent.datapacks.generators;

import java.io.IOException;

import com.scytl.cryptolib.api.elgamal.ElGamalServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.primitives.PrimitivesServiceAPI;
import com.scytl.cryptolib.api.scytl.keystore.ScytlKeyStoreServiceAPI;
import com.scytl.cryptolib.elgamal.bean.ElGamalEncryptionParameters;
import com.scytl.cryptolib.elgamal.bean.ElGamalKeyPair;
import com.scytl.cryptolib.elgamal.cryptoapi.CryptoAPIElGamalKeyPairGenerator;
import com.scytl.cryptolib.scytl.keystore.cryptoapi.CryptoAPIScytlKeyStore;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomString;
import com.scytl.products.ov.config.commands.electionevent.datapacks.beans.ElGamalCredentialDataPack;
import com.scytl.products.ov.constants.Constants;
import com.scytl.products.ov.datapacks.beans.CredentialProperties;

/**
 * Generator for creating {@link ElGamalCredentialDataPackGenerator}.
 */
public class ElGamalCredentialDataPackGenerator {
    private final ElGamalServiceAPI elGamalService;

    private final ScytlKeyStoreServiceAPI storeService;

    private final PrimitivesServiceAPI primitivesService;

    /**
     * Constructor.
     * 
     * @param elGamalService
     * @param storeService
     * @param primitivesService
     */
    public ElGamalCredentialDataPackGenerator(
            ElGamalServiceAPI elGamalService,
            ScytlKeyStoreServiceAPI storeService,
            PrimitivesServiceAPI primitivesService) {
        this.elGamalService = elGamalService;
        this.storeService = storeService;
        this.primitivesService = primitivesService;
    }

    /**
     * Generates new {@link ElGamalCredentialDataPack} for given credential
     * properties
     * 
     * @param properties
     *            the properties
     * @param parameters
     *            the encryption parameters
     * @param length
     *            the key lengh
     * @return the generated data pack.
     * @throws GeneralCryptoLibException
     *             failed to generate the data pack.
     * @throws IOException
     */
    public ElGamalCredentialDataPack generate(
            CredentialProperties properties,
            ElGamalEncryptionParameters parameters, int length)
            throws GeneralCryptoLibException {
        ElGamalKeyPair keyPair =
            generateElGamalKeyPair(parameters, length);
        CryptoAPIScytlKeyStore keyStore = storeService.createKeyStore();
        char[] password = generatePassword();
        String alias = getElGamalPrivateKeyAlias(properties);
        keyStore.setElGamalPrivateKeyEntry(alias, keyPair.getPrivateKeys(),
            password);

        ElGamalCredentialDataPack pack = new ElGamalCredentialDataPack();
        pack.setKeyPair(keyPair);
        pack.setKeyStore(keyStore);
        pack.setPassword(password);
        return pack;
    }

    private ElGamalKeyPair generateElGamalKeyPair(
            ElGamalEncryptionParameters parameters, int length)
            throws GeneralCryptoLibException {
        CryptoAPIElGamalKeyPairGenerator generator =
            elGamalService.getElGamalKeyPairGenerator();
        return generator.generateKeys(parameters, length);
    }

    private char[] generatePassword() throws GeneralCryptoLibException {
        CryptoAPIRandomString random =
            primitivesService.get32CharAlphabetCryptoRandomString();
        return random.nextRandom(Constants.KEYSTORE_PW_LENGTH)
            .toCharArray();
    }

    private String getElGamalPrivateKeyAlias(
            CredentialProperties properties) {
        return properties.getAlias().getOrDefault("privateKey",
            "elegamalprivatekey");
    }
}
