/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.isis.viewer.wicket.ui.components.collectioncontents.summary;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.AbstractItem;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.Model;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
import org.apache.isis.core.metamodel.spec.ObjectAdapterUtils;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.feature.Contributed;
import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
import org.apache.isis.viewer.wicket.ui.components.collection.count.CollectionCountProvider;
import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
/**
* {@link PanelAbstract Panel} that represents a {@link EntityCollectionModel
* collection of entity}s rendered using as a table of summary values with a
* chart alongside.
*/
public class CollectionContentsAsSummary extends PanelAbstract<EntityCollectionModel> implements CollectionCountProvider {
private static final String ID_MAX = "max";
private static final String ID_MIN = "min";
private static final String ID_AVG = "avg";
private static final String ID_SUM = "sum";
private static final String ID_PROPERTY_NAME = "propertyName";
private static final String ID_REPEATING_SUMMARY = "repeatingSummary";
private static final long serialVersionUID = 1L;
private static final String ID_FEEDBACK = "feedback";
public CollectionContentsAsSummary(final String id, final EntityCollectionModel model) {
super(id, model);
buildGui();
}
private void buildGui() {
final EntityCollectionModel model = getModel();
final ObjectSpecification elementSpec = model.getTypeOfSpecification();
final NotificationPanel feedback = new NotificationPanel(ID_FEEDBACK);
feedback.setOutputMarkupId(true);
addOrReplace(feedback);
List<ObjectAssociation> numberAssociations = elementSpec.getAssociations(Contributed.EXCLUDED, CollectionContentsAsSummaryFactory.OF_TYPE_BIGDECIMAL);
RepeatingView repeating = new RepeatingView(ID_REPEATING_SUMMARY);
addOrReplace(repeating);
for (ObjectAssociation numberAssociation : numberAssociations) {
AbstractItem item = new AbstractItem(repeating.newChildId());
repeating.add(item);
String propertyName = numberAssociation.getName();
item.add(new Label(ID_PROPERTY_NAME, new Model<String>(propertyName)));
List<ObjectAdapter> adapters = model.getObject();
Summary summary = new Summary(propertyName, adapters, numberAssociation);
addItem(item, ID_SUM, summary.getTotal());
addItem(item, ID_AVG, summary.getAverage());
addItem(item, ID_MIN, summary.getMin());
addItem(item, ID_MAX, summary.getMax());
}
}
public static class Summary {
private BigDecimal sum = BigDecimal.ZERO;
private BigDecimal min = null;
private BigDecimal max = null;
private final List<String> titles = Lists.newArrayList();
private final List<BigDecimal> values = Lists.newArrayList();
private BigDecimal average;
private String propertyName;
public Summary(List<ObjectAdapter> adapters, ObjectAssociation numberAssociation) {
this(null, adapters, numberAssociation);
}
public Summary(String propertyName, List<ObjectAdapter> adapters, ObjectAssociation numberAssociation) {
this.propertyName = propertyName;
int nonNullCount = 0;
for (ObjectAdapter objectAdapter : adapters) {
titles.add(objectAdapter.titleString(null));
final ObjectAdapter valueAdapter = numberAssociation.get(objectAdapter, InteractionInitiatedBy.USER);
if (valueAdapter == null) {
values.add(null);
continue;
}
final Object valueObj = ObjectAdapterUtils.unwrapObject(valueAdapter);
if (valueObj == null) {
values.add(null);
continue;
}
nonNullCount++;
BigDecimal value = (BigDecimal) valueObj;
sum = sum.add(value);
min = min != null && min.compareTo(value) < 0 ? min : value;
max = max != null && max.compareTo(value) > 0 ? max : value;
values.add(value);
}
average = nonNullCount != 0 ? sum.divide(BigDecimal.valueOf(nonNullCount), 2, RoundingMode.HALF_UP) : null;
}
public String getPropertyName() {
return propertyName;
}
public BigDecimal getTotal() {
return sum;
}
public BigDecimal getAverage() {
return average;
}
public BigDecimal getMax() {
return max;
}
public BigDecimal getMin() {
return min;
}
public List<String> getTitles() {
return Collections.unmodifiableList(titles);
}
public List<BigDecimal> getValues() {
return Collections.unmodifiableList(values);
}
public List<Number> getValuesAsNumbers() {
return asNumbers(getValues());
}
private static List<Number> asNumbers(List<BigDecimal> values) {
return Lists.newArrayList(Iterables.transform(values, BIGDECIMAL_TO_NUMBER));
}
private static final com.google.common.base.Function<BigDecimal, Number> BIGDECIMAL_TO_NUMBER = new com.google.common.base.Function<BigDecimal, Number>(){
public Number apply(BigDecimal value) {
return value;
}
};
}
private void addItem(AbstractItem item, String id, BigDecimal amt) {
TextField<String> textField = new TextField<String>(id, new Model<String>(format(amt)));
item.add(textField);
}
private String format(BigDecimal amt) {
return amt != null ? amt.setScale(2, RoundingMode.HALF_UP).toPlainString() : "";
}
@Override
protected void onModelChanged() {
buildGui();
}
@Override
public Integer getCount() {
final EntityCollectionModel model = getModel();
return model.getCount();
}
}