gt:         if (onClose != null) {
context: /*
   * 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);
  