package de.ugoe.cs.quest.plugin.jfc;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;

import junit.framework.TestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.mockito.Mockito.*;

import de.ugoe.cs.quest.eventcore.Event;
import de.ugoe.cs.quest.eventcore.IEventTarget;
import de.ugoe.cs.quest.eventcore.IEventType;
import de.ugoe.cs.quest.plugin.jfc.eventcore.JFCEventId;
import de.ugoe.cs.quest.plugin.jfc.guimodel.JFCGUIElement;
import de.ugoe.cs.quest.plugin.jfc.guimodel.JFCGUIElementSpec;
import de.ugoe.cs.util.console.TextConsole;

/**
 * The class <code>EFGReplayIDCalculatorTest</code> contains tests for the class
 * {@link <code>EFGReplayIDCalculator</code>}
 *
 * @pattern JUnit Test Case
 *
 * @author fabian.glaser
 *
 * @version $Revision$
 */
public class JFCReplayIDCalculatorTest extends TestCase {
	
	Set<String> knownIDs = new HashSet<String>();

	/**
	 * Construct new test instance
	 *
	 * @param name the test name
	 */
	public JFCReplayIDCalculatorTest(String name) {
		super(name);
	}

	/**
	 * Run the String calculateReplayID(JFCEvent) method test.
	 *
	 * @throws Exception
	 *
	 * @generatedBy CodePro at 7/30/12 4:58 PM
	 */
	@Test
	public void testCalculateReplayIDwithEvent()
		throws Exception {
		Collection<JFCEventId> ignoredEvents = new HashSet<JFCEventId>();
		ignoredEvents.add(JFCEventId.FOCUS_GAINED);
		JFCLogParser parser = new JFCLogParser(ignoredEvents);
		parser.parseFile(new File(ClassLoader.getSystemResource("freemind_trace.xml").getFile()));
		
		Collection<List<Event>> sequences = parser.getSequences();
		Event event = sequences.iterator().next().get(0);
		
		String result = new JFCReplayIDCalculator().calculateReplayID(event);
		assertEquals("e3561778462", result);
	}
	
	/**
	 * Run the String calculateReplayID(List<JFCGUIElementSpec>) method test.
	 *
	 * @throws Exception
	 */
	@Test
	public void testCalculateReplayIDwithGuiElementPath()
		throws Exception {
		Collection<JFCEventId> ignoredEvents = new HashSet<JFCEventId>();
		ignoredEvents.add(JFCEventId.FOCUS_GAINED);
		JFCLogParser parser = new JFCLogParser(ignoredEvents);
		parser.parseFile(new File(ClassLoader.getSystemResource("freemind_trace.xml").getFile()));
		
		Collection<List<Event>> sequences = parser.getSequences();
		Event event = sequences.iterator().next().get(0);
		
		List<JFCGUIElementSpec> guiElementPath = new ArrayList<JFCGUIElementSpec>();
		
		IEventTarget target = event.getTarget();
		JFCGUIElement jfcTarget = (JFCGUIElement) target;
		
		// extract element path
		JFCGUIElement currentTarget = jfcTarget;
		while (currentTarget != null){
			JFCGUIElementSpec currentSpec = (JFCGUIElementSpec) currentTarget.getSpecification();
			guiElementPath.add(0, currentSpec);
			currentTarget = (JFCGUIElement) currentTarget.getParent();
		}
		
		String result = new JFCReplayIDCalculator().calculateReplayID(guiElementPath);
		assertEquals("e3561778462", result);
	}
	
	/**
	 * Method to test if calculated IDs are included in guitar efg file.
	 * If not more than 75 % can be matched, test fails. 
	 *
	 * @throws Exception
	 */
	@Test
	public void testCalculateReplayIDAllEvents()
		throws Exception {
		// generate list of known replayIDs from guitar efg file
		File guiFile = new File(ClassLoader.getSystemResource("freemind.xml").getFile());
		JFCReplayIDValidator validator = new JFCReplayIDValidator(guiFile);
		
		// calculate replayIDs from trace file
		Collection<JFCEventId> ignoredEvents = new HashSet<JFCEventId>();
		ignoredEvents.add(JFCEventId.FOCUS_GAINED);
		JFCLogParser parser = new JFCLogParser(ignoredEvents);
		parser.parseFile(new File(ClassLoader.getSystemResource("freemind_trace3_corrected.xml").getFile()));
		JFCReplayIDCalculator calculator = new JFCReplayIDCalculator(validator);
		
		Set<String> generatedIDs = new HashSet<String>(); 
		
		Collection<List<Event>> sequences = parser.getSequences();
		
		assertTrue(sequences.size() > 0);
		
		Set<Event> seenEvents = new HashSet<Event>();
		
		for (List<Event> currentSequence: sequences){
			seenEvents.addAll(currentSequence);
		}
		
		for (Event currentEvent: seenEvents){
			String replayID = calculator.calculateReplayID(currentEvent);
			generatedIDs.add(replayID);
			System.out.println("Generated ID: " + replayID);
			System.out.println();
		}
		
		System.out.println();
		
		// check if generatedIDs are known
		int known = 0;
		for (String replayID: generatedIDs){
			if (validator.validateReplayID("w" + replayID.substring(1))){
				System.out.println(replayID + "\t is known.");
				known++;
			}
			else
				System.out.println(replayID + "\t is unknown.");
		}
		System.out.println();
		
		float percentage = (float) known/generatedIDs.size()*100;
		System.out.println(percentage + "% of the generated IDs are known.");
		
		assertTrue(percentage > 75);	
	}
	
	/**
	 * Method to test if calculated IDs are included in guitar efg file.
	 * If not more than 75 % can be matched, test fails.  
	 *
	 * @throws Exception
	 */
	@Test
	public void testCalculateReplayIDAllEventsArgo()
		throws Exception {
		// generate list of known replayIDs from guitar efg file
		File guiFile = new File(ClassLoader.getSystemResource("argo.xml").getFile());
		JFCReplayIDValidator validator = new JFCReplayIDValidator(guiFile);
		
		// calculate replayIDs from trace file
		Collection<JFCEventId> ignoredEvents = new HashSet<JFCEventId>();
		ignoredEvents.add(JFCEventId.FOCUS_GAINED);
		JFCLogParser parser = new JFCLogParser(ignoredEvents);
		parser.parseFile(new File(ClassLoader.getSystemResource("argouml_trace1_corrected.xml").getFile()));
		JFCReplayIDCalculator calculator = new JFCReplayIDCalculator(validator);
		
		Set<String> generatedIDs = new HashSet<String>(); 
		
		Collection<List<Event>> sequences = parser.getSequences();
		
		assertTrue(sequences.size() > 0);
		
		Set<Event> seenEvents = new HashSet<Event>();
		
		for (List<Event> currentSequence: sequences){
			seenEvents.addAll(currentSequence);
		}
		
		for (Event currentEvent: seenEvents){
			String replayID = calculator.calculateReplayID(currentEvent);
			generatedIDs.add(replayID);
			System.out.println("Generated ID: " + replayID);
			System.out.println();
		}
		
		System.out.println();
		
		// check if generatedIDs are known
		int known = 0;
		for (String replayID: generatedIDs){
			if (validator.validateReplayID("w" + replayID.substring(1))){
				System.out.println(replayID + "\t is known.");
				known++;
			}
			else
				System.out.println(replayID + "\t is unknown.");
		}
		System.out.println();
		
		float percentage = (float) known/generatedIDs.size()*100;
		System.out.println(percentage + "% of the generated IDs are known.");
		
		assertTrue(percentage > 75);	
	}
	
	
	/**
	 * Method to test if calculateReplayID throws the right exception when
	 * it is called with a target of the wrong type.
	 */
	@Test
	public void testCalculateReplayIDIllegalArgumentException(){
		try{
			JFCReplayIDCalculator calculator = new JFCReplayIDCalculator();
			Event event = new Event(mock(IEventType.class), mock(IEventTarget.class));
			
			calculator.calculateReplayID(event);
		
			fail("Expected IllegalArgumentException!");
		}
		catch(IllegalArgumentException e){
			System.out.println("Expected exception thrown.");
		}
	}

	/**
	 * Perform pre-test initialization.
	 *
	 * @throws Exception
	 *         if the initialization fails for some reason
	 *
	 * @generatedBy CodePro at 7/30/12 4:58 PM
	 */
	@Before
	public void setUp()
		throws Exception {
		    new TextConsole(Level.FINEST);
	}

	/**
	 * Perform post-test clean-up.
	 *
	 * @throws Exception
	 *         if the clean-up fails for some reason
	 *
	 * @generatedBy CodePro at 7/30/12 4:58 PM
	 */
	@After
	public void tearDown()
		throws Exception {
		// Add additional tear down code here
	}

	/**
	 * Launch the test.
	 *
	 * @param args the command line arguments
	 *
	 * @generatedBy CodePro at 7/30/12 4:58 PM
	 */
	public static void main(String[] args) {
		new org.junit.runner.JUnitCore().run(JFCReplayIDCalculatorTest.class);
	}
}

/*$CPS$ This comment was generated by CodePro. Do not edit it.
 * patternId = com.instantiations.assist.eclipse.pattern.testCasePattern
 * strategyId = com.instantiations.assist.eclipse.pattern.testCasePattern.junitTestCase
 * additionalTestNames = 
 * assertTrue = false
 * callTestMethod = true
 * createMain = false
 * createSetUp = false
 * createTearDown = false
 * createTestFixture = false
 * createTestStubs = false
 * methods = 
 * package = de.ugoe.cs.eventbench.efg
 * package.sourceFolder = EventBenchConsoleTest/src
 * superclassType = junit.framework.TestCase
 * testCase = EFGEventIDCalculatorTest
 * testClassType = de.ugoe.cs.eventbench.efg.EFGEventIDCalculator
 */