package ua.ansymo.hintco.test

import java.util.Map
import org.junit.Ignore
import org.junit.Test
import ua.ansymo.hintco.CandidateSpaceGenerator
import ua.ansymo.hintco.CandidatesGenerator
import ua.ansymo.hintco.ConstraintChecker
import ua.ansymo.hintco.CosimUnitInstance
import ua.ansymo.hintco.FmuLoader
import ua.ansymo.hintco.IOutputProcessor
import ua.ansymo.hintco.ModelStorage
import ua.ansymo.hintco.OutputPortInstance
import ua.ansymo.hintco.OutputProcessor
import ua.ansymo.hintco.RootCandidateScenario
import ua.ansymo.hintco.SingleCosimRunner
import ua.ansymo.hintco.VariantProcessor
import ua.ansymo.hintco.VariantValidator

import static org.junit.Assert.*

class CandidateSpaceGeneratorTest {
	val generator = new CandidateSpaceGenerator()
	val loader = new ModelStorage()
	
	@Test
	def void createDefaultCandidateSpaceTest(){
		val src = loader.loadCandidates("instances/create_default_candidate_space_test.xmi")
		generator.createDefaultCandidateSpace(src)
		loader.storeCandidates("instances/generated/create_default_candidate_space_test.xmi", src)
	}
	
	@Test
	def void loadHintsModelTest(){
		val contractSet = loader.loadContractSet("instances/case_study_contract.xmi")
		assertNotNull(contractSet)
	}
	
	@Test
	def void duplicateScenarioTest(){
		val candidates = loader.loadCandidates("instances/case_study_double_loop.xmi")
		val src  = candidates.candidates.head
		val copy = generator.duplicateScenario(candidates.candidates.head)
		assertFalse(src === copy)
		assertFalse(src.cosimunits.head === copy.cosimunits.head)
		assertTrue(src.cosimunits.head.identifier == copy.cosimunits.head.identifier)
		val scrOutPort = (src.cosimunits.head as CosimUnitInstance).ports.head as OutputPortInstance
		val copyOutPort = (copy.cosimunits.head as CosimUnitInstance).ports.head as OutputPortInstance
		assertFalse(scrOutPort === copyOutPort)
		assertTrue(scrOutPort.identifier == copyOutPort.identifier)
		assertFalse(scrOutPort.valueTo.head === copyOutPort.valueTo.head)
		assertTrue(scrOutPort.valueTo.head.identifier == copyOutPort.valueTo.head.identifier)
	}
	
	@Test
	def void generateSoftwareHintsTest(){
		val contractSet = loader.loadContractSet("instances/case_study_contract.xmi")
		val candidates = loader.loadCandidates("instances/case_study_double_loop.xmi")
		generator.createCandidateSpace(contractSet, candidates)
		val newScenario = candidates.candidates.last
		assertTrue(newScenario.cosimunits.filter[u | u.identifier != "DLoopController_FixedEuler_1Em6"]
										.forall[u | u.adaptation !== null]
		)
	}
	
	@Test
	def void endToEndWaterTankTest(){
		val resultsDirPath = "results-gen/waterTankTest"
		val candidates = loader.loadCandidates("instances/watertanks.xmi")
		val contractSet = loader.loadContractSet("instances/watertanks_ctrl.xmi")
		generator.createCandidateSpace(contractSet, candidates)
		val runner = new SingleCosimRunner(new OutputProcessor(resultsDirPath), new FmuLoader)
		val variantGen = new CandidatesGenerator(new ConstraintChecker,new VariantValidator, new VariantProcessor(runner))
		variantGen.createVariantTree(candidates)
		variantGen.generateVariants(candidates, 5)
		runner.close()
	}
	
	@Test
	@Ignore // Only works on windows
	def void endToEndBoeingTest(){
		val candidates = loader.loadCandidates("instances/case_study_double_loop.xmi")
		val contractSet = loader.loadContractSet("instances/case_study_contract.xmi")
		generator.createCandidateSpace(contractSet, candidates)
		
		val mockOutputP = new IOutputProcessor{
			var variantID = null
			override initialize(RootCandidateScenario scenario, String vID) {
				variantID = vID
				println("Processing Variant: " + variantID)
			}
			
			override setOutputs(int i, double d, Map<OutputPortInstance, Double> map) {
			}
			
			override terminate() {
				println("Processing Variant: " + variantID + "... DONE")
				variantID = null
			}
			
		}
		
		val runner = new SingleCosimRunner(mockOutputP, new FmuLoader)
		val variantGen = new CandidatesGenerator(new ConstraintChecker,new VariantValidator, new VariantProcessor(runner))
		variantGen.createVariantTree(candidates)
		variantGen.generateVariants(candidates, 1)
		runner.close()
	}
}