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

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

import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.scytl.products.ov.commons.correctness.builder.attributes.AttributesCorrectnessBuilder;
import com.scytl.products.ov.commons.correctness.feedback.CorrectnessFeedback;
import com.scytl.products.ov.commons.correctness.feedback.ReportedError;;

public class CachedAttributeCorrectnessTest {

	private static final Logger LOGGER = LoggerFactory.getLogger(CachedAttributeCorrectnessTest.class);
	
	private final CachedAttributeCorrectnessEvaluator ce = new CachedAttributeCorrectnessEvaluator(LOGGER);
	
	@Test
	public void correctnessEvalutionMultipleTimesTest(){
		AttributesCorrectnessBuilder cb = new AttributesCorrectnessBuilder();
		cb.addContest("contestId1").addQuestion("attributeId1", 2).addQuestion("attributeId2", 1).build()
		.addContest("contestId2").addQuestion("attributeId3", 1).addQuestion("attributeId4", 2).build();
		String correctness = CorrectnessFeedback.decorateRule(cb, false);
	
		List<List<String>> selection1 = new ArrayList<>();
		String[] selectedVotingOption1Attributes = { "a", "b", "attributeId1" };
		String[] selectedVotingOption2Attributes = { "c", "d", "attributeId1" };
		String[] selectedVotingOption3Attributes = { "e", "f", "attributeId2" };
		String[] selectedVotingOption4Attributes = { "g", "h", "attributeId3" };
		String[] selectedVotingOption5Attributes = { "i", "j", "attributeId4" };
		String[] selectedVotingOption6Attributes = { "k", "l", "attributeId4" };
		selection1.add(Arrays.asList(selectedVotingOption1Attributes));
		selection1.add(Arrays.asList(selectedVotingOption2Attributes));
		selection1.add(Arrays.asList(selectedVotingOption3Attributes));
		selection1.add(Arrays.asList(selectedVotingOption4Attributes));
		selection1.add(Arrays.asList(selectedVotingOption5Attributes));
		selection1.add(Arrays.asList(selectedVotingOption6Attributes));
		
		List<List<String>> selection2 = new ArrayList<>();
		String[] selectedVotingOption1Attributes2 = { "a", "b", "attributeId1" };
		String[] selectedVotingOption2Attributes2 = { "c", "d", "attributeId2" };
		String[] selectedVotingOption3Attributes2 = { "e", "f", "attributeId2" };
		String[] selectedVotingOption4Attributes2 = { "g", "h", "attributeId3" };
		String[] selectedVotingOption5Attributes2 = { "i", "j", "attributeId3" };
		String[] selectedVotingOption6Attributes2 = { "k", "l", "attributeId4" };
		selection2.add(Arrays.asList(selectedVotingOption1Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption2Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption3Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption4Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption5Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption6Attributes2));
		
		for (int i = 0; i < 1000; i++) {
			CorrectnessFeedback evaluateCorrectness = ce.evaluateCorrectness(correctness, selection1);
			Assert.assertTrue(evaluateCorrectness.getResult());
			Assert.assertNull(evaluateCorrectness.getErrors());
			evaluateCorrectness = ce.evaluateCorrectness(correctness, selection2);
			Assert.assertFalse(evaluateCorrectness.getResult());
			Assert.assertNotNull(evaluateCorrectness.getErrors());
			int passcount = 0;
			for (int j = 0; j < 4; j++) {
				ReportedError errors = evaluateCorrectness.getErrors().get(j);
				CorrectnessError errorType = errors.getErrorType();
				String reference = errors.getReference();
				if("contestId2".equals(reference) && CorrectnessError.MAX_ERROR.equals(errorType)){
					passcount++;
				} else if("contestId2".equals(reference) && CorrectnessError.MIN_ERROR.equals(errorType)){
					passcount++;
				} else if("contestId1".equals(reference) && CorrectnessError.MAX_ERROR.equals(errorType)){
					passcount++;
				} else if("contestId1".equals(reference) && CorrectnessError.MIN_ERROR.equals(errorType)){
					passcount++;
				}
			}
			Assert.assertEquals(passcount, 4);
		}
	}

	@Test
	public void alternatingCorrectnessEvalutionMultipleTimesTest(){
		AttributesCorrectnessBuilder cb1 = new AttributesCorrectnessBuilder();
		cb1.addContest("contestId1").addQuestion("attributeId1", 2).addQuestion("attributeId2", 1).build()
		.addContest("contestId2").addQuestion("attributeId3", 1).addQuestion("attributeId4", 2).build();
		String correctness1 = CorrectnessFeedback.decorateRule(cb1, false);
	
		List<List<String>> selection1 = new ArrayList<>();
		String[] selectedVotingOption1Attributes = { "a", "b", "attributeId1" };
		String[] selectedVotingOption2Attributes = { "c", "d", "attributeId1" };
		String[] selectedVotingOption3Attributes = { "e", "f", "attributeId2" };
		String[] selectedVotingOption4Attributes = { "g", "h", "attributeId3" };
		String[] selectedVotingOption5Attributes = { "i", "j", "attributeId4" };
		String[] selectedVotingOption6Attributes = { "k", "l", "attributeId4" };
		selection1.add(Arrays.asList(selectedVotingOption1Attributes));
		selection1.add(Arrays.asList(selectedVotingOption2Attributes));
		selection1.add(Arrays.asList(selectedVotingOption3Attributes));
		selection1.add(Arrays.asList(selectedVotingOption4Attributes));
		selection1.add(Arrays.asList(selectedVotingOption5Attributes));
		selection1.add(Arrays.asList(selectedVotingOption6Attributes));
		

		AttributesCorrectnessBuilder cb2 = new AttributesCorrectnessBuilder();
		cb2.addContest("contestId1").addQuestion("attributeId1", 1).addQuestion("attributeId2", 2).build()
		.addContest("contestId2").addQuestion("attributeId3", 2).addQuestion("attributeId4", 1).build();
		String correctness2 = CorrectnessFeedback.decorateRule(cb2, false);
		
		List<List<String>> selection2 = new ArrayList<>();
		String[] selectedVotingOption1Attributes2 = { "a", "b", "attributeId1" };
		String[] selectedVotingOption2Attributes2 = { "c", "d", "attributeId2" };
		String[] selectedVotingOption3Attributes2 = { "e", "f", "attributeId2" };
		String[] selectedVotingOption4Attributes2 = { "g", "h", "attributeId3" };
		String[] selectedVotingOption5Attributes2 = { "i", "j", "attributeId3" };
		String[] selectedVotingOption6Attributes2 = { "k", "l", "attributeId4" };
		selection2.add(Arrays.asList(selectedVotingOption1Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption2Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption3Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption4Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption5Attributes2));
		selection2.add(Arrays.asList(selectedVotingOption6Attributes2));
		
		for (int i = 0; i < 1000; i++) {
			CorrectnessFeedback evaluateCorrectness = ce.evaluateCorrectness(correctness1, selection1);
			Assert.assertTrue(evaluateCorrectness.getResult());
			Assert.assertNull(evaluateCorrectness.getErrors());
			evaluateCorrectness = ce.evaluateCorrectness(correctness2, selection2);
			Assert.assertTrue(evaluateCorrectness.getResult());
			Assert.assertNull(evaluateCorrectness.getErrors());
		}
	}
}
