package de.prob2.ui.animation.symbolic;

import de.prob.statespace.Trace;
import de.prob2.ui.animation.symbolic.testcasegeneration.TestCaseGenerationFormulaExtractor;
import de.prob2.ui.symbolic.SymbolicExecutionType;
import de.prob2.ui.symbolic.SymbolicFormulaItem;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class SymbolicAnimationFormulaItem extends SymbolicFormulaItem {

	private static final String MAX_DEPTH = "maxDepth";

	private static final String LEVEL = "level";

	private static final String OPERATIONS = "operations";

	private transient ListProperty<Trace> examples;

	private Map<String, Object> additionalInformation;

	public SymbolicAnimationFormulaItem(String name, SymbolicExecutionType type) {
		super(name, type);
		this.examples = new SimpleListProperty<>(FXCollections.observableArrayList());
		this.additionalInformation = new HashMap<>();
	}

	public SymbolicAnimationFormulaItem(String name, SymbolicExecutionType type, Map<String, Object> additionalInformation) {
		super(name, type);
		this.examples = new SimpleListProperty<>(FXCollections.observableArrayList());
		this.additionalInformation = additionalInformation;
	}

	public SymbolicAnimationFormulaItem(int maxDepth, int level) {
		super("MCDC:" + level + "/" + "DEPTH:" + maxDepth, SymbolicExecutionType.MCDC);
		this.examples = new SimpleListProperty<>(FXCollections.observableArrayList());
		this.additionalInformation = new HashMap<>();
		additionalInformation.put(MAX_DEPTH, maxDepth);
		additionalInformation.put(LEVEL, level);
	}

	public SymbolicAnimationFormulaItem(int maxDepth, List<String> operations) {
		super("OPERATION:" + String.join(",", operations) + "/" + "DEPTH:" + maxDepth, SymbolicExecutionType.COVERED_OPERATIONS);
		this.examples = new SimpleListProperty<>(FXCollections.observableArrayList());
		this.additionalInformation = new HashMap<>();
		additionalInformation.put(MAX_DEPTH, maxDepth);
		additionalInformation.put(OPERATIONS, operations);
	}

	@Override
	public void replaceMissingWithDefaults() {
		super.replaceMissingWithDefaults();
		if(this.examples == null) {
			this.examples = new SimpleListProperty<>(FXCollections.observableArrayList());
		} else {
			this.examples.setValue(FXCollections.observableArrayList());
		}
		if(this.additionalInformation == null) {
			this.additionalInformation = new HashMap<>();
		}
		if(type == SymbolicExecutionType.MCDC) {
			if(additionalInformation.get(MAX_DEPTH) == null || additionalInformation.get(LEVEL) == null) {
				int depth = TestCaseGenerationFormulaExtractor.extractDepth(this.code);
				int level = TestCaseGenerationFormulaExtractor.extractLevel(this.code);
				additionalInformation.put(MAX_DEPTH, depth);
				additionalInformation.put(LEVEL, level);
			}
		} else if(type == SymbolicExecutionType.COVERED_OPERATIONS) {
			if(additionalInformation.get(MAX_DEPTH) == null || additionalInformation.get(OPERATIONS) == null) {
				int depth = TestCaseGenerationFormulaExtractor.extractDepth(this.code);
				List<String> operations = TestCaseGenerationFormulaExtractor.extractOperations(this.code);
				additionalInformation.put(MAX_DEPTH, depth);
				additionalInformation.put(OPERATIONS, operations);
			}
		}
	}

	public ObservableList<Trace> getExamples() {
		return examples.get();
	}

	public ListProperty<Trace> examplesProperty() {
		return examples;
	}
	
	@Override
	public void reset() {
		this.initialize();
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj == this) {
			return true;
		}
		if (!(obj instanceof SymbolicAnimationFormulaItem)) {
			return false;
		}
		SymbolicAnimationFormulaItem otherItem = (SymbolicAnimationFormulaItem) obj;
		return otherItem.getName().equals(this.getName()) &&
				otherItem.getCode().equals(this.getCode()) &&
				otherItem.getType().equals(this.getType());
	}
	
	@Override
	public int hashCode() {
		 return Objects.hash(name, code, type);
	}

	public void setData(String name, String description, String code, SymbolicExecutionType type, Map<String, Object> additionalInformation) {
		super.setData(name, description, code, type);
		this.additionalInformation = additionalInformation;
	}

	public Object getAdditionalInformation(String key) {
		return additionalInformation.get(key);
	}

	public void putAdditionalInformation(String key, Object value) {
		additionalInformation.put(key, value);
	}
}

@@ -2615,24 +2615,247 @@
 pe.MCDC) %7B%0A%09
+%09%09replaceMissingMCDCOptionsByDefaults();%0A%09%09%7D else if(type == SymbolicExecutionType.COVERED_OPERATIONS) %7B%0A%09%09%09replaceMissingCoveredOperationsOptionsByDefaults();%0A%09%09%7D%0A%09%7D%0A%09%0A%09private void replaceMissingMCDCOptionsByDefaults() %7B%0A
 %09%09if(additio
@@ -2931,33 +2931,32 @@
 VEL) == null) %7B%0A
-%09
 %09%09%09int depth = T
@@ -3013,25 +3013,24 @@
 s.code);%0A%09%09%09
-%09
 int level = 
@@ -3084,33 +3084,32 @@
 (this.code);%0A%09%09%09
-%09
 additionalInform
@@ -3129,33 +3129,32 @@
 _DEPTH, depth);%0A
-%09
 %09%09%09additionalInf
@@ -3187,78 +3187,84 @@
 ;%0A%09%09
+%7D%0A
 %09%7D%0A%09
-%09%7D else if(type == SymbolicExecutionType.COVERED_OPERATIONS
+%0A%09private void replaceMissingCoveredOperationsOptionsByDefaults(
 ) %7B%0A%09%09
-%09
 if(a
@@ -3362,17 +3362,16 @@
 l) %7B%0A%09%09%09
-%09
 int dept
@@ -3434,17 +3434,16 @@
 .code);%0A
-%09
 %09%09%09List%3C
@@ -3527,25 +3527,24 @@
 s.code);%0A%09%09%09
-%09
 additionalIn
@@ -3576,17 +3576,16 @@
 depth);%0A
-%09
 %09%09%09addit
@@ -3634,13 +3634,8 @@
 s);%0A
-%09%09%09%7D%0A
 %09%09%7D%0A

Refactor SymbolicAnimationFormulaItem