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.eventcore.StringEventType;
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<Event>> sequences;
	Set<List<Event>> subSequences;
	MockTrieBasedModel mockProcess;
	
	@Test
	public void testContainedSubSequences_1()
		throws Exception {
		int length = 2;

		Set<List<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<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<Event>, Double> result = SequenceTools.generateWeights(mockProcess, subSequences);

		assertNotNull(result);
		Set<Entry<List<Event>, Double>> entrySet = result.entrySet();
		assertEquals(subSequences.size(),entrySet.size());
		for( Entry<List<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<Event>, Double> result = SequenceTools.generateWeights(null, subSequences);
		
		Set<Entry<List<Event>, Double>> entrySet = result.entrySet();
		assertEquals(subSequences.size(),entrySet.size());
		for( Entry<List<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<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<Event>>();
		List<Event> sequence1 = new ArrayList<Event>();
		sequence1.add(new Event(new StringEventType("a")));
		sequence1.add(new Event(new StringEventType("b")));
		sequence1.add(new Event(new StringEventType("r")));
		sequence1.add(new Event(new StringEventType("a")));
		List<Event> sequence2 = new ArrayList<Event>();
		sequence2.add(new Event(new StringEventType("c")));
		sequence2.add(new Event(new StringEventType("a")));
		sequence2.add(new Event(new StringEventType("d")));
		sequence2.add(new Event(new StringEventType("a")));
		sequence2.add(new Event(new StringEventType("b")));
		sequence2.add(new Event(new StringEventType("r")));
		sequence2.add(new Event(new StringEventType("a")));
		sequences.add(sequence1);
		sequences.add(sequence2);
		
		subSequences = new LinkedHashSet<List<Event>>();
		List<Event> tmpList = new ArrayList<Event>();
		tmpList.add(new Event(new StringEventType("a")));
		tmpList.add(new Event(new StringEventType("b")));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event>();
		tmpList.add(new Event(new StringEventType("b")));
		tmpList.add(new Event(new StringEventType("r")));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event>();
		tmpList.add(new Event(new StringEventType("r")));
		tmpList.add(new Event(new StringEventType("a")));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event>();
		tmpList.add(new Event(new StringEventType("c")));
		tmpList.add(new Event(new StringEventType("a")));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event>();
		tmpList.add(new Event(new StringEventType("a")));
		tmpList.add(new Event(new StringEventType("d")));
		subSequences.add(tmpList);
		tmpList = new ArrayList<Event>();
		tmpList.add(new Event(new StringEventType("d")));
		tmpList.add(new Event(new StringEventType("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);
	}
}