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

import javax.script.ScriptException;

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

import com.scytl.products.ov.commons.correctness.builder.options.VotingOptionCorrectnessBuilder;
import com.scytl.products.ov.commons.correctness.feedback.CorrectnessFeedback;
import com.scytl.products.ov.commons.correctness.internal.CorrectnessEvaluator;
import com.scytl.products.ov.commons.correctness.internal.OptionCorrectnessEvaluator;

public class OptionCorrectnessTest {

	private static final Logger LOGGER = LoggerFactory.getLogger(OptionCorrectnessTest.class);
	private CorrectnessEvaluator<String> ce = new OptionCorrectnessEvaluator(LOGGER, true);

	@Test
	public void no_rule_list_test() throws NoSuchMethodException, ScriptException {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] selections = { "vo1", "vo3" };
		LOGGER.info(cb.build());
		CorrectnessFeedback checkCorrectness = new OptionCorrectnessEvaluator(LOGGER, cb, true)
				.checkCorrectness(Arrays.asList(selections));
		Assert.assertTrue(checkCorrectness.getResult());
	}

	@Test
	public void fail_wrong_correctness_test() throws NoSuchMethodException, ScriptException {
		VotingOptionCorrectnessBuilder cb = new WrongCorrectnessBuilder();
		String[] selections = { "vo1", "vo3" };
		LOGGER.info(cb.build());
		CorrectnessFeedback checkCorrectness = new OptionCorrectnessEvaluator(LOGGER, cb, false)
				.checkCorrectness(Arrays.asList(selections));
		Assert.assertFalse(checkCorrectness.getResult());
		Assert.assertNull(checkCorrectness.getErrors());
	}

	@Test
	public void fail_wrong_correctness_2_test() throws NoSuchMethodException, ScriptException {
		VotingOptionCorrectnessBuilder cb = new WrongCorrectnessBuilder();
		String[] selections = { "vo1", "vo3" };
		LOGGER.info(cb.build());
		CorrectnessFeedback checkCorrectness = new OptionCorrectnessEvaluator(LOGGER)
				.checkCorrectness(Arrays.asList(selections), cb);
		Assert.assertFalse(checkCorrectness.getResult());
		Assert.assertNull(checkCorrectness.getErrors());
	}

	@Test
	public void min_max_single_list_test_with_weird_characters() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections = { "\n \r \t=? \\ \"\"vo1 \u06A0\u0AA0\u42B0\uFFFFFF1", "vo2", "vo3" };
		String[] selections = { "\n \r \t=? \\ \"\"vo1 \u06A0\u0AA0\u42B0\uFFFFFF1", "vo3" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections)).withMaxSelection(2).withMinSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections), cb);
		Assert.assertTrue(checkCorrectness.getResult());
		Assert.assertNull(checkCorrectness.getErrors());
	}

	@Test
	@Ignore
	public void fail_incorrect_value_single_list_test() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections = { "vo1", "vo2", "vo3" };
		String[] selections = { "vo1", "vo5" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections)).withMaxSelection(2).withMinSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections), cb);
		Assert.assertFalse(checkCorrectness.getResult());
		Assert.assertTrue(checkCorrectness.getErrors().get(0).getErrorType().equals(CorrectnessError.SELECTION_ERROR));
	}

	@Test
	@Ignore
	public void fail_incorrect_value_double_list_test() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections1 = { "vo1", "vo2", "vo3" };
		String[] avaiableSelections2 = { "vo4", "vo5", "vo6" };
		String[] selections = { "vo5", "vo1", "vo2", "vo3", "vo8" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections1)).withMinSelection(2).finish()
				.withSelectionCorrectness("list2").withVotingOptions((Arrays.asList(avaiableSelections2)))
				.withMinSelection(1).withMaxSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections), cb);
		Assert.assertFalse(checkCorrectness.getResult());
		Assert.assertTrue(checkCorrectness.getErrors().get(0).getErrorType().equals(CorrectnessError.SELECTION_ERROR));
	}

	@Test
	public void fail_insufficient_min_double_list_test() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections1 = { "vo1", "vo2", "vo3" };
		String[] avaiableSelections2 = { "vo4", "vo5", "vo6" };
		String[] selections = { "vo5" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections1)).withMaxSelection(2).withMinSelection(1).finish()
				.withSelectionCorrectness("list2").withVotingOptions((Arrays.asList(avaiableSelections2)))
				.withMinSelection(1).withMaxSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections), cb);
		Assert.assertFalse(checkCorrectness.getResult());
		Assert.assertTrue(checkCorrectness.getErrors().get(0).getErrorType().equals(CorrectnessError.MIN_ERROR));
	}

	@Test
	public void double_list_without_minvalue_for_first_list_test() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections1 = { "vo1", "vo2", "vo3" };
		String[] avaiableSelections2 = { "vo4", "vo5", "vo6" };
		String[] selections = { "vo1", "vo5" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections1)).withMaxSelection(1).finish()
				.withSelectionCorrectness("list2").withVotingOptions((Arrays.asList(avaiableSelections2)))
				.withMinSelection(1).withMaxSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections), cb);
		Assert.assertTrue(checkCorrectness.getResult());
		Assert.assertNull(checkCorrectness.getErrors());
	}

	@Test
	public void double_list_without_max_value_for_first_list_test() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections1 = { "vo1", "vo2", "vo3" };
		String[] avaiableSelections2 = { "vo4", "vo5", "vo6" };
		String[] selections = { "vo5", "vo1", "vo2", "vo3" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections1)).withMinSelection(2).finish()
				.withSelectionCorrectness("list2").withVotingOptions((Arrays.asList(avaiableSelections2)))
				.withMinSelection(1).withMaxSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections), cb);
		Assert.assertTrue(checkCorrectness.getResult());
		Assert.assertNull(checkCorrectness.getErrors());
	}

	@Test
	public void min_max_double_list_test() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections1 = { "vo1", "vo2", "v\"o3" };
		String[] avaiableSelections2 = { "vo4", "vo5", "vo6" };
		String[] selections1 = { "vo1", "v\"o3", "vo5" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections1)).withMaxSelection(2).withMinSelection(1).finish()
				.withSelectionCorrectness("list2").withVotingOptions((Arrays.asList(avaiableSelections2)))
				.withMinSelection(1).withMaxSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections1), cb);
		Assert.assertTrue(checkCorrectness.getResult());
		Assert.assertNull(checkCorrectness.getErrors());
	}

	@Test
	public void fail_min_max_double_list_test_max_exceeded() {
		VotingOptionCorrectnessBuilder cb = new VotingOptionCorrectnessBuilder();
		String[] avaiableSelections1 = { "vo1", "vo2", "vo3" };
		String[] avaiableSelections2 = { "vo4", "vo5", "vo6" };
		String[] selections1 = { "vo1", "vo3", "vo5", "vo6" };
		VotingOptionCorrectnessBuilder correctness = cb.withSelectionCorrectness("list1")
				.withVotingOptions(Arrays.asList(avaiableSelections1)).withMaxSelection(2).withMinSelection(1).finish()
				.withSelectionCorrectness("list2").withVotingOptions((Arrays.asList(avaiableSelections2)))
				.withMinSelection(1).withMaxSelection(1).finish();
		LOGGER.info(correctness.build());
		CorrectnessFeedback checkCorrectness = ce.checkCorrectness(Arrays.asList(selections1), cb);
		Assert.assertFalse(checkCorrectness.getResult());
		Assert.assertTrue(checkCorrectness.getErrors().get(0).getErrorType().equals(CorrectnessError.MAX_ERROR));
	}

}
