/*
 * 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 static org.junit.Assert.assertTrue;

public class PermutationGeneratorTest {

    private static PermutationGenerator permutationGenerator;

    private static int NUM_LIST_ELEMENTS;

    @BeforeClass
    public static void setUp() {

        permutationGenerator = new PermutationGenerator();

        NUM_LIST_ELEMENTS = 10000;
    }

    /**
     * A permutated list contains the same elements as the original list, but
     * with each element in a random position in the permutated list. Before
     * performing a permutation, it is not known how many elements in the
     * original list will be in the same position in the permutated list. There
     * are NO requirements that a certain percentage of the elements must be in
     * a different position for a permutation to be valid. However in most
     * permutations, the vast majority (or all) of the elements will be in a
     * different position.
     * <p>
     * It is reasonable to expect that most elements will have "changed"
     * position. This is not a requirement of a permutation, it is simply an
     * expectation of what will happen in the vast majority of permutations. If
     * this expectation is not met, then the probability that there is a problem
     * with the software is much greater than the probability that a valid
     * permutation has been created. For this reason (not because it is a real
     * requirement of a valid permutation), we check that a minimum number of
     * elements have changed position.
     */
    @Test
    public void levelOfChangesInGeneratedPermutationReachReasonableExpectation() {

        final int[] intArray = createSequentialIntArray();
        final Permutation originalPermutation = new Permutation(intArray);

        final Permutation permutation =
                permutationGenerator.generate(NUM_LIST_ELEMENTS);

        final String errorMsg =
                "Expected that the number of elements with different positions in the permutated array would be greater.";
        assertTrue(
                errorMsg,
                maxNumElementsInSamePositionNotExceeded(originalPermutation,
                        permutation));
    }

    private int[] createSequentialIntArray() {

        final int[] list = new int[NUM_LIST_ELEMENTS];
        for (int i = 0; i < NUM_LIST_ELEMENTS; i++) {
            list[i] = i;
        }
        return list;
    }

    private boolean maxNumElementsInSamePositionNotExceeded(
            final Permutation originalPerm, final Permutation permutation) {

        final int numElementsInOriginalPosition =
                getNumElementsInOriginalPosition(originalPerm, permutation);

        return numElementsInOriginalPosition <= NUM_LIST_ELEMENTS / 5;
    }

    private int getNumElementsInOriginalPosition(final Permutation list1,
                                                 final Permutation list2) {

        int matchesFound = 0;

        final int list1Size = list1.getLength();

        for (int i = 0; i < list1Size; i++) {
            if (list1.destinationOf(i) == list2.destinationOf(i)) {
                matchesFound++;
                break;
            }
        }

        return matchesFound;
    }
}
