/*
 * 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.shuffler.permutation;

import com.scytl.products.ov.mixnet.commons.beans.Permutation;
import org.junit.BeforeClass;
import org.junit.Test;

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

import static org.junit.Assert.assertEquals;

public class PermutatorTest {

    private static Permutator permutator;

    private static Permutation permutationTenElements1;

    private static Permutation permutationTenElements2;

    @BeforeClass
    public static void setUp() {

        permutator = new Permutator();

        permutationTenElements1 =
                new Permutation(new int[] { 5, 8, 3, 1, 6, 4, 7, 9, 0, 2 });

        permutationTenElements2 =
                new Permutation(new int[] { 2, 4, 9, 6, 5, 8, 0, 1, 7, 3 });
    }

    @Test(expected = IllegalArgumentException.class)
    public void givenNullListWhenPermutateThenException() {

        final int[] permutationArray = new int[] { 2, 1, 0, 4, 3 };

        final Permutation permutation = new Permutation(permutationArray);

        permutator.createPermutatedList(null, permutation);
    }

    @Test(expected = IllegalArgumentException.class)
    public void givenNullPermutationWhenPermutateThenException() {

        final List<BigInteger> list = generateOrderedList(5);

        permutator.createPermutatedList(list, null);
    }

    @Test(expected = IllegalArgumentException.class)
    public void givenListAndPermutationOfSizeOneWithInvalidRangeOfValuesThenException() {

        final int[] permutationArray = new int[] { 5 };

        final Permutation permutation = new Permutation(permutationArray);

        final List<BigInteger> list = generateOrderedList(1);

        permutator.createPermutatedList(list, permutation);
    }

    @Test
    public void givenListAndPermutationOfSizeOneThenOK() {

        final int[] permutationArray = new int[] { 0 };

        final Permutation permutation = new Permutation(permutationArray);

        final List<BigInteger> list = generateOrderedList(1);

        permutator.createPermutatedList(list, permutation);
    }

    @Test(expected = IllegalArgumentException.class)
    public void givenListSmallerThanPermutationWhenPermutateThenException() {

        final int[] permutationArray = new int[] { 2, 1, 0, 4, 3 };

        final Permutation permutation = new Permutation(permutationArray);

        final List<BigInteger> list = generateOrderedList(4);

        permutator.createPermutatedList(list, permutation);
    }

    @Test(expected = IllegalArgumentException.class)
    public void giveListLargerThanPermutationWhenPermutateThenException() {

        final int[] permutationArray = new int[] { 2, 1, 0, 4, 3 };

        final Permutation permutation = new Permutation(permutationArray);

        final List<BigInteger> list = generateOrderedList(6);

        permutator.createPermutatedList(list, permutation);
    }

    @Test
    public void whenApplyPermutationThenExpectedResult() {

        final int[] permutationArray = new int[] { 2, 1, 0, 4, 3 };

        final Permutation permutation = new Permutation(permutationArray);

        final List<BigInteger> list = generateOrderedList(5);

        final List<BigInteger> permutatedList =
                permutator.createPermutatedList(list, permutation);

        final List<BigInteger> expectedList =
                getResultAfterPermutationFiveElements();

        final String errorMsg =
                "Expected that list would make expected permutated list";
        assertEquals(errorMsg, expectedList, permutatedList);
    }

    @Test
    public void whenPermutateListTwiceThenExpectedResult() {

        final List<BigInteger> list = generateOrderedList(10);

        final List<BigInteger> permutatedList1 =
                permutator.createPermutatedList(list, permutationTenElements1);

        final List<BigInteger> permutatedList2 =
                permutator.createPermutatedList(permutatedList1,
                    permutationTenElements2);

        final List<BigInteger> expectedList = getResultAfterSecondPermutation();

        final String errorMsg =
                "Expected that list would make expected permutated list after second permutation";
        assertEquals(errorMsg, expectedList, permutatedList2);
    }

    private List<BigInteger> generateOrderedList(final int numElements) {

        final List<BigInteger> list = new ArrayList<>();

        for (int i = 0; i < numElements; i++) {
            list.add(BigInteger.valueOf( + i));
        }
        return list;
    }

    private List<BigInteger> getResultAfterPermutationFiveElements() {

        final List<BigInteger> list = new ArrayList<>();
        list.add(new BigInteger("2"));
        list.add(new BigInteger("1"));
        list.add(new BigInteger("0"));
        list.add(new BigInteger("4"));
        list.add(new BigInteger("3"));
        return list;
    }

    private List<BigInteger> getResultAfterSecondPermutation() {

        final List<BigInteger> list = new ArrayList<>();
        list.add(new BigInteger("3"));
        list.add(new BigInteger("6"));
        list.add(new BigInteger("2"));
        list.add(new BigInteger("7"));
        list.add(new BigInteger("4"));
        list.add(new BigInteger("0"));
        list.add(new BigInteger("5"));
        list.add(new BigInteger("8"));
        list.add(new BigInteger("9"));
        list.add(new BigInteger("1"));
        return list;
    }
}
