/*
 * 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.encryption.params.generation;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;
import com.scytl.cryptolib.mathematical.groups.utils.GroupUtils;
import com.scytl.cryptolib.primitives.primes.utils.PrimesUtils;

import java.math.BigInteger;
import java.util.List;

/**
 * Allows the generation of ElGamal data parameters.
 *
 * @see {@link ElGamalDataParameters}.
 */
public final class PrimeGroupMembersProvider {

    private final GroupUtils groupUtils;

    public PrimeGroupMembersProvider() {

        groupUtils = new GroupUtils();
    }

    /**
     * Generates an ElGamalDataParameters using the received encryption parameters and number of primes.
     *
     * @param numRequiredPrimes
     *            The number of required primes.
     * @param encryptionParameters
     *            The ElGamal encryption parameters to use.
     * @return An ElGamalDataParameters.
     * @throws GeneralCryptoLibException
     */
    public List<BigInteger> generateDataParameters(final int numRequiredPrimes,
            final ElGamalEncryptionParameters encryptionParameters) throws GeneralCryptoLibException {

        ZpSubgroup quadraticResidueGroup =
            new ZpSubgroup(encryptionParameters.getG(), encryptionParameters.getP(), encryptionParameters.getQ());

        List<BigInteger> listOfPrimes = PrimesUtils.getPrimesList();

        validate(listOfPrimes.size(), numRequiredPrimes);

		return groupUtils.extractNumberOfGroupMembersFromListOfPossibleMembers(listOfPrimes, quadraticResidueGroup,
				numRequiredPrimes);
    }

    /**
     * Validates that the number of primes is not less than a minimum number of required primes.
     * <P>
     * Note: we define the minimum number of primes as being:
     * <ul>
     * <li>'number voting options' * 2</li>
     * </ul>
     * This is an estimate of the number of required primes, but it is not a guarantee that this number of primes will
     * allow the required number of group members to be found. In fact, it is likely that a larger number of primes will
     * be needed to ensure that the required number of groups elements is found.
     *
     * @param numPrimes
     *            The number of primes found.
     * @param minimumPrimesNeeded
     *            The minimum number of primes needed.
     * @throws IllegalArgumentException
     */
    private void validate(final int numPrimes, final int numVoteOptions) throws IllegalArgumentException {

        int minimumPrimesNeeded = numVoteOptions * 2;

        if (numPrimes < minimumPrimesNeeded) {
            throw new IllegalArgumentException(
                "The number of primes found in the file was too small. The mimum number of primes needed was "
                    + minimumPrimesNeeded + " but the number of primes found was " + numPrimes);
        }
    }
}
