package sushi.application.pages.eventrepository.eventtypeeditor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.markup.html.form.palette.Palette;
import org.apache.wicket.extensions.markup.html.form.palette.component.Recorder;
import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.util.ListModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import sushi.application.components.form.BlockingAjaxButton;
import sushi.application.components.form.ConditionInputPanel;
import sushi.application.components.form.WarnOnExitForm;
import sushi.application.pages.AbstractSushiPage;
import sushi.application.pages.main.MainPage;
import sushi.event.EventTypeRule;
import sushi.event.SushiEvent;
import sushi.event.SushiEventType;
import sushi.event.attribute.SushiAttribute;
import sushi.event.collection.SushiMapTree;
import sushi.eventhandling.Broker;
import sushi.notification.SushiCondition;
/**
* This page allows the creation of new {@link SushiEventType}s from existing ones.
* @author micha
*/
public class ExistingEventTypeEditor extends Panel {
private static final long serialVersionUID = 1L;
private ConditionInputPanel conditionInput;
private TextField<String> eventTypeInput;
private Palette<SushiAttribute> relevantEventTypeColumnsPalette;
private AbstractSushiPage abstractSushiPage;
private CheckBoxMultipleChoice<SushiEventType> eventTypesCheckBoxMultipleChoice;
private List<SushiEventType> selectedEventTypes = new ArrayList<SushiEventType>();
private List<SushiAttribute> selectedEventTypeAttributes = new ArrayList<SushiAttribute>();
private List<SushiAttribute> commonCorrelationAttributes = new ArrayList<SushiAttribute>();
private List<SushiEventType> eventTypes = SushiEventType.findAll();
/**
* Constructor for a page to create new {@link SushiEventType}s from existing ones.
* @param id
* @param abstractSushiPage
*/
public ExistingEventTypeEditor(String id, AbstractSushiPage abstractSushiPage){
super(id);
this.abstractSushiPage = abstractSushiPage;
Form<Void> layoutForm = new WarnOnExitForm("layoutForm");
add(layoutForm);
layoutForm.add(addEventTypeInput());
layoutForm.add(addConditionInput());
layoutForm.add(addExistingEventTypeSelect());
layoutForm.add(addRelevantEventTypeColumnsPalette());
addButtonsToForm(layoutForm);
}
private Component addEventTypeInput() {
eventTypeInput = new TextField<String>("eventTypeInput", Model.of(""));
eventTypeInput.setOutputMarkupId(true);
return eventTypeInput;
}
private Component addConditionInput() {
conditionInput = new ConditionInputPanel("conditionInput", true);
conditionInput.setOutputMarkupId(true);
return conditionInput;
}
private Component addExistingEventTypeSelect() {
eventTypesCheckBoxMultipleChoice = new CheckBoxMultipleChoice<SushiEventType>("eventTypesCheckBoxMultipleChoice", new PropertyModel<ArrayList<SushiEventType>>(this, "selectedEventTypes"), eventTypes) {
@Override
protected boolean isDisabled(SushiEventType eventType, int index, String selected) {
// true for event types without matching attributes
if (selectedEventTypes.isEmpty()) {
return false;
} else {
for (SushiAttribute commonAttribute : commonCorrelationAttributes) {
if (eventType.getValueTypes().contains(commonAttribute)) {
return false;
}
}
return true;
}
}
};
eventTypesCheckBoxMultipleChoice.add(new AjaxFormChoiceComponentUpdatingBehavior() {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
commonCorrelationAttributes.clear();
if (!selectedEventTypes.isEmpty()) {
commonCorrelationAttributes.addAll(selectedEventTypes.get(0).getValueTypes());
for (SushiEventType actualEventType : selectedEventTypes) {
commonCorrelationAttributes.retainAll(actualEventType.getValueTypes());
}
}
conditionInput.setSelectedEventTypes(selectedEventTypes);
conditionInput.updateAttributesValues();
target.add(conditionInput.getConditionAttributeSelect());
target.add(conditionInput.getConditionValueSelect());
target.add(relevantEventTypeColumnsPalette);
target.add(eventTypesCheckBoxMultipleChoice);
}
});
eventTypesCheckBoxMultipleChoice.setOutputMarkupId(true);
return eventTypesCheckBoxMultipleChoice;
}
private Component addRelevantEventTypeColumnsPalette() {
IModel<List<? extends SushiAttribute>> eventTypeAttributeModel = new AbstractReadOnlyModel<List<? extends SushiAttribute>>() {
@Override
public List<SushiAttribute> getObject() {
//in the columnsPalette should only be attributes, that are contained in all selected event Types
Set<SushiAttribute> attributes = new HashSet<SushiAttribute>();
boolean first = true;
for (SushiEventType eventType : selectedEventTypes) {
if (eventType != null) {
if (first) {
attributes.addAll(eventType.getValueTypes());
first = false;
} else {
attributes.retainAll(eventType.getValueTypes());
}
}
}
return new ArrayList<SushiAttribute>(attributes);
}
};
relevantEventTypeColumnsPalette = new Palette<SushiAttribute>("relevantEventTypePalette",
new ListModel<SushiAttribute>(new ArrayList<SushiAttribute>()),
eventTypeAttributeModel,
new ChoiceRenderer(), 5, false) {
private static final long serialVersionUID = 1L;
protected Recorder newRecorderComponent() {
Recorder recorder = super.newRecorderComponent();
recorder.add(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
Iterator<SushiAttribute> selectedColumns = getSelectedChoices();
selectedEventTypeAttributes = new ArrayList<SushiAttribute>();
while(selectedColumns.hasNext()){
SushiAttribute eventTypeAttribute = selectedColumns.next();
selectedEventTypeAttributes.add(eventTypeAttribute);
}
}
});
return recorder;
}
};
relevantEventTypeColumnsPalette.setOutputMarkupId(true);
return relevantEventTypeColumnsPalette;
}
private void addButtonsToForm(Form layoutForm) {
AjaxButton clearButton = new AjaxButton("clearButton") {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form form) {
eventTypeInput.setModel(Model.of(""));
conditionInput.setSelectedEventTypes(new ArrayList());
target.add(conditionInput);
target.add(eventTypeInput);
}
};
layoutForm.add(clearButton);
AjaxButton deleteButton = new AjaxButton("deleteButton") {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form form) {
for(SushiEventType selectedEventType : selectedEventTypes){
selectedEventType.remove();
}
target.add(eventTypesCheckBoxMultipleChoice);
}
};
layoutForm.add(deleteButton);
BlockingAjaxButton createButton = new BlockingAjaxButton("createButton", layoutForm) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form form) {
String newEventTypeName = (String) eventTypeInput.getValue();
if(!newEventTypeName.isEmpty() && SushiEventType.findByTypeName(newEventTypeName) == null){
//create EventType
SushiEventType newEventType = new SushiEventType(newEventTypeName);
newEventType.addValueTypes(selectedEventTypeAttributes);
Broker.send(newEventType);
//create EventTypeRule
Set<SushiEventType> usedEventTypes = new HashSet<SushiEventType>();
for(SushiEventType selectedEventType: selectedEventTypes){
usedEventTypes.add(selectedEventType);
}
SushiCondition condition = conditionInput.getCondition();
EventTypeRule newEventTypeRule = new EventTypeRule(new ArrayList<SushiEventType>(usedEventTypes), condition, newEventType);
newEventTypeRule.save();
//execute on existing data
ArrayList<SushiEvent> newEvents = newEventTypeRule.execute();
Broker.send(newEvents);
target.add(eventTypesCheckBoxMultipleChoice);
PageParameters pageParameters = new PageParameters();
pageParameters.add("successFeedback", newEvents.size() + " events have been added to " + newEventTypeName);
setResponsePage(MainPage.class, pageParameters);
} else if (SushiEventType.getAllTypeNames().contains(newEventTypeName)) {
target.appendJavaScript("$.unblockUI();");
abstractSushiPage.getFeedbackPanel().error("Event type already exists.");
target.add(abstractSushiPage.getFeedbackPanel());
} else {
target.appendJavaScript("$.unblockUI();");
abstractSushiPage.getFeedbackPanel().error("You did not provide correct information.");
target.add(abstractSushiPage.getFeedbackPanel());
}
}
};
layoutForm.add(createButton);
}
}