package pipe.gui.widgets;
import pipe.controllers.ArcController;
import uk.ac.imperial.pipe.animation.AnimationUtils;
import uk.ac.imperial.pipe.models.petrinet.PetriNet;
import uk.ac.imperial.pipe.models.petrinet.Place;
import uk.ac.imperial.pipe.parsers.FunctionalResults;
import uk.ac.imperial.pipe.parsers.FunctionalWeightParser;
import uk.ac.imperial.pipe.parsers.PetriNetWeightParser;
import uk.ac.imperial.pipe.parsers.StateEvalVisitor;
import uk.ac.imperial.state.State;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
/**
* Editor for modifying arc properties
*/
@SuppressWarnings("serial")
public class ArcFunctionEditor extends JPanel {
/**
* Petri net arc belongs to
*/
private PetriNet petriNet;
/**
* dialog for messages
*/
private EscapableDialog rootPane;
/**
* Arc controller
*/
private ArcController<?, ?> arcController;
/**
* Token id
*/
private String token;
/**
* Editor panel
*/
private ArcWeightEditorPanel weightEditorPanel;
/**
* Constructor
* @param weightEditorPanel panel
* @param guiDialog dialog
* @param petriNet Petr net
* @param arcController controller
* @param token currently selected token
*/
public ArcFunctionEditor(ArcWeightEditorPanel weightEditorPanel, EscapableDialog guiDialog, PetriNet petriNet,
ArcController<?, ?> arcController, String token) {
this.weightEditorPanel = weightEditorPanel;
this.petriNet = petriNet;
rootPane = guiDialog;
this.arcController = arcController;
this.token = token;
init();
}
/**
* Initializes the editor
*/
private void init() {
final JTextArea function = new JTextArea();
function.setText(arcController.getWeightForToken(token));
JScrollPane scrollPane = new JScrollPane(function);
scrollPane.setBorder(javax.swing.BorderFactory.createTitledBorder("Weight expression input:"));
JPanel north = new JPanel();
north.setBorder(javax.swing.BorderFactory.createTitledBorder("Places input:"));
Collection<String> placeNames = new LinkedList<>();
for (Place place : petriNet.getPlaces()) {
placeNames.add(place.getName());
}
JComboBox places = new JComboBox(placeNames.toArray());
north.add(places);
JPanel south = new JPanel(new FlowLayout());
JButton okbutton = new JButton("OK");
JButton helpbutton = new JButton("Help");
okbutton.addActionListener(new ArcOKAction(function));
helpbutton.addActionListener(new java.awt.event.ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
String help = "Operators supported:\r\n" +
"+\r\n" +
"-\r\n" +
"*\r\n" +
"/\r\n" +
"max()\r\n" +
"min()\r\n" +
"ceil()\r\n" +
"floor()\r\n" +
"cap(place_name)";
JOptionPane.showMessageDialog(null, help);
}
});
south.add(okbutton);
south.add(helpbutton);
places.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
JComboBox cb = (JComboBox) evt.getSource();
String placeName = (String) cb.getSelectedItem();
function.replaceSelection(placeName);
}
});
this.setLayout(new BorderLayout());
this.add(north, BorderLayout.NORTH);
this.add(scrollPane, BorderLayout.CENTER);
this.add(south, BorderLayout.SOUTH);
this.setSize(100, 100);
this.setVisible(true);
}
/**
* Exits the editor
*/
private void exit() {
rootPane.setVisible(false);
}
/**
* Concatenates a list of errors into a single string
*
* @param errors to be concatenated
* @return single string representation of the error, which is just the errors
* appended together and separated via a comma.
*/
private String concatenateErrors(List<String> errors) {
StringBuilder builder = new StringBuilder();
for (String error : errors) {
builder.append(error).append(", ");
}
return builder.toString();
}
/**
* Action performed when OK is pressed on the arc editor.
*
* Saves the properties
*/
private final class ArcOKAction implements ActionListener {
/**
* functional expression
*/
private final JTextArea function;
/**
* Constructor
* @param function arc functional expression
*/
private ArcOKAction(JTextArea function) {
this.function = function;
}
/**
* Tries to parse the functional expression to determine its validity
* @param e event
*/
@Override
public void actionPerformed(ActionEvent e) {
String func = function.getText();
if (func == null || func.equals("")) {
exit();
return;
}
State state = AnimationUtils.getState(petriNet);
StateEvalVisitor evalVisitor = new StateEvalVisitor(petriNet, state);
FunctionalWeightParser<Double> parser = new PetriNetWeightParser(evalVisitor, petriNet);
FunctionalResults<Double> results = parser.evaluateExpression(func);
if (!results.hasErrors()) {
weightEditorPanel.setWeight(func, token);
} else {
List<String> errors = results.getErrors();
String concatenated = concatenateErrors(errors);
JOptionPane.showMessageDialog(null, concatenated);
return;
}
exit();
}
}
}