package sushi.application.pages.monitoring.visualisation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.wicket.Component;
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.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
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.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.odlabs.wiquery.ui.slider.AjaxSlider;
import sushi.application.pages.eventrepository.eventtypeeditor.model.EventTypeNamesProvider;
import sushi.event.SushiEvent;
import sushi.event.SushiEventType;
import sushi.event.attribute.SushiAttribute;
import sushi.event.attribute.SushiAttributeTypeEnum;
import sushi.visualisation.SushiChartTypeEnum;
import sushi.visualisation.SushiChartConfiguration;
import de.agilecoders.wicket.markup.html.bootstrap.common.NotificationPanel;
/**
* This panel is used to configure and save a new @see SushiChartConfiguration Object
* This will create a new attribute chart.
*/
public class ChartConfigurationPanel extends Panel{
private static final long serialVersionUID = 1L;
private DropDownChoice<String> eventTypeSelect;
private DropDownChoice<SushiAttribute> attributeSelect;
private EventTypeNamesProvider eventTypeNameProvider = new EventTypeNamesProvider();
List<SushiAttribute> attributes = new ArrayList<SushiAttribute>();
private AttributeChartPage parentPage;
private String selectedEventTypeName = "";
private SushiAttribute selectedAttribute = null;
private String chartTitle = "";
private List<SushiChartTypeEnum> chartTypes = Arrays.asList(SushiChartTypeEnum.values());
private IModel<SushiChartTypeEnum> chartType = Model.of(SushiChartTypeEnum.COLUMN);
private TextField<String> chartTitleInput;
private DropDownChoice<SushiChartTypeEnum> chartTypeSelect;
private ChartConfigurationPanel panel;
private NotificationPanel feedbackPanel;
private SushiEventType selectedEventType;
private Form<Void> layoutForm;
private AjaxSlider slider;
private Integer sliderValue = 1;
private Label sliderLabel;
private WebMarkupContainer sliderContainer;
public ChartConfigurationPanel(String id, AttributeChartPage visualisationPage){
super(id);
this.panel = this;
this.parentPage = visualisationPage;
layoutForm = new Form<Void>("layoutForm");
add(layoutForm);
addFeedbackPanel(layoutForm);
layoutForm.add(addChartTitleInput());
layoutForm.add(addChartTypeSelect());
layoutForm.add(addEventTypeSelect());
updateAttributes();
layoutForm.add(addAttributeSelect());
sliderContainer = new WebMarkupContainer("sliderDiv") {
public boolean isVisible() {
return isSliderVisible();
};
};
sliderContainer.setOutputMarkupPlaceholderTag(true);
sliderContainer.add(addSlider());
sliderContainer.add(addSliderLabel());
layoutForm.add(sliderContainer);
addButtonsToForm(layoutForm);
}
/**
* creates a slider that defines the size of the integer ranges,
* that define the attribute-value ranges for the distribution chart
* @return slider
*/
private Component addSlider() {
slider = new AjaxSlider("slider", 1, 100) {
public boolean isVisible() {
return isSliderVisible();
}
};
slider.setOutputMarkupPlaceholderTag(true);
slider.setAjaxStopEvent(new AjaxSlider.ISliderAjaxEvent() {
private static final long serialVersionUID = 1L;
public void onEvent(AjaxRequestTarget target, AjaxSlider slider1, int value, int[] values) {
sliderValue = value;
sliderLabel.detach();
target.add(sliderLabel);
}
});
return slider;
}
/**
* creates the label that displays the value of the slider
* @return slider label
*/
private Component addSliderLabel() {
sliderLabel = new Label("sliderLabel", new PropertyModel<Integer>(this, "sliderValue")) {
public boolean isVisible() {
return isSliderVisible();
}
};
sliderLabel.setOutputMarkupPlaceholderTag(true);
return sliderLabel;
}
/**
* updates the slider range
* in dependence of the selected attribute and the actual in the database existing values
*/
public void updateSlider() {
if (isSliderInvisible()) {
return;
}
//find smallest ang biggest value from selected attribute
long min = SushiEvent.getMinOfAttributeValue(selectedAttribute.getName(), selectedEventType);
long max = SushiEvent.getMaxOfAttributeValue(selectedAttribute.getName(), selectedEventType);
//the maximum should be the difference from the min-value to the max-value
slider.setMax(Math.abs(max) + Math.abs(min));
sliderContainer.detach();
}
public boolean isSliderVisible() {
return (selectedAttribute != null && chartType != null && selectedAttribute.getType()==SushiAttributeTypeEnum.INTEGER
&& chartType.getObject() == SushiChartTypeEnum.COLUMN);
}
public boolean isSliderInvisible() {
return !isSliderVisible();
}
private void addFeedbackPanel(Form<Void> layoutForm) {
feedbackPanel = new NotificationPanel("feedback");
feedbackPanel.setOutputMarkupId(true);
feedbackPanel.setOutputMarkupPlaceholderTag(true);
layoutForm.add(feedbackPanel);
}
private Component addChartTitleInput() {
chartTitleInput = new TextField<String>("chartTitleInput", new PropertyModel<String>(this, "chartTitle"));
return chartTitleInput;
}
private Component addEventTypeSelect() {
eventTypeSelect = new DropDownChoice<String>("eventTypeSelect", new PropertyModel<String>(this, "selectedEventTypeName"), eventTypeNameProvider);
eventTypeSelect.setOutputMarkupId(true);
eventTypeSelect.add(new AjaxFormComponentUpdatingBehavior("onchange"){
@Override
protected void onUpdate(AjaxRequestTarget target) {
selectedEventType = SushiEventType.findByTypeName(selectedEventTypeName);
updateAttributes();
target.add(attributeSelect);
}
});
return eventTypeSelect;
}
private Component addChartTypeSelect() {
chartTypeSelect = new DropDownChoice<SushiChartTypeEnum>("chartTypeSelect", chartType, chartTypes);
chartTypeSelect.setOutputMarkupId(true);
chartTypeSelect.add(new AjaxFormComponentUpdatingBehavior("onchange"){
@Override
protected void onUpdate(AjaxRequestTarget target) {
updateAttributes();
updateSlider();
target.add(attributeSelect);
target.add(sliderContainer);
}
});
return chartTypeSelect;
}
private Component addAttributeSelect() {
updateAttributes();
attributeSelect = new DropDownChoice<SushiAttribute>("attributeSelect", new PropertyModel<SushiAttribute>(this, "selectedAttribute"), attributes);
attributeSelect.setOutputMarkupId(true);
attributeSelect.add(new AjaxFormComponentUpdatingBehavior("onchange"){
@Override
protected void onUpdate(AjaxRequestTarget target) {
updateSlider();
target.add(sliderContainer);
}
});
return attributeSelect;
}
/**
* update attributes in dependence of selected event type
*/
private void updateAttributes() {
attributes.clear();
//collect attributes of event type
if(selectedEventType != null){
if (chartType.getObject() == null) {
attributes.addAll(selectedEventType.getValueTypes());
} else if (chartType.getObject() == SushiChartTypeEnum.COLUMN) {
//BarChart only for string or Integer
for (SushiAttribute attribute : selectedEventType.getValueTypes()) {
if (attribute.getType() == SushiAttributeTypeEnum.STRING || attribute.getType() == SushiAttributeTypeEnum.INTEGER)
attributes.add(attribute);
}
} else if (chartType.getObject() == SushiChartTypeEnum.SPLATTER) {
//SplatterChart only integer
for (SushiAttribute attribute : selectedEventType.getValueTypes()) {
if (attribute.getType() == SushiAttributeTypeEnum.INTEGER)
attributes.add(attribute);
}
}
}
}
private void addButtonsToForm(Form<Void> layoutForm) {
AjaxButton createButton = new AjaxButton("createButton") {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form form) {
panel.getFeedbackPanel().setVisible(true);
boolean error = false;
if (chartTitle == null) {
panel.getFeedbackPanel().error("Chart needs a title!");
panel.getFeedbackPanel().setVisible(true);
target.add(panel.getFeedbackPanel());
error = true;
};
if(selectedEventType == null){
panel.getFeedbackPanel().error("eventType must be chosen!");
panel.getFeedbackPanel().setVisible(true);
target.add(panel.getFeedbackPanel());
error = true;
};
if (chartType == null) {
panel.getFeedbackPanel().error("Choose a chart type!");
panel.getFeedbackPanel().setVisible(true);
target.add(panel.getFeedbackPanel());
error = true;
};
if (selectedAttribute == null) {
panel.getFeedbackPanel().error("Choose an attribute!");
panel.getFeedbackPanel().setVisible(true);
target.add(panel.getFeedbackPanel());
error = true;
};
if (error == false) {
//create new ChartConfiguration
String attributeName = selectedAttribute.getAttributeExpression();
SushiAttributeTypeEnum attributeType = selectedAttribute.getType();
SushiChartConfiguration newOptions = new SushiChartConfiguration(selectedEventType, attributeName, attributeType, chartTitle, chartType.getObject(), sliderValue);
newOptions.save();
AttributeChartPage visualisation = parentPage;
visualisation.getOptions().detach();
target.add(visualisation.listview.getParent());
//close this Panel
visualisation.addChartModal.close(target);
};
};
};
layoutForm.add(createButton);
}
public NotificationPanel getFeedbackPanel() {
return feedbackPanel;
}
}