/*
 * 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.choices.codes;

import org.apache.commons.lang3.StringUtils;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.api.primitives.PrimitivesServiceAPI;
import com.scytl.products.ov.config.exceptions.CreateVotingCardSetException;
import com.scytl.products.ov.constants.Constants;
import com.scytl.products.ov.utils.ChecksumUtils;

/**
 * Generator of ballot casting keys consisting of a random number with a checksum.
 */
public final class RandomWithChecksumBallotCastingKeyGenerator implements BallotCastingKeyGenerator {

    private final PrimitivesServiceAPI primitivesService;

    private final ChecksumUtils checksumUtils;

    private final String allZeroBCK;

    public RandomWithChecksumBallotCastingKeyGenerator(final PrimitivesServiceAPI primitivesService,
            final ChecksumUtils checksumUtils) {

        this.primitivesService = primitivesService;
        this.checksumUtils = checksumUtils;
        this.allZeroBCK = constructStringAllZerosBCK();
    }

    private String constructStringAllZerosBCK() {

        StringBuilder strAllZeroBCK = new StringBuilder();
        for (int i = 0; i < Constants.NUM_DIGITS_BALLOT_CASTING_KEY_WITHOUT_CHECKSUM; i++) {
        	strAllZeroBCK.append("0");
        }
        return strAllZeroBCK.toString();
    }

    @Override
    public String generateBallotCastingKey() {

    	StringBuilder ballotCastingKeyWithoutChecksum = new StringBuilder();
    	String nonZeroBCK = getNonZeroBCK(Constants.NUM_DIGITS_BALLOT_CASTING_KEY_WITHOUT_CHECKSUM);
    	
		ballotCastingKeyWithoutChecksum.append(nonZeroBCK).append(checksumUtils.generate(nonZeroBCK));
		
        return ballotCastingKeyWithoutChecksum.toString();
    }

    private String getNonZeroBCK(final int numDigits) {

        String randomDigitsAsString = getRandomNumber(numDigits);

        while (randomDigitsAsString.equals(allZeroBCK)) {
            randomDigitsAsString = getRandomNumber(numDigits);
        }
        return randomDigitsAsString;
    }

    private String getRandomNumber(final int numDigits) {

        try {

            String randomNumber = primitivesService.getCryptoRandomInteger().nextRandom(numDigits).toString();
            return StringUtils.leftPad(randomNumber, numDigits, '0');

        } catch (GeneralCryptoLibException e) {
            throw new CreateVotingCardSetException(
                "Error while attempting to generate a random number with " + numDigits + " digits: " + e, e);
        }
    }
}
