package de.prob2.ui.internal;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import com.google.inject.Inject;

import de.prob.formula.PredicateBuilder;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;

@FXMLInjected
public final class PredicateBuilderView extends VBox {
	private final class ValueCell extends TableCell<String, String> {
		private ValueCell() {
			super();
		}
		
		@Override
		protected void updateItem(final String item, final boolean empty) {
			super.updateItem(item, empty);
			
			if (empty || item == null) {
				this.setGraphic(null);
			} else {
				final TextField textField = new TextField(items.get(item));
				textField.textProperty().addListener((o, from, to) -> items.put(item, to));
				this.setGraphic(textField);
			}
		}
	}
	
	@FXML private TableView<String> table;
	@FXML private TableColumn<String, String> nameColumn;
	@FXML private TableColumn<String, String> valueColumn;
	@FXML private TextField predicateField;
	
	private final ObjectProperty<Node> placeholder;
	private final Map<String, String> items;
	
	@Inject
	private PredicateBuilderView(final StageManager stageManager) {
		super();
		
		this.placeholder = new SimpleObjectProperty<>(this, "placeholder", null);
		this.items = new LinkedHashMap<>();
		
		stageManager.loadFXML(this, "predicate_builder_view.fxml");
	}
	
	@FXML
	private void initialize() {
		this.table.placeholderProperty().bind(this.placeholderProperty());
		this.nameColumn.setCellValueFactory(features -> new SimpleStringProperty(features.getValue()));
		this.valueColumn.setCellValueFactory(features -> new SimpleStringProperty(features.getValue()));
		this.valueColumn.setCellFactory(col -> this.new ValueCell());
	}
	
	public ObjectProperty<Node> placeholderProperty() {
		return this.placeholder;
	}
	
	public Node getPlaceholder() {
		return this.placeholderProperty().get();
	}
	
	public void setPlaceholder(final Node placeholder) {
		this.placeholderProperty().set(placeholder);
	}
	
	public Map<String, String> getItems() {
		return new LinkedHashMap<>(this.items);
	}
	
	public void setItems(final Map<String, String> items) {
		this.items.clear();
		this.items.putAll(items);
		this.table.getItems().setAll(this.items.keySet());
	}
	
	public void setFromPredicate(final String predicate) {
		items.clear();
		final String[] predicates = predicate.split(" & ");
		for (int i = 0; i < predicates.length-1; i++) {
			final String part = predicates[i];
			final String[] assignment = part.split("=");
			final String lhs = assignment[0];
			final String rhs = assignment[1];
			items.put(lhs, rhs);
		}
		table.refresh();
		this.predicateField.setText(predicates[predicates.length-1]);
	}
	
	public String getPredicate() {
		final PredicateBuilder builder = new PredicateBuilder();
		final Map<String, String> filteredItems = new LinkedHashMap<>();
		this.items.forEach((k, v) -> {
			if (!v.isEmpty()) {
				filteredItems.put(k, v);
			}
		});
		builder.addMap(filteredItems);
		if (!this.predicateField.getText().isEmpty()) {
			builder.addList(Collections.singletonList(this.predicateField.getText()));
		}
		return builder.toString();
	}
	
	public void reset() {
		this.setFromPredicate("");
	}
}

@@ -24,16 +24,44 @@
 ernal;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -131,19 +131,100 @@
 va.util.
-Map
+List;%0Aimport java.util.Map;%0Aimport java.util.Set;%0Aimport java.util.stream.Collectors
 ;%0A%0Aimpor
@@ -2758,25 +2758,8 @@
 ) %7B%0A
-%09%09items.clear();%0A
 %09%09fi
@@ -2814,324 +2814,793 @@
 ;%0A%09%09
-for (int i = 0; i %3C predicates.length-1; i++) %7B%0A%09%09%09final String part = predicates%5Bi%5D;%0A%09%09%09final String%5B%5D assignment = part.split(%22=%22);%0A%09%09%09final String lhs = assignment%5B0%5D;%0A%09%09%09final String rhs = assignment%5B1%5D;%0A%09%09%09items.put(lhs, rhs);%0A%09%09%7D%0A%09%09table.refresh();%0A%09%09this.predicateField.setText(predicates%5Bpredicates.length-1%5D
+//Copy elements of items.keySet(), otherwise they will be lost due to items.clear()%0A%09%09Set%3CString%3E keys = items.keySet().stream().collect(Collectors.toSet());%0A%09%09int size = Math.min(items.size(), predicates.length);%0A%09%09List%3CString%3E restPredicates = new ArrayList%3C%3E();%0A%09%09items.clear();%0A%09%09for (int i = 0; i %3C size; i++) %7B%0A%09%09%09final String part = predicates%5Bi%5D;%0A%09%09%09final String%5B%5D assignment = part.split(%22=%22);%0A%09%09%09final String lhs = assignment%5B0%5D;%0A%09%09%09if(assignment.length %3C= 1 %7C%7C !keys.contains(lhs)) %7B%0A%09%09%09%09restPredicates.add(part);%0A%09%09%09%09continue;%0A%09%09%09%7D%0A%09%09%09final String rhs = assignment%5B1%5D;%0A%09%09%09items.put(lhs, rhs);%0A%09%09%7D%0A%09%09table.refresh();%0A%09%09for (int i = size; i %3C predicates.length; i++) %7B%0A%09%09%09restPredicates.add(predicates%5Bi%5D);%0A%09%09%7D%0A%09%09this.predicateField.setText(String.join(%22 & %22, restPredicates)
 );%0A%09

Update PredicateBuilderView