package sushi.application.pages.input;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
import org.apache.wicket.extensions.markup.html.repeater.tree.AbstractTree;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.io.IClusterable;
import sushi.FileUtils;
import sushi.application.components.form.WarnOnExitForm;
import sushi.application.components.tree.SushiAttributeTreeExpansion;
import sushi.application.components.tree.SushiAttributeTreeExpansionModel;
import sushi.application.components.tree.SushiAttributeTreeProvider;
import sushi.application.components.tree.SushiMultiSelectTree;
import sushi.application.pages.AbstractSushiPage;
import sushi.application.pages.main.MainPage;
import sushi.event.SushiEventType;
import sushi.event.attribute.SushiAttribute;
import sushi.event.attribute.SushiAttributeTree;
import sushi.event.attribute.SushiAttributeTypeEnum;
import sushi.eventhandling.Broker;
import sushi.xml.importer.XMLParsingException;
import sushi.xml.importer.XSDParser;
public class XSDEventTypeCreator extends AbstractSushiPage{
private TextField<String> eventTypeNameTextField;
private String filePath;
private SushiEventType importedEventType;
private SushiAttributeTree eventTypeAttributesTree;
private List<String> leafPathes = new ArrayList<String>();
private DropDownChoice<String> timestampDropDownChoice;
private String timestampXPath;
private SushiMultiSelectTree<SushiAttribute> tree;
private TextFieldDefaultValues textFieldDefaultValues;
private Form<Void> layoutForm;
private AbstractSushiPage xsdEventTypeCreator;
private SushiAttribute timestamp;
private AjaxCheckBox importTimeCheckBox;
private Boolean eventTypeUsingImportTime = false;
@SuppressWarnings("serial")
public XSDEventTypeCreator(PageParameters parameters) {
super();
this.xsdEventTypeCreator = this;
layoutForm = new WarnOnExitForm("layoutForm");
add(layoutForm);
filePath = parameters.get("filePath").toString();
String schemaName = FileUtils.getFileNameWithoutExtension(filePath);
try {
importedEventType = XSDParser.generateEventTypeFromXSD(filePath, schemaName);
} catch (XMLParsingException e1) {
getFeedbackPanel().error(e1.getMessage());
} catch (RuntimeException e2) {
getFeedbackPanel().error(e2.getMessage());
}
eventTypeAttributesTree = importedEventType.getValueTypeTree();
// timestamp must be a root attribute
for (SushiAttribute element : eventTypeAttributesTree.getLeafAttributes()) {
if (element.getType() == SushiAttributeTypeEnum.DATE) {
leafPathes.add(element.getXPath());
}
}
if (leafPathes.isEmpty()) {
eventTypeUsingImportTime = true;
} else {
timestampXPath = leafPathes.get(0);
}
textFieldDefaultValues = new TextFieldDefaultValues();
setDefaultModel(new CompoundPropertyModel<TextFieldDefaultValues>(textFieldDefaultValues));
eventTypeNameTextField = new TextField<String>("eventTypeNameTextField");
layoutForm.add(eventTypeNameTextField);
importTimeCheckBox = new AjaxCheckBox("importTimeCheckBox", new PropertyModel<Boolean>(this, "eventTypeUsingImportTime")) {
@Override
protected void onUpdate(AjaxRequestTarget target) {
if (eventTypeUsingImportTime) {
tree.getSelectedElements().remove(timestamp);
timestampDropDownChoice.setEnabled(false);
} else {
tree.getSelectedElements().add(timestamp);
timestampDropDownChoice.setEnabled(true);
}
target.add(tree);
target.add(timestampDropDownChoice);
}
};
timestampDropDownChoice = new DropDownChoice<String>("timestampDropDownChoice", new PropertyModel<String>(this, "timestampXPath"), leafPathes);
timestampDropDownChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
@Override
protected void onUpdate(AjaxRequestTarget target) {
tree.getSelectedElements().remove(timestamp);
if (timestamp.hasParent()) {
deselectTreeElement(timestamp.getParent());
}
timestamp = eventTypeAttributesTree.getAttributeByXPath(timestampXPath);
tree.getSelectedElements().add(timestamp);
if (timestamp.hasParent()) {
selectTreeElement(timestamp.getParent());
}
target.add(tree);
}
});
if (leafPathes.isEmpty()) {
importTimeCheckBox.setEnabled(false);
timestampDropDownChoice.setEnabled(false);
}
importTimeCheckBox.setOutputMarkupId(true);
timestampDropDownChoice.setOutputMarkupId(true);
layoutForm.add(importTimeCheckBox);
layoutForm.add(timestampDropDownChoice);
renderTree();
buildButtons();
}
private void selectTreeElement(SushiAttribute element) {
tree.getSelectedElements().add(element);
if (element.hasParent()) {
selectTreeElement(element);
}
}
private void deselectTreeElement(SushiAttribute element) {
ArrayList<SushiAttribute> children = element.getChildren();
boolean hasChildren = false;
for (SushiAttribute child : children) {
if (tree.getSelectedElements().contains(child)) {
hasChildren = true;
}
}
if (!hasChildren) {
tree.getSelectedElements().remove(element);
if (element.hasParent()) {
deselectTreeElement(element.getParent());
}
}
}
protected void renderTree() {
tree = new SushiMultiSelectTree<SushiAttribute>("eventTypeTree", new SushiAttributeTreeProvider(eventTypeAttributesTree.getRoots()), new SushiAttributeTreeExpansionModel()) {
@Override
protected void toggle(SushiAttribute element, AbstractTree<SushiAttribute> tree, final AjaxRequestTarget target) {
if (eventTypeUsingImportTime || !element.equals(timestamp)) {
if (element.getType() != null) {
super.toggle(element, tree, target);
} else {
ArrayList<SushiAttribute> children = element.getChildren();
boolean hasChildren = false;
for (SushiAttribute child : children) {
if (selectedElements.contains(child)) {
hasChildren = true;
}
}
if (hasChildren) {
selectedElements.add(element);
} else {
selectedElements.remove(element);
}
tree.updateNode(element, target);
}
if (element.hasParent()) {
toggle(element.getParent(), tree, target);
}
}
}
};
if (!leafPathes.isEmpty()) {
timestamp = eventTypeAttributesTree.getAttributeByXPath(leafPathes.get(0));
tree.getSelectedElements().add(timestamp);
}
SushiAttributeTreeExpansion.get().expandAll();
tree.setOutputMarkupId(true);
layoutForm.add(tree);
}
private void buildButtons() {
AjaxButton selectAllButton = new AjaxButton("selectAllButton") {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
tree.getSelectedElements().addAll(eventTypeAttributesTree.getAttributes());
target.add(tree);
}
};
layoutForm.add(selectAllButton);
AjaxButton unselectAllButton = new AjaxButton("unselectAllButton") {
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
tree.getSelectedElements().clear();
if (!eventTypeUsingImportTime) {
tree.getSelectedElements().add(timestamp);
}
target.add(tree);
}
};
layoutForm.add(unselectAllButton);
Button confirmButton = new Button("confirmButton") {
@Override
public void onSubmit() {
Set<SushiAttribute> selectedNodes = tree.getSelectedElements();
eventTypeAttributesTree.retainAllAttributes(selectedNodes);
try {
importedEventType.setTypeName(eventTypeNameTextField.getModelObject());
if (eventTypeUsingImportTime) {
importedEventType.setTimestampName(XSDParser.GENERATED_TIMESTAMP_COLUMN_NAME);
} else {
String timestampName = timestamp.getAttributeExpression();
importedEventType.setTimestampName(timestampName);
if (!timestamp.hasParent()) {
eventTypeAttributesTree.removeRoot(timestamp);
importedEventType.setValueTypeTree(eventTypeAttributesTree);
}
timestamp.removeAttribute();
}
if (SushiEventType.findByTypeName(importedEventType.getTypeName()) != null) {
xsdEventTypeCreator.getFeedbackPanel().error("Event type " + importedEventType.getTypeName() + " already exists");
return;
}
System.out.println(importedEventType);
Broker.send(importedEventType);
PageParameters pageParameters = new PageParameters();
pageParameters.add("successFeedback", "Event type " + importedEventType.getTypeName() + " has been created");
setResponsePage(MainPage.class, pageParameters);
} catch (RuntimeException e) {
e.printStackTrace();
xsdEventTypeCreator.getFeedbackPanel().error("Event type has not been created. See output console for more details.");
}
}
};
layoutForm.add(confirmButton);
}
private class TextFieldDefaultValues implements IClusterable {
private static final long serialVersionUID = 1L;
public String eventTypeNameTextField = FileUtils.getFileNameWithoutExtension(filePath);
@Override
public String toString()
{
return "eventTypeNameTextField = '" + eventTypeNameTextField + "'";
}
public String getEventTypeNameTextField() {
return eventTypeNameTextField;
}
public void setEventTypeNameTextField(String eventTypeNameTextField) {
this.eventTypeNameTextField = eventTypeNameTextField;
}
}
}