package de.ugoe.cs.quest.coverage;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import de.ugoe.cs.quest.coverage.SequenceTools;
import de.ugoe.cs.quest.eventcore.Event;
import de.ugoe.cs.quest.usageprofiles.FirstOrderMarkovModel;
import de.ugoe.cs.quest.usageprofiles.IStochasticProcess;
import de.ugoe.cs.quest.usageprofiles.MockTrieBasedModel;

import org.junit.*;

import static org.junit.Assert.*;

/**
 * The class <code>SequenceToolsTest</code> contains tests for the class <code>{@link SequenceTools}</code>.
 *
 * @author Steffen Herbold
 * @version 1.0
 */
public class SequenceToolsTest {
	
	Collection<List<? extends Event<?>>> sequences;
	Set<List<? extends Event<?>>> subSequences;
	MockTrieBasedModel mockProcess;
	
	@Test
	public void testContainedSubSequences_1()
		throws Exception {
		int length = 2;

		Set<List<? extends Event<?>>> result = SequenceTools.containedSubSequences(sequences, length);

		assertNotNull(result);
		assertTrue(result.containsAll(subSequences));
		assertEquals(subSequences.size(), result.size());
	}
	
	@Test
	public void testContainedSubSequences_2()
		throws Exception {
		int length = 2;

		Set<List<? extends Event<?>>> result = SequenceTools.containedSubSequences(null, length);
		assertNotNull(result);
		assertTrue(result.isEmpty());
	}
	
	@Test(expected=java.security.InvalidParameterException.class)
	public void testContainedSubSequences_3()
		throws Exception {
		int length = 0;

		SequenceTools.containedSubSequences(sequences, length);
	}
	
	@Test(expected=java.security.InvalidParameterException.class)
	public void testContainedSubSequences_4()
		throws Exception {
		int length = -1;

		SequenceTools.containedSubSequences(sequences, length);
	}

	@Test
	public void testGenerateWeights_1()
		throws Exception {
		Map<List<? extends Event<?>>, Double> result = SequenceTools.generateWeights(mockProcess, subSequences);

		assertNotNull(result);
		Set<Entry<List<? extends Event<?>>, Double>> entrySet = result.entrySet();
		assertEquals(subSequences.size(),entrySet.size());
		for( Entry<List<? extends Event<?>>, Double> entry : entrySet ) {
			assertEquals(Double.valueOf(2.0d), entry.getValue());
			assertTrue(subSequences.contains(entry.getKey()));
		}
	}
	
	@Test
	public void testGenerateWeights_2()
		throws Exception {
		Map<List<? extends Event<?>>, Double> result = SequenceTools.generateWeights(null, subSequences);
		
		Set<Entry<List<? extends Event<?>>, Double>> entrySet = result.entrySet();
		assertEquals(subSequences.size(),entrySet.size());
		for( Entry<List<? extends Event<?>>, Double> entry : entrySet ) {
			assertEquals(Double.valueOf(0.0d), entry.getValue());
			assertTrue(subSequences.contains(entry.getKey()));
		}
	}
	
	@Test
	public void testGenerateWeights_3()
		throws Exception {
		Map<List<? extends Event<?>>, Double> result = SequenceTools.generateWeights(mockProcess, null);
		
		assertNotNull(result);
		assertTrue(result.isEmpty());
	}

	@Test
	public void testNumSequences_1()
		throws Exception {
		int length = 2;
		int expected = 49;

		long result = SequenceTools.numSequences(mockProcess, length);

		assertEquals(expected, result);
	}
	
	@Test
	public void testNumSequences_2()
		throws Exception {
		int length = 2;
		int expected = 49;

		long result = SequenceTools.numSequences(mockProcess, length);

		assertEquals(expected, result);
	}
	
	@Test(expected = java.security.InvalidParameterException.class )
	public void testNumSequences_3()
		throws Exception {
		int length = 0;

		SequenceTools.numSequences(mockProcess, length);
	}

	@Test(expected = java.security.InvalidParameterException.class )
	public void testNumSequences_4()
		throws Exception {
		IStochasticProcess process = new FirstOrderMarkovModel(new Random());
		int length = -1;

		SequenceTools.numSequences(process, length);
	}
	
	@Before
	public void setUp()
		throws Exception {
		sequences = new LinkedList<List<? extends Event<?>>>();
		List<Event<?>> sequence1 = new ArrayList<Event<?>>();
		sequence1.add(new Event<String>("a"));
		sequence1.add(new Event<String>("b"));
		sequence1.add(new Event<String>("r"));
		sequence1.add(new Event<String>("a"));
		List<Event<?>> sequence2 = new ArrayList<Event<?>>();
		sequence2.add(new Event<String>("c"));
		sequence2.add(new Event<String>("a"));
		sequence2.add(new Event<String>("d"));
		sequence2.add(new Event<String>("a"));
		sequence2.add(new Event<String>("b"));
		sequence2.add(new Event<String>("r"));
		sequence2.add(new Event<String>("a"));
		sequences.add(sequence1);
		sequences.add(sequence2);
		
		subSequences = new LinkedHashSet<List<? extends Event<?>>>();
		List<Event<?>> tmpList = new ArrayList<Event<?>>();
		tmpList.add(new Event<String>("a"));
		tmpList.add(new Event<String>("b"));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event<?>>();
		tmpList.add(new Event<String>("b"));
		tmpList.add(new Event<String>("r"));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event<?>>();
		tmpList.add(new Event<String>("r"));
		tmpList.add(new Event<String>("a"));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event<?>>();
		tmpList.add(new Event<String>("c"));
		tmpList.add(new Event<String>("a"));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event<?>>();
		tmpList.add(new Event<String>("a"));
		tmpList.add(new Event<String>("d"));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event<?>>();
		tmpList.add(new Event<String>("d"));
		tmpList.add(new Event<String>("a"));
		subSequences.add(tmpList);
		
		int markovOrder = 2;
		mockProcess = new MockTrieBasedModel(markovOrder, new Random());
		mockProcess.train(sequences);
	}

	public static void main(String[] args) {
		new org.junit.runner.JUnitCore().run(SequenceToolsTest.class);
	}
}