/*
 * 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.ov.mixing.core.shuffle;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

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

import com.scytl.ov.mixing.shuffle.Permutation;

public class PermutatorTest {

    private static Permutator<Integer> _target = new Permutator<>();

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

    @Test
    public void givenNullListWhenPermutateThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("An initialized list, with at least 1 elemement must be received");

        int[] permutationArray = {2, 0, 1, 3 };
        Permutation permutation = new Permutation(permutationArray);

        List<Integer> unshuffledList = null;

        _target.permutate(unshuffledList, permutation);
    }

    @Test
    public void givenEmptyListWhenPermutateThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("An initialized list, with at least 1 elemement must be received");

        int[] permutationArray = {2, 0, 1, 3 };
        Permutation permutation = new Permutation(permutationArray);

        List<Integer> unshuffledList = new ArrayList<>();

        _target.permutate(unshuffledList, permutation);
    }

    @Test
    public void givenNullPermutationWhenPermutateThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("An initialized permutation must be received");

        int[] unshuffledArray = {777, 888, 666, 999 };

        List<Integer> unshuffledList = asList(unshuffledArray);

        Permutation permutation = null;

        _target.permutate(unshuffledList, permutation);
    }

    @Test
    public void givenPermutationSmallerThanListWhenPermutateThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The sizes of the list of elements and the permutation must be the same");

        int[] unshuffledArray = {777, 888, 666, 999 };
        int[] permutationArray = {2, 0, 1 };

        List<Integer> unshuffledList = asList(unshuffledArray);

        Permutation permutation = new Permutation(permutationArray);

        _target.permutate(unshuffledList, permutation);
    }

    @Test
    public void givenPermutationLargerThanListWhenPermutateThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The sizes of the list of elements and the permutation must be the same");

        int[] unshuffledArray = {777, 888, 666, 999 };
        int[] permutationArray = {2, 0, 1, 3, 4 };

        List<Integer> unshuffledList = asList(unshuffledArray);

        Permutation permutation = new Permutation(permutationArray);

        _target.permutate(unshuffledList, permutation);
    }

    @Test
    public void givenPermutationWithInvalidValueThenException() {

        expectedEx.expect(IllegalArgumentException.class);
        expectedEx.expectMessage("The given permutation contains values which are outside the valid range");

        int[] unshuffledArray = {777, 888, 666, 999 };
        int[] permutationArray = {2, 0, 1, 4 };
        int[] expectedShuffledArray = {666, 777, 888, 999 };

        List<Integer> unshuffledList = asList(unshuffledArray);
        List<Integer> expectedList = asList(expectedShuffledArray);

        Permutation permutation = new Permutation(permutationArray);

        List<Integer> shuffledList = _target.permutate(unshuffledList, permutation);

        assertEquals(expectedList, shuffledList);
    }

    @Test
    public void whenShuffleThenExpectedList() {

        int[] unshuffledArray = {777, 888, 666, 999 };
        int[] permutationArray = {2, 0, 1, 3 };
        int[] expectedShuffledArray = {666, 777, 888, 999 };

        List<Integer> unshuffledList = asList(unshuffledArray);
        List<Integer> expectedList = asList(expectedShuffledArray);

        Permutation permutation = new Permutation(permutationArray);

        List<Integer> shuffledList = _target.permutate(unshuffledList, permutation);

        assertEquals(expectedList, shuffledList);
    }

    private List<Integer> asList(int[] array) {

        return Arrays.stream(array).boxed().collect(Collectors.toList());
    }
}
