package aalgTest;

import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import org.junit.Assert;
import org.junit.Test;

import aalg.algebra.DlDomainParameters;
import aalg.algebra.MultiGroup;
import aalg.algebra.MultiMonoidElement;
import aalg.algebra.PrimeField;
import aalg.algebra.PrimeFieldElement;
import aalg.algebra.PrimeMultiGroupGenerator;
import aalg.algebra.RationalMultiMonoidGenerator;

public class MultiGroupTest {

	private static final BigInteger MIN_PRIME = BigInteger.valueOf(3);
	private static final long SEED = 123456789;
	private static final int MIN_VAL = -5;
	private static final int MAX_VAL = 5;
	private static final int MIN_PART_COUNT = 1;
	private static final int MAX_PART_COUNT = 2;

	private static class TestCase {
		public MultiGroup<PrimeFieldElement> group;
		public MultiMonoidElement<PrimeFieldElement> generator;
	};
	
	private final List<TestCase> testCaseList;
	
	public MultiGroupTest() {
		this.testCaseList = new LinkedList<TestCase>();
		
		generateGroup();
	}
	
	private void generateGroup() {
		for (int partCount = MIN_PART_COUNT; partCount <= MAX_PART_COUNT; partCount++) {
			final Random rnd = new Random(SEED);
			final RationalMultiMonoidGenerator rationalGenerator = new RationalMultiMonoidGenerator(partCount, MIN_VAL, MAX_VAL, rnd);
			final PrimeMultiGroupGenerator primeGenerator = new PrimeMultiGroupGenerator(rationalGenerator, MIN_PRIME, rnd);
			final DlDomainParameters<MultiMonoidElement<PrimeFieldElement>> domainParameters = primeGenerator.generate();
			
			final TestCase testCase = new TestCase();
			testCase.group = (MultiGroup<PrimeFieldElement>) domainParameters.getGroup();
			testCase.generator = domainParameters.getFullSubGroup().getGenerator();
			
			testCaseList.add(testCase);
		}
	}
	
	@Test
	public void testMultiGroup() {
		for (TestCase testCase: testCaseList) {
			final FiniteGroupTester<MultiMonoidElement<PrimeFieldElement>> tester = new FiniteGroupTester<MultiMonoidElement<PrimeFieldElement>>(testCase.group);
			tester.testGroup();
		}
	}

	@Test
	public void testGenerator() {
		for (TestCase testCase: testCaseList) {
			final MultiGroup<PrimeFieldElement> group = testCase.group;
			final MultiMonoidElement<PrimeFieldElement> generator = testCase.generator;
			
			MultiMonoidElement<PrimeFieldElement> element = group.getIdentity();
			BigInteger order = BigInteger.ZERO;
			
			do {
				element = group.operation(element, generator);
				order = order.add(BigInteger.ONE);
			} while (!element.equals(group.getIdentity()));
			
			Assert.assertEquals("Generator does not generate all elements", group.getOrder(), order);
		}
	}
	
}
