/*
 * 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.cryptolib.elgamal.bean;

import static org.junit.Assert.assertEquals;

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

import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;

/**
 * Tests of ElGamalComputationsValues.
 */
public class ElGamalComputationsValuesTest {

    private static BigInteger _p;

    private static BigInteger _q;

    private static BigInteger _g;

    private static ZpSubgroup _group;

    @BeforeClass
    public static void setUp() throws GeneralCryptoLibException {

        _p = new BigInteger("23");

        _q = new BigInteger("11");

        _g = new BigInteger("2");

        _group = new ZpSubgroup(_g, _p, _q);
    }

    @Test
    public void testGetPhis() throws GeneralCryptoLibException {
        ZpGroupElement ge1 = new ZpGroupElement(BigInteger.ONE, _group);
        ZpGroupElement ge2 =
            new ZpGroupElement(new BigInteger("2"), _group);

        ZpGroupElement gamma = new ZpGroupElement(BigInteger.ONE, _group);

        List<ZpGroupElement> phis = new ArrayList<ZpGroupElement>();
        phis.add(ge1);
        phis.add(ge2);

        ElGamalComputationsValues values =
            new ElGamalComputationsValues(gamma, phis);

        Assert.assertEquals("The phis returned are not the phis expected",
            phis, values.getPhis());
    }

    @Test
    public void testConstructorWithFullList()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> ciphertext = new ArrayList<ZpGroupElement>();
        ZpGroupElement gamma = new ZpGroupElement(BigInteger.ONE, _group);

        List<ZpGroupElement> phis =
            getSamplePhisList(new BigInteger("2"), new BigInteger("4"));

        ciphertext.add(gamma);
        ciphertext.addAll(phis);

        ElGamalComputationsValues values =
            new ElGamalComputationsValues(ciphertext);

        Assert.assertEquals("The gamma has not the expected value", gamma,
            values.getGamma());
        Assert.assertEquals("The list of phis is not the expected one",
            phis, values.getPhis());
    }

    @Test
    public void testGetValuesMethod() throws GeneralCryptoLibException {

        List<ZpGroupElement> ciphertext = new ArrayList<ZpGroupElement>();

        ZpGroupElement gamma = createGamma();
        List<ZpGroupElement> phis = createPhis();

        ciphertext.add(gamma);
        ciphertext.addAll(phis);

        ElGamalComputationsValues values =
            new ElGamalComputationsValues(ciphertext);

        Assert.assertEquals("The gamma has not the expected value", gamma,
            values.getValues().get(0));
        Assert.assertEquals("The list of phis is not the expected one",
            phis,
            values.getValues().subList(1, values.getValues().size()));
        Assert.assertEquals(
            "The values list does not have the expected value",
            values.getValues().size(), values.getValues().size());
    }

    @Test
    public void testGetGamma() throws GeneralCryptoLibException {

        ZpGroupElement gamma = createGamma();
        List<ZpGroupElement> phis = createPhis();

        ElGamalComputationsValues preComputationValues =
            new ElGamalComputationsValues(gamma, phis);

        Assert.assertEquals(
            "The gamma returned by the get method is not the gamma expected",
            gamma, preComputationValues.getGamma());
    }

    @Test
    public void testGetPrePhis() throws GeneralCryptoLibException {

        ZpGroupElement gamma = new ZpGroupElement(BigInteger.ONE, _group);
        List<ZpGroupElement> phis = createPhis();

        ElGamalComputationsValues preComputationValues =
            new ElGamalComputationsValues(gamma, phis);

        Assert.assertEquals("The phis returned are not the phis expected",
            phis, preComputationValues.getPhis());
    }

    private List<ZpGroupElement> getSamplePhisList(
            final BigInteger phi1Value, final BigInteger phi2Value)
            throws GeneralCryptoLibException {
        List<ZpGroupElement> phis = new ArrayList<ZpGroupElement>();

        ZpGroupElement phi1 = new ZpGroupElement(phi1Value, _group);
        ZpGroupElement phi2 = new ZpGroupElement(phi2Value, _group);

        phis.add(phi1);
        phis.add(phi2);

        return phis;
    }

    private List<ZpGroupElement> createPhis()
            throws GeneralCryptoLibException {
        ZpGroupElement ge1 = new ZpGroupElement(BigInteger.ONE, _group);
        ZpGroupElement ge2 =
            new ZpGroupElement(new BigInteger("2"), _group);

        List<ZpGroupElement> phis = new ArrayList<ZpGroupElement>();
        phis.add(ge1);
        phis.add(ge2);

        return phis;
    }

    private ZpGroupElement createGamma() throws GeneralCryptoLibException {
        ZpGroupElement gamma = new ZpGroupElement(BigInteger.ONE, _group);
        return gamma;
    }

    @Test
    public void testJsonSerialization() throws GeneralCryptoLibException {

        List<ZpGroupElement> ciphertext = new ArrayList<ZpGroupElement>();

        ZpGroupElement gamma = new ZpGroupElement(BigInteger.ONE, _group);
        List<ZpGroupElement> phis =
            getSamplePhisList(new BigInteger("6"), new BigInteger("8"));

        ciphertext.add(gamma);
        ciphertext.addAll(phis);

        ElGamalComputationsValues values =
            new ElGamalComputationsValues(ciphertext);

        String jsonStr = values.toJson();

        ElGamalComputationsValues reconstrucedValues =
            ElGamalComputationsValues.fromJson(jsonStr);

        assertEquals(reconstrucedValues, values);
    }
}
