/*
 * 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.mixnet.commons.proofs.bg.config;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.io.IOException;
import java.math.BigInteger;

import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.impl.Exponent;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;
import com.scytl.products.ov.mixnet.commons.exceptions.InvalidInputException;
import com.scytl.products.ov.mixnet.commons.homomorphic.Cryptosystem;
import com.scytl.products.ov.mixnet.commons.homomorphic.impl.GjosteenElGamal;
import com.scytl.products.ov.mixnet.commons.tools.GroupTools;

public class ProofsGeneratorConfigurationParamsTest {

    private static int _matrixM;

    private static int _matrixN;

    private static Cryptosystem _cryptosystem;

    private static int _numIterations;

    private static int _mu;

    private static ZpSubgroup group;

    private static ProofsGeneratorConfigurationParams _proofsGeneratorConfigurationParams;

    @Rule
    public ExpectedException exception = ExpectedException.none();

    @BeforeClass
    public static void setUp() throws IOException {

        group = createGroup();

        final Exponent[] privateKeyExponentArray = createPrivateKeyArray(group.getQ());

        _matrixM = 8;

        _matrixN = 32;

        _cryptosystem = new GjosteenElGamal(group, privateKeyExponentArray);

        _numIterations = 0;

        _proofsGeneratorConfigurationParams = new ProofsGeneratorConfigurationParams(_matrixM, _matrixN, _cryptosystem,
            _numIterations, _mu, group);
    }

    private static Exponent[] createPrivateKeyArray(final BigInteger order) {

        try {

            final Exponent privateKeyExponent = new Exponent(order, new BigInteger("5"));
            return new Exponent[] {privateKeyExponent };

        } catch (GeneralCryptoLibException ex) {
            throw new CryptoLibException(ex);
        }
    }

    private static ZpSubgroup createGroup() {

        final BigInteger p = new BigInteger("23");
        final BigInteger q = new BigInteger("11");
        return GroupTools.createGroupWithRandomGenerator(p, q);
    }

    @Test
    public void return_the_cryptosystem() {

        final Cryptosystem returnedCryptosystem = _proofsGeneratorConfigurationParams.getCryptosystem();

        String errorMsg = "The returned cryptosystem as null";
        assertNotNull(errorMsg, returnedCryptosystem);

        errorMsg = "The returned cryptosystem is not configured for the expected number of messages";
        assertEquals(errorMsg, _proofsGeneratorConfigurationParams.getCryptosystem().getNumberOfMessages(),
            returnedCryptosystem.getNumberOfMessages());
    }

    // un-ignore it when reduction is supported.
    // {@see ParallelShuffleReductionProofIT}
    @Ignore
    @Test
    public void return_the_apply_reduction() {

        String errorMsg = "The apply reduction value was not the expected value";
        assertEquals(errorMsg, true, _proofsGeneratorConfigurationParams.applyReduction());
    }

    @Test
    public void return_not_apply_reduction() {

        String errorMsg = "The apply reduction value was not the expected value";
        assertEquals(errorMsg, false, _proofsGeneratorConfigurationParams.applyReduction());
    }

    @Test
    public void return_the_number_of_iterations() {

        String errorMsg = "The number of iterations was not the expected value";
        assertEquals(errorMsg, _numIterations, _proofsGeneratorConfigurationParams.getNumIterations());
    }

    @Test
    public void return_the_mu() {

        String errorMsg = "The mu was not the expected value";
        assertEquals(errorMsg, _mu, _proofsGeneratorConfigurationParams.getMu());
    }

    @Test
    public void return_the_matrix_dimensions() {

        String errorMsg = "The m was not the expected value";
        assertEquals(errorMsg, _matrixM, _proofsGeneratorConfigurationParams.getMatrixDimensions().getNumberOfRows());

        errorMsg = "The n was not the expected value";
        assertEquals(errorMsg, _matrixN,
            _proofsGeneratorConfigurationParams.getMatrixDimensions().getNumberOfColumns());
    }

    @Test
    public void return_the_group_params() {

        String errorMsg = "The group params was not the expected value";

        assertEquals(errorMsg, group, _proofsGeneratorConfigurationParams.getZpGroupParams());
    }

    @Test
    public void throw_exception_when_set_to_use_reduction() {

        exception.expect(InvalidInputException.class);
        exception.expectMessage("Number of iterations > 0 is currently not supported.");

        new ProofsGeneratorConfigurationParams(_matrixM, _matrixN, _cryptosystem, 1, _mu, group);

    }
}
