/*
 * 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 GroupElementsDividerTest {

    private static BigInteger _p;

    private static BigInteger _q;

    private static BigInteger _g;

    private static ZpSubgroup _group;

    private static GroupElementsDivider _divider;

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

        _divider = new GroupElementsDivider();
    }

    @Test
    public void givenGroupAndListOfGroupElementsWhenCompressThenExpectedValue()
            throws GeneralCryptoLibException {

        List<ZpGroupElement> list1 = getList1_4elements();

        List<ZpGroupElement> list2 = getList2_4elements();

        List<ZpGroupElement> combinedList =
            _divider.divide(list1, list2, _group);

        List<ZpGroupElement> expectedList =
            buildExpectedList();

        String errorMsg = "The created list is not the expected list";
        assertEquals(errorMsg, expectedList, combinedList);
    }

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

        List<ZpGroupElement> list1 = getList1_4elements();

        List<ZpGroupElement> list2 = getList2_4elements();

        _divider.divide(list1, list2, null);
    }

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

        List<ZpGroupElement> list1 = null;

        List<ZpGroupElement> list2 = getList_5elements();

        _divider.divide(list1, list2, _group);
    }

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

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

        List<ZpGroupElement> list2 = getList_5elements();

        _divider.divide(list1, list2, _group);
    }

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

        List<ZpGroupElement> list1 = getList_5elements();

        List<ZpGroupElement> list2 = null;

        _divider.divide(list1, list2, _group);
    }

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

        List<ZpGroupElement> list1 = getList_5elements();

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

        _divider.divide(list1, list2, _group);
    }

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

        List<ZpGroupElement> list1 = getList1_4elements();

        List<ZpGroupElement> list2 = getList_5elements();

        _divider.divide(list1, list2, _group);
    }

    private List<ZpGroupElement> buildExpectedList()
            throws GeneralCryptoLibException {

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

        ZpGroupElement element_8 =
            new ZpGroupElement(new BigInteger("8"), _group);
        ZpGroupElement element_4 =
            new ZpGroupElement(new BigInteger("4"), _group);
        ZpGroupElement element_12 =
            new ZpGroupElement(new BigInteger("12"), _group);

        groupMembers.add(element_8);
        groupMembers.add(element_4);
        groupMembers.add(element_12);
        groupMembers.add(element_12);

        return groupMembers;
    }

    private List<ZpGroupElement> getList1_4elements()
            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);
        ZpGroupElement element_8 =
            new ZpGroupElement(new BigInteger("8"), _group);
        ZpGroupElement element_9 =
            new ZpGroupElement(new BigInteger("9"), _group);

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

        return groupMembers;
    }

    private List<ZpGroupElement> getList2_4elements()
            throws GeneralCryptoLibException {

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

        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_12);
        groupMembers.add(element_13);
        groupMembers.add(element_16);
        groupMembers.add(element_18);

        return groupMembers;
    }

    private List<ZpGroupElement> getList_5elements()
            throws GeneralCryptoLibException {

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

        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);
        ZpGroupElement element_9 =
            new ZpGroupElement(new BigInteger("9"), _group);

        groupMembers.add(element_12);
        groupMembers.add(element_13);
        groupMembers.add(element_16);
        groupMembers.add(element_18);
        groupMembers.add(element_9);

        return groupMembers;
    }
}
