org.libreplan.web.montecarlo.MonteCarloGraphController.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.web.montecarlo.MonteCarloGraphController.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2010-2011 Igalia, S.L.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.libreplan.web.montecarlo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.LocalDate;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.CategoryModel;
import org.zkoss.zul.Chart;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.SimpleCategoryModel;

/**
 * Generates a BarChart 3D with the results of a MonteCarlo computation.
 * The window also shows a set of Datebox controllers that allow the  user to specify a start and end date
 * and calculate the probability density between both values.
 *
 * @author Diego Pino Garcia <dpino@igalia.com>
 */
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class MonteCarloGraphController extends GenericForwardComposer {

    private Chart monteCarloChart;

    private Datebox dateboxStartDateProbability;

    private Datebox dateboxEndDateProbability;

    private Decimalbox dbIntervalProbability;

    private List<LocalDate> dates;

    private Map<LocalDate, BigDecimal> monteCarloValues;

    public MonteCarloGraphController() {

    }

    public void doAfterCompose(org.zkoss.zk.ui.Component comp) throws Exception {
        super.doAfterCompose(comp);
        self.setAttribute("monteCarloGraphController", this, true);
    }

    public interface IOnClose {

        void monteCarloGraphClosed();
    }

    private IOnClose onClose = null;

    public void generateMonteCarloGraph(String orderName, Map<LocalDate, BigDecimal> data, boolean byWeek,
            IOnClose onClose) {

        this.onClose = onClose;

        CategoryModel xyModel;

        initializeMonteCarloValues(data);

        // Generate MonteCarlo chart
        if (byWeek) {
            xyModel = generateMonteCarloGraphByWeek(orderName, groupByWeek(data));
        } else {
            xyModel = generateMonteCarloGraphByDay(orderName, data);
        }
        monteCarloChart.setModel(xyModel);

        // Initialize dates for calculating probability density
        LocalDate first = getFirstDate();
        LocalDate last = getLastDate();
        dateboxStartDateProbability.setValue(toDate(first));
        dateboxEndDateProbability.setValue(toDate(last));
        dbIntervalProbability.setValue(calculateProbabilityDensity(first, last));
    }

    private void initializeMonteCarloValues(Map<LocalDate, BigDecimal> data) {
        monteCarloValues = data;
        initializeDates(data);
    }

    private void initializeDates(Map<LocalDate, BigDecimal> monteCarloValues) {
        dates = new ArrayList<>(monteCarloValues.keySet());
        Collections.sort(dates);
    }

    private CategoryModel generateMonteCarloGraphByDay(String orderName, Map<LocalDate, BigDecimal> data) {
        CategoryModel result = new SimpleCategoryModel();

        LocalDate first = getFirstDate();
        LocalDate last = getLastDate();
        for (LocalDate i = first; i.compareTo(last) <= 0; i = i.plusDays(1)) {
            String labelDate = i.toString();
            result.setValue(orderName, labelDate, data.get(i));
        }

        return result;
    }

    private LocalDate getFirstDate() {
        return dates.get(0);
    }

    private LocalDate getLastDate() {
        return dates.get(dates.size() - 1);
    }

    private Date toDate(LocalDate date) {
        return date.toDateTimeAtStartOfDay().toDate();
    }

    private String weekLabelFor(LocalDate date) {
        return "W" + date.getWeekOfWeekyear();
    }

    private String weekAndYearLabelFor(LocalDate date) {
        return "W" + date.getWeekOfWeekyear() + "-" + date.getYear();
    }

    private CategoryModel generateMonteCarloGraphByWeek(String orderName, Map<String, BigDecimal> data) {
        CategoryModel result = new SimpleCategoryModel();

        LocalDate first = getFirstDate();
        LocalDate last = getLastDate();
        for (LocalDate i = first; i.compareTo(last) <= 0; i = i.plusDays(1)) {
            plotWeekValue(result, orderName, weekLabelFor(i), data.get(weekAndYearLabelFor(i)));
        }

        return result;
    }

    private void plotWeekValue(CategoryModel model, String orderName, String date, BigDecimal probability) {
        if (probability == null) {
            probability = BigDecimal.ZERO;
        }
        model.setValue(orderName, date, probability);
    }

    private Map<String, BigDecimal> groupByWeek(Map<LocalDate, BigDecimal> data) {
        Map<String, BigDecimal> result = new HashMap<>();

        // Group values of each date by week
        for (LocalDate date : data.keySet()) {
            String weekLabel = weekAndYearLabelFor(date);
            BigDecimal value = result.get(weekLabel);
            value = (value != null) ? value.add(data.get(date)) : data.get(date);
            result.put(weekLabel, value);
        }

        return result;
    }

    private BigDecimal calculateProbabilityDensity(LocalDate start, LocalDate end) {
        BigDecimal result = BigDecimal.ZERO;

        for (LocalDate i = start; i.compareTo(end) <= 0; i = i.plusDays(1)) {
            BigDecimal value = monteCarloValues.get(i);
            if (value == null) {
                continue;
            }

            result = result.add(value);
        }
        return result;
    }

    public void showProbabilityDensity(Datebox startDatebox, Datebox endDatebox) {
        LocalDate start = (startDatebox.getValue() != null) ? new LocalDate(startDatebox.getValue())
                : getFirstDate();
        LocalDate end = (endDatebox.getValue() != null) ? new LocalDate(endDatebox.getValue()) : getLastDate();

        BigDecimal probabilityDensity = calculateProbabilityDensity(start, end);
        dbIntervalProbability.setValue(probabilityDensity);
    }

    public void onCancel() {
        cancel();
    }

    public void cancel() {
        self.setVisible(false);
        if (onClose != null) {
            onClose.monteCarloGraphClosed();
        }
    }

}