package nl.utwente.viskell.ui.components;
import java.util.Map;
import java.util.Optional;
import com.google.common.collect.ImmutableMap;
import javafx.scene.control.TextInputDialog;
import nl.utwente.viskell.ghcj.GhciSession;
import nl.utwente.viskell.ghcj.HaskellException;
import nl.utwente.viskell.haskell.type.Type;
import nl.utwente.viskell.haskell.type.TypeScope;
import nl.utwente.viskell.ui.ToplevelPane;
import nl.utwente.viskell.ui.serialize.Bundleable;
/** Block with a constant value that is editable as a plain text expression. */
public class ConstantBlock extends ValueBlock implements Bundleable {
private boolean hasValidValue;
public ConstantBlock(ToplevelPane pane) {
super("ValueBlock", pane, TypeScope.unique("x"));
this.setValue("undefined");
this.hasValidValue = false;
this.outputSpace.setVisible(false);
}
public ConstantBlock(ToplevelPane pane, Type type, String value, boolean hasValidValue) {
super("ValueBlock", pane, type);
this.setValue(value);
this.hasValidValue = hasValidValue;
}
@Override
protected ImmutableMap<String, Object> toBundleFragment() {
return ImmutableMap.of(
"value", getValue(),
"type", type.toString(), // TODO this seems to create some kind of UTF-8 problem
"hasValidValue", hasValidValue);
}
public static ConstantBlock fromBundleFragment(ToplevelPane pane, Map<String,Object> bundleFragment) throws ClassNotFoundException {
String value = (String)bundleFragment.get("value");
boolean hasValidValue = (Boolean)bundleFragment.get("hasValidValue");
if (hasValidValue) {
// Recover the type from the saved value.
try {
Type type = pane.getGhciSession().pullType(value, pane.getEnvInstance());
return new ConstantBlock(pane, type, value, true);
} catch (HaskellException e) {
// Should not happen as it was typechecked before saving.
}
}
// Constant with invalid value or bad type.
ConstantBlock block = new ConstantBlock(pane);
block.setValue(value);
return block;
}
public void editValue(Optional<String> startValue) {
TextInputDialog dialog = new TextInputDialog(startValue.orElse(this.getValue()));
dialog.setTitle("Edit constant block");
dialog.setHeaderText("Type a Haskell expression");
Optional<String> result = dialog.showAndWait();
result.ifPresent(value -> {
this.setValue(value);
GhciSession ghci = this.getToplevel().getGhciSession();
try {
Type type = ghci.pullType(value, this.getToplevel().getEnvInstance());
this.output.setExactRequiredType(type);
this.hasValidValue = true;
this.outputSpace.setVisible(true);
} catch (HaskellException e) {
this.hasValidValue = false;
this.outputSpace.setVisible(false);
}
this.initiateConnectionChanges();
});
}
@Override
public ConnectionAnchor getAssociatedAnchor() {
if (hasValidValue) {
return output;
} else {
return null;
}
}
@Override
public Optional<Block> getNewCopy() {
return Optional.of(new ConstantBlock(this.getToplevel(), this.output.binder.getFreshAnnotationType(), this.value.getText(), this.hasValidValue));
}
}