/*
 * 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.mathematical.groups.activity;

import static org.junit.Assert.assertEquals;

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

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;

public class GroupElementsCompressorTest {

    private static BigInteger _p;

    private static BigInteger _q;

    private static BigInteger _g;

    private static ZpSubgroup _group;

    private static GroupElementsCompressor<ZpGroupElement> _compressor;

    @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);

        _compressor =
            new GroupElementsCompressor<ZpGroupElement>();
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenNullListWhenCompressThenExpectedValue()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> nullList = null;

        _compressor.compress(nullList);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenEmptyListWhenCompressThenExpectedValue()
            throws GeneralCryptoLibException {

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

        _compressor.compress(nullList);
    }

    @Test
    public void givenGroupAndListOfGroupElementsWhenCompressThenExpectedValue()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> groupMembers = getSmallList();

        ZpGroupElement compressedValue =
            _compressor.compress(groupMembers);

        ZpGroupElement expectedResult =
            new ZpGroupElement(new BigInteger("1"), _group);

        String errorMsg =
            "The generated compressed value was not the expected value";
        assertEquals(errorMsg, expectedResult, compressedValue);
    }

    @Test
    public void givenGroupAndListOfManyElementsWhenCompressThenExpectedValue()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> groupMembers = getLargeList();

        ZpGroupElement compressedValue =
            _compressor.compress(groupMembers);

        ZpGroupElement expectedResult =
            new ZpGroupElement(new BigInteger("12"), _group);

        String errorMsg =
            "The generated compressed value was not the expected value";
        assertEquals(errorMsg, expectedResult, compressedValue);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenNegativeNumRequiredElementsWhenBuildListThenException()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> originalList = getLargeList();
        int numRequired = -1;

        _compressor.buildListWithCompressedFinalElement(numRequired,
            originalList);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenNullListWhenBuildListThenException()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> nullList = null;
        int numRequired = 2;

        _compressor.buildListWithCompressedFinalElement(numRequired,
            nullList);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenEmptyListWhenBuildListThenException()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> emptyList =
            new ArrayList<ZpGroupElement>();
        int numRequired = 2;

        _compressor.buildListWithCompressedFinalElement(numRequired,
            emptyList);
    }

    @Test
    public void givenListAndNumRequiredElementWhenBuildNewListThenOK()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> originalList = getLargeList();
        int numRequired = 4;

        List<ZpGroupElement> newList =
            _compressor.buildListWithCompressedFinalElement(numRequired,
                originalList);

        List<ZpGroupElement> expectedList =
            getExpectedCompressedList();

        String errorMsg =
            "The created compressed list was not the expected size, expected: "
                + numRequired + ", but was: " + newList.size();
        assertEquals(errorMsg, numRequired, newList.size());

        errorMsg =
            "The created compressed did not have the expected values, expected: "
                + expectedList + ", but was: " + newList;
        assertEquals(errorMsg, expectedList, newList);
    }

    private List<ZpGroupElement> getSmallList()
            throws GeneralCryptoLibException {

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

        ZpGroupElement element_4 =
            new ZpGroupElement(new BigInteger("4"), _group);
        ZpGroupElement element_6 =
            new ZpGroupElement(new BigInteger("6"), _group);

        groupMembers.add(element_4);
        groupMembers.add(element_6);

        return groupMembers;
    }

    private List<ZpGroupElement> getLargeList()
            throws GeneralCryptoLibException {

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

        ZpGroupElement element_3 =
            new ZpGroupElement(new BigInteger("3"), _group);
        ZpGroupElement element_4 =
            new ZpGroupElement(new BigInteger("4"), _group);
        ZpGroupElement element_6 =
            new ZpGroupElement(new BigInteger("6"), _group);
        ZpGroupElement element_8 =
            new ZpGroupElement(new BigInteger("8"), _group);
        ZpGroupElement element_9 =
            new ZpGroupElement(new BigInteger("9"), _group);
        ZpGroupElement element_12 =
            new ZpGroupElement(new BigInteger("12"), _group);
        ZpGroupElement element_13 =
            new ZpGroupElement(new BigInteger("13"), _group);
        ZpGroupElement element_16 =
            new ZpGroupElement(new BigInteger("16"), _group);
        ZpGroupElement element_18 =
            new ZpGroupElement(new BigInteger("18"), _group);

        groupMembers.add(element_3);
        groupMembers.add(element_4);
        groupMembers.add(element_6);
        groupMembers.add(element_8);
        groupMembers.add(element_9);
        groupMembers.add(element_12);
        groupMembers.add(element_13);
        groupMembers.add(element_16);
        groupMembers.add(element_18);

        return groupMembers;
    }

    private List<ZpGroupElement> getExpectedCompressedList()
            throws GeneralCryptoLibException {

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

        ZpGroupElement element_3 =
            new ZpGroupElement(new BigInteger("3"), _group);
        ZpGroupElement element_4 =
            new ZpGroupElement(new BigInteger("4"), _group);
        ZpGroupElement element_6 =
            new ZpGroupElement(new BigInteger("6"), _group);

        groupMembers.add(element_3);
        groupMembers.add(element_4);
        groupMembers.add(element_6);
        groupMembers.add(element_4);

        return groupMembers;
    }
}
