/*
 * 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.commons.tools;

import static org.junit.Assert.assertEquals;

import java.util.List;

import org.apache.commons.lang3.NotImplementedException;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.scytl.ov.mixing.commons.beans.IntPair;

public class IntegerPairCalculatorTest {

    private final IntPairCalculator intPairCalculator = new IntPairCalculator();

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

    @Test
    public void compute_all_two_addends_from_a_given_correct_number() {

        final int number = 100;

        final List<IntPair> partitions = intPairCalculator.computeTwoAddendsCombinations(number);

        for (final IntPair partition : partitions) {

            assertEquals(partition.getLeft() + partition.getRight(), number);
        }
    }

    @Test
    public void compute_all_two_addends_from_a_given_negative_number() {

        final int number = -100;

        final List<IntPair> partitions = intPairCalculator.computeTwoAddendsCombinations(number);

        for (final IntPair partition : partitions) {

            assertEquals(partition.getLeft() + partition.getRight(), number);
        }
    }

    @Test
    public void compute_all_two_addends_from_a_max_positive_value() {

        exception.expect(IllegalArgumentException.class);
        exception.expectMessage("The given number should be a value between MAX and MIN Integer value (not included)");

        final int number = Integer.MAX_VALUE;

        intPairCalculator.computeTwoAddendsCombinations(number);
    }

    @Test
    public void compute_all_two_addends_from_a_min_positive_value() {

        exception.expect(IllegalArgumentException.class);
        exception.expectMessage("The given number should be a value between MAX and MIN Integer value (not included)");

        final int number = Integer.MIN_VALUE;

        intPairCalculator.computeTwoAddendsCombinations(number);
    }

    @Test
    public void generate_two_factors_from_a_given_correct_value() {

        int N = 24;

        List<IntPair> combinations = intPairCalculator.generateTwoFactorCombinationsWithoutOnes(N);

        Assert.assertEquals(6, combinations.size());

        Assert.assertEquals(12, combinations.get(0).getLeft());
        Assert.assertEquals(2, combinations.get(0).getRight());

        Assert.assertEquals(8, combinations.get(1).getLeft());
        Assert.assertEquals(3, combinations.get(1).getRight());

        Assert.assertEquals(6, combinations.get(2).getLeft());
        Assert.assertEquals(4, combinations.get(2).getRight());

        Assert.assertEquals(4, combinations.get(3).getLeft());
        Assert.assertEquals(6, combinations.get(3).getRight());

        Assert.assertEquals(3, combinations.get(4).getLeft());
        Assert.assertEquals(8, combinations.get(4).getRight());

        Assert.assertEquals(2, combinations.get(5).getLeft());
        Assert.assertEquals(12, combinations.get(5).getRight());
    }

    @Test
    public void generate_two_factors_from_zero_to_three_value() {

        for (int N = 0; N < 4; N++) {
            List<IntPair> combinations = intPairCalculator.generateTwoFactorCombinationsWithoutOnes(N);

            Assert.assertEquals(0, combinations.size());
        }
    }

    @Test
    public void generate_two_factors_from_four_value() {

        int N = 4;

        List<IntPair> combinations = intPairCalculator.generateTwoFactorCombinationsWithoutOnes(N);

        Assert.assertEquals(1, combinations.size());
        Assert.assertEquals(2, combinations.get(0).getLeft());
        Assert.assertEquals(2, combinations.get(0).getRight());
    }

    @Test
    public void generate_two_factors_from_a_max_positive_value() {

        exception.expect(IllegalArgumentException.class);
        exception.expectMessage("The given number should be a value between MAX and MIN Integer value (not included)");

        intPairCalculator.generateTwoFactorCombinationsWithoutOnes(Integer.MAX_VALUE);
    }

    @Test
    public void generate_two_factors_from_a_min_positive_value() {

        exception.expect(IllegalArgumentException.class);
        exception.expectMessage("The given number should be a value between MAX and MIN Integer value (not included)");

        intPairCalculator.generateTwoFactorCombinationsWithoutOnes(Integer.MIN_VALUE);
    }

    @Test
    public void generate_all_two_factors_from_a_positive_value_with_ones() {

        int N = 24;

        List<IntPair> combinations = intPairCalculator.generateAllTwoFactorCombinations(N);

        Assert.assertEquals(8, combinations.size());

        Assert.assertEquals(1, combinations.get(6).getLeft());
        Assert.assertEquals(24, combinations.get(6).getRight());

        Assert.assertEquals(24, combinations.get(7).getLeft());
        Assert.assertEquals(1, combinations.get(7).getRight());
    }

    @Test
    public void getMostOptimalCombinationTest() {

        int N = 24;

        exception.expect(NotImplementedException.class);
        exception.expectMessage("Pending code the table of best parameter values");

        intPairCalculator.getMostOptimalCombination(N);
    }
}
