com.aurel.track.report.dashboard.BurnDownChart.java Source code

Java tutorial

Introduction

Here is the source code for com.aurel.track.report.dashboard.BurnDownChart.java

Source

/**
 * Genji Scrum Tool and Issue Tracker
 * Copyright (C) 2015 Steinbeis GmbH & Co. KG Task Management Solutions
    
 * <a href="http://www.trackplus.com">Genji Scrum Tool</a>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* $Id:$ */

package com.aurel.track.report.dashboard;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

import com.aurel.track.Constants;
import com.aurel.track.admin.customize.category.filter.execute.FilterExecuterFacade;
import com.aurel.track.admin.customize.category.filter.execute.loadItems.FilterUpperConfigUtil;
import com.aurel.track.admin.customize.category.filter.execute.loadItems.LoadItemIDListItems;
import com.aurel.track.admin.customize.category.filter.execute.loadItems.LoadTreeFilterItems;
import com.aurel.track.admin.customize.category.filter.execute.loadItems.ReportBeanLoader;
import com.aurel.track.admin.customize.category.filter.execute.loadItems.TooManyItemsToLoadException;
import com.aurel.track.admin.customize.category.filter.tree.design.FilterUpperTO;
import com.aurel.track.admin.customize.lists.ListBL;
import com.aurel.track.admin.customize.lists.customOption.OptionBL;
import com.aurel.track.admin.customize.lists.systemOption.StatusBL;
import com.aurel.track.admin.customize.treeConfig.field.FieldBL;
import com.aurel.track.admin.project.ProjectBL;
import com.aurel.track.beans.TFieldBean;
import com.aurel.track.beans.TOptionBean;
import com.aurel.track.beans.TPersonBean;
import com.aurel.track.beans.TWorkItemBean;
import com.aurel.track.errors.ErrorData;
import com.aurel.track.fieldType.constants.SystemFields;
import com.aurel.track.fieldType.runtime.base.IFieldTypeRT;
import com.aurel.track.fieldType.types.FieldTypeManager;
import com.aurel.track.item.history.HistoryLoaderBL;
import com.aurel.track.item.history.HistoryLoaderBL.LONG_TEXT_TYPE;
import com.aurel.track.item.history.HistoryValues;
import com.aurel.track.itemNavigator.ItemNavigatorBL;
import com.aurel.track.itemNavigator.QueryContext;
import com.aurel.track.json.JSONUtility;
import com.aurel.track.persist.ReportBeanHistoryLoader;
import com.aurel.track.plugin.DashboardDescriptor;
import com.aurel.track.report.dashboard.ProjectFilterDashboardView.DATASOURCE_TYPE;
import com.aurel.track.report.datasource.IPluggableDatasource.CONTEXT_ATTRIBUTE;
import com.aurel.track.report.datasource.earnedValue.EarnedValueBL;
import com.aurel.track.report.datasource.earnedValue.EarnedValueDatasource;
import com.aurel.track.report.datasource.earnedValue.EarnedValueTimeSlice;
import com.aurel.track.report.execute.ReportBean;
import com.aurel.track.report.execute.ReportBeanWithHistory;
import com.aurel.track.resources.LocalizeUtil;
import com.aurel.track.util.DateTimeUtils;
import com.aurel.track.util.GeneralUtils;
import com.aurel.track.util.IntegerStringBean;
import com.aurel.track.util.StringArrayParameterUtils;
import com.sun.tools.ws.ant.Apt.Option;

public class BurnDownChart extends TimePeriodDashboardView {
    private static final Logger LOGGER = LogManager.getLogger(BurnDownChart.class);

    private List<ReportBean> reportBeanList;
    private List<ReportBeanWithHistory> reportBeanWithHistoryList;
    private Date dateTo;
    private Date dateFrom;
    private HashMap<Integer, Integer> storyPointValueIDToValueMap;
    private int sumOfStoryPointForAllItems;
    private Integer customFieldIDForStoryPoint;

    static final int PLANNED_VALUE = 1;
    static final int ACTUAL_EFFORT = 2;
    static final int EARNED_VALUE = 3;
    static String ISO_FORMATTED_DATE = "yyyy-MM-dd";

    //Configuration page constants
    public static interface CONFIGURATION_PARAMETERS {
        static String STATUSES = "statuses";
        static String SELECTED_STATUS = "selectedStatus";
        static String TIME_INTERVALS = "timeIntervals";
        static String EFFORT_TYPE = "effortType";
        static String CUSTOM_FIELD_FOR_STORY_POINT = "customFieldForStoryPoint";
        static String SELECTED_EFFORT_TYPE = "selectedEffortType";
        static String SELECTED_CUSTOM_FIELD_FOR_STORY_POINT = "selectedCustomFieldForStoryPoint";
        static String REPORTING_INTERVAL = "reportingInterval";
        static String SELECTED_REPORTING_INTERVAL = "selectedReportingInterval";
        static String Y_AXE = "yAxe";
    }

    protected int DEFAULT_HEIGHT = 400;
    protected int MIN_HEIGHT = 250;
    protected int MAX_HEIGHT = 900;

    public static interface PERIOD_TYPE {
        static int FROM_TO = 1;
        static int DAYS_BEFORE = 2;
    }

    public static interface TIME_INTERVAL {
        static int DAY = 1;
        static int WEEK = 2;
        static int MONTH = 3;
    }

    // Effort type constants
    public static interface EFFORT_TYPE {
        static int TIME = 1;
        static int NR_OF_ITEMS_IN_INTERVAL = 2;
        static int STORY_POINTS = 3;
    }

    // Reporting interval constants
    public static interface REPORTING_INTERVAL {
        static int DAILY = 1;
        static int WEEKLY = 2;
        static int MONTHLY = 3;
    }

    // Property parameters
    public static interface PROPERTY_PARAMS {
        static String EFFORT_TYPE_EFFORT = "burnDownChart.tooltip.effortTypeEffort";
        static String EFFORT_TYPE_NR_OF_ITEMS_IN_INTERVAL = "burnDownChart.tooltip.effortTypeNrOfItemsInInterval";
        static String EFFORT_TYPE_STORY_POINTS = "burnDownChart.tooltip.effortTypeStoryPoints";
        static String EFFORT_TYPE_COST = "burnDownChart.tooltip.effortTypeCost";
        static String REPORTING_INTERVAL_DAILY = "burnDownChart.tooltip.reportingInterval.daily";
        static String REPORTING_INTERVAL_WEEKLY = "burnDownChart.tooltip.reportingInterval.weekly";
        static String REPORTING_INTERVAL_MONTHLY = "burnDownChart.tooltip.reportingInterval.monthly";
    }

    protected boolean isUseConfig() {
        return true;
    }

    @Override
    protected String encodeJSONExtraData(Integer dashboardID, Map<String, Object> session,
            Map<String, String> parameters, Integer projectID, Integer releaseID, Map<String, String> ajaxParams)
            throws TooManyItemsToLoadException {

        TPersonBean user = (TPersonBean) session.get(Constants.USER_KEY);
        Locale locale = user.getLocale();
        DashboardDescriptor dashboardDescriptor = getDescriptor();
        String bundleName = dashboardDescriptor.getBundleName();

        StringBuilder sb = new StringBuilder();
        String sessionPrefix = "dashboard" + "." + dashboardID;

        //the name where configParameters are stored
        String theParams = sessionPrefix + "Params";
        //to avoid caching if IE

        String userEnteredTitle = parameters.get("title");
        if (userEnteredTitle == null || "".equals(userEnteredTitle.trim())) {
            userEnteredTitle = "burnDownChart.label";
        }
        int height = parseInteger(parameters, CONFIGURATION_PARAMETERS.Y_AXE, DEFAULT_HEIGHT);

        Map<String, Object> configParameters = new HashMap<String, Object>();
        Iterator<String> it = parameters.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            configParameters.put(key, parameters.get(key));
        }
        //used in preparing the locale specific chart
        configParameters.put("locale", locale);
        configParameters.put("personBean", user);
        configParameters.put("projectID", projectID);
        configParameters.put("releaseID", releaseID);
        session.put(theParams, configParameters);
        JSONUtility.appendIntegerValue(sb, "height", height);

        dateTo = null;
        dateFrom = null;

        if ((configParameters.get("dateTo") != null && configParameters.get("dateTo") != null
                && !configParameters.get("dateTo").equals("null")
                && !configParameters.get("dateFrom").equals("null"))
                || (configParameters.get("daysBefore") != null)) {

            SimpleDateFormat dateFormat;
            dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            if (configParameters.get("daysBefore") != null) {

                Calendar calendar = Calendar.getInstance();
                int daysBefore = BasePluginDashboardBL.parseIntegerValue(configParameters,
                        TIMEPERIOD_PARAMETERS.DAYS_BEFORE, 0);
                dateTo = calendar.getTime();
                dateFrom = calendar.getTime();
                if (daysBefore != 0) {
                    calendar.add(Calendar.DATE, -daysBefore);
                    dateFrom = calendar.getTime();
                }

            } else {
                try {
                    dateFrom = dateFormat.parse(configParameters.get("dateFrom").toString());
                    dateTo = dateFormat.parse(configParameters.get("dateTo").toString());
                } catch (Exception ex) {
                    LOGGER.error(ExceptionUtils.getStackTrace(ex), ex);
                }
            }
            JSONUtility.appendStringValue(sb, "dateTo", dateFormat.format(dateTo).toString());
            JSONUtility.appendStringValue(sb, "dateFrom", dateFormat.format(dateFrom).toString());
            String chartData = generateJSONResponse(configParameters, user, locale);
            boolean chartDataIsEmpty = false;
            if (chartData == null) {
                chartData = "[]";
                chartDataIsEmpty = true;
            }
            JSONUtility.appendJSONValue(sb, "chartData", chartData);
            JSONUtility.appendBooleanValue(sb, "empty", chartDataIsEmpty);
            String xAxesLabel = "";
            if (Integer
                    .parseInt(configParameters.get("reportingInterval").toString()) == REPORTING_INTERVAL.WEEKLY) {
                xAxesLabel = LocalizeUtil.getLocalizedText("burnDownChart.xAxesLabelWeekly", locale, bundleName);
            } else {
                xAxesLabel = LocalizeUtil.getLocalizedText("burnDownChart.xAxesLabel", locale, bundleName);
            }
            Integer selectedEffortType = Integer
                    .parseInt(parameters.get(CONFIGURATION_PARAMETERS.EFFORT_TYPE).toString());

            customFieldIDForStoryPoint = parseInteger(parameters,
                    CONFIGURATION_PARAMETERS.CUSTOM_FIELD_FOR_STORY_POINT, -1);

            String yAxesLabel = "";
            if (selectedEffortType == EFFORT_TYPE.NR_OF_ITEMS_IN_INTERVAL) {
                yAxesLabel = LocalizeUtil.getLocalizedText("burnDownChart.yAxesLabel.no.of.item", locale,
                        bundleName);
            } else if (selectedEffortType == EFFORT_TYPE.STORY_POINTS) {
                yAxesLabel = LocalizeUtil.getLocalizedText("burnDownChart.yAxesLabel.story.point", locale,
                        bundleName);
            } else if (selectedEffortType == EFFORT_TYPE.TIME) {
                yAxesLabel = LocalizeUtil.getLocalizedText("burnDownChart.yAxesLabel.effort", locale, bundleName);
            }

            JSONUtility.appendIntegerValue(sb, CONFIGURATION_PARAMETERS.SELECTED_EFFORT_TYPE, selectedEffortType);
            JSONUtility.appendIntegerValue(sb, CONFIGURATION_PARAMETERS.SELECTED_CUSTOM_FIELD_FOR_STORY_POINT,
                    customFieldIDForStoryPoint);

            JSONUtility.appendStringValue(sb, "xAxesLabel", xAxesLabel);
            JSONUtility.appendStringValue(sb, "yAxesLabel", yAxesLabel);
            JSONUtility.appendStringValue(sb, "reportingInterval",
                    configParameters.get("reportingInterval").toString());
            JSONUtility.appendStringValue(sb, "locale", locale.toString());
        } else {
            JSONUtility.appendBooleanValue(sb, "empty", true);
            LOGGER.debug("Burn-Down Chart not configured yet!");
        }
        return sb.toString();
    }

    @Override
    public String encodeJSONExtraDataConfig(Map<String, String> parameters, TPersonBean user, Integer entityId,
            Integer entityType) {
        StringBuilder sb = new StringBuilder();
        Locale locale = user.getLocale();
        DashboardDescriptor dashboardDescriptor = getDescriptor();
        String bundleName = dashboardDescriptor.getBundleName();

        sb.append(getDatasourceConfig(parameters, entityId, entityType, locale));
        sb.append(getTimePeriodConfig(parameters, locale));

        JSONUtility.appendILabelBeanList(sb, CONFIGURATION_PARAMETERS.STATUSES, StatusBL.loadAll(locale));
        JSONUtility.appendStringList(sb, CONFIGURATION_PARAMETERS.SELECTED_STATUS,
                StringArrayParameterUtils.splitSelection(parameters.get(CONFIGURATION_PARAMETERS.SELECTED_STATUS)));

        //Reporting interval
        JSONUtility.appendIntegerStringBeanList(sb, BurnDownChart.CONFIGURATION_PARAMETERS.REPORTING_INTERVAL,
                getPossibleReportingIntervals(locale, bundleName));
        int reportingInterval = parseInteger(parameters, CONFIGURATION_PARAMETERS.REPORTING_INTERVAL,
                TIME_INTERVAL.MONTH);
        JSONUtility.appendIntegerValue(sb, CONFIGURATION_PARAMETERS.SELECTED_REPORTING_INTERVAL, reportingInterval);

        JSONUtility.appendIntegerValue(sb, CONFIGURATION_PARAMETERS.Y_AXE,
                parseInteger(parameters, CONFIGURATION_PARAMETERS.Y_AXE, DEFAULT_HEIGHT));
        //Effort type
        JSONUtility.appendIntegerStringBeanList(sb, BurnDownChart.CONFIGURATION_PARAMETERS.EFFORT_TYPE,
                getPossibleEffortTypes(locale, bundleName));
        //selected Effort type
        Integer selectedEffortType = parseIntegerValue(parameters, CONFIGURATION_PARAMETERS.EFFORT_TYPE,
                EFFORT_TYPE.NR_OF_ITEMS_IN_INTERVAL);
        JSONUtility.appendIntegerValue(sb, CONFIGURATION_PARAMETERS.SELECTED_EFFORT_TYPE, selectedEffortType);

        JSONUtility.appendIntegerStringBeanList(sb,
                BurnDownChart.CONFIGURATION_PARAMETERS.CUSTOM_FIELD_FOR_STORY_POINT,
                getPossibleCustomFieldsAsStoryPointValue());

        customFieldIDForStoryPoint = -1;
        if (parameters.get(CONFIGURATION_PARAMETERS.CUSTOM_FIELD_FOR_STORY_POINT) != null) {
            customFieldIDForStoryPoint = parseIntegerValue(parameters,
                    CONFIGURATION_PARAMETERS.CUSTOM_FIELD_FOR_STORY_POINT, -1);
        }
        JSONUtility.appendIntegerValue(sb, CONFIGURATION_PARAMETERS.SELECTED_CUSTOM_FIELD_FOR_STORY_POINT,
                customFieldIDForStoryPoint);
        JSONUtility.appendIntegerValue(sb, "storyPointEffortTypeID", EFFORT_TYPE.STORY_POINTS);
        int prefWidth = 480;
        int prefHeight = 680;
        JSONUtility.appendIntegerValue(sb, "prefWidth", prefWidth);
        JSONUtility.appendIntegerValue(sb, "prefHeight", prefHeight);
        return sb.toString();
    }

    public String generateJSONResponse(Map configParameters, TPersonBean personBean, Locale locale)
            throws TooManyItemsToLoadException {
        int datasourceType = parseInteger(configParameters, "selectedDatasourceType", 1);
        Integer projectOrReleaseID = null;
        Integer filterID = null;
        if (configParameters.get("projectID") != null || configParameters.get("releaseID") != null) {
            if (configParameters.get("releaseID") != null) {
                projectOrReleaseID = Integer.valueOf(configParameters.get("releaseID").toString());
            } else {
                projectOrReleaseID = Integer.valueOf(configParameters.get("projectID").toString());
                projectOrReleaseID = projectOrReleaseID * (-1);
            }
            datasourceType = DATASOURCE_TYPE.PROJECT_RELEASE;
        } else {
            if (datasourceType == 1) {
                projectOrReleaseID = parseInteger(configParameters, "selectedProjectOrRelease", 1);
            } else {
                filterID = parseInteger(configParameters, "selectedQueryID", 1);
            }
        }

        boolean isTime = true;
        Map<String, Object> contextMap = new HashMap<String, Object>();
        contextMap.put("fromIssueNavigator", false);
        contextMap.put("useProjectSpecificID", false);
        Integer selectedEffortType = Integer
                .parseInt(configParameters.get(CONFIGURATION_PARAMETERS.EFFORT_TYPE).toString());
        reportBeanList = getReportBeanList(datasourceType, projectOrReleaseID, filterID, contextMap, true, true,
                true, personBean, locale);
        reportBeanWithHistoryList = ReportBeanHistoryLoader.getReportBeanWithHistoryList(reportBeanList, locale,
                false, false, true, new Integer[] { SystemFields.INTEGER_STATE }, true, true, true, true, false,
                personBean.getObjectID(), null, dateFrom, dateTo, true, LONG_TEXT_TYPE.ISPLAIN);
        SortedMap<Date, EarnedValueTimeSlice> earnedValueTimeSliceMap = new TreeMap<Date, EarnedValueTimeSlice>();

        int reportingInterval = parseIntegerValue(configParameters, CONFIGURATION_PARAMETERS.REPORTING_INTERVAL, 1);
        if (!reportBeanWithHistoryList.isEmpty()) {
            LOGGER.debug(
                    "Number of reportBeanWithHistoryList after removing items with no budget or overlapping start/end dates "
                            + reportBeanWithHistoryList.size());
            Date minStartDate = EarnedValueBL.getMinMaxStartEndDate(reportBeanWithHistoryList, true);
            Date maxEndDate = EarnedValueBL.getMinMaxStartEndDate(reportBeanWithHistoryList, false);
            if (minStartDate != null && maxEndDate != null) {
                Integer[] selectedStatuses = getSelectedStatuses(configParameters);
                SortedMap<Integer, SortedMap<Integer, Double>> plannedValues = null;
                SortedMap<Integer, SortedMap<Integer, Double>> earnedValues = null;
                if (selectedEffortType == EFFORT_TYPE.TIME) {
                    Set<Integer> projectIDs = EarnedValueBL
                            .prefilterReportBeansGetProjectIDs(reportBeanWithHistoryList, isTime, dateFrom, dateTo);
                    Map<Integer, Double> hoursPerWorkingDayMap = ProjectBL.getHoursPerWorkingDayMap(projectIDs);
                    plannedValues = EarnedValueBL.calculatePlannedValues(reportBeanWithHistoryList, isTime,
                            minStartDate, maxEndDate, reportingInterval, hoursPerWorkingDayMap);
                    earnedValues = EarnedValueBL.calculateEarnedValues(reportBeanWithHistoryList, isTime,
                            minStartDate, maxEndDate, reportingInterval, hoursPerWorkingDayMap,
                            GeneralUtils.createSetFromIntegerArr(selectedStatuses));
                    BurnDownChartBL.addZerosForEmptyIntervals(dateFrom, dateTo, reportingInterval, plannedValues,
                            false);
                    BurnDownChartBL.addZerosForEmptyIntervals(dateFrom, dateTo, reportingInterval, earnedValues,
                            false);
                    EarnedValueBL.accumulateValues(plannedValues);
                    EarnedValueBL.accumulateValues(earnedValues);
                } else if (selectedEffortType == EFFORT_TYPE.NR_OF_ITEMS_IN_INTERVAL) {
                    plannedValues = calculatePlannedValuesDependingOnEffortType(minStartDate, maxEndDate,
                            reportingInterval, selectedEffortType);
                    earnedValues = calculateEarnedValuesDependingOnEffortType(plannedValues, reportingInterval,
                            GeneralUtils.createSetFromIntegerArr(selectedStatuses), selectedEffortType);
                    BurnDownChartBL.addZerosForEmptyIntervals(dateFrom, dateTo, reportingInterval, plannedValues,
                            false);
                    BurnDownChartBL.addZerosForEmptyIntervals(dateFrom, dateTo, reportingInterval, earnedValues,
                            false);
                } else if (selectedEffortType == EFFORT_TYPE.STORY_POINTS) {
                    customFieldIDForStoryPoint = Integer.parseInt(
                            configParameters.get(CONFIGURATION_PARAMETERS.CUSTOM_FIELD_FOR_STORY_POINT).toString());
                    storyPointValueIDToValueMap = createStoryPointValueIDToValueMap(reportBeanList);

                    sumOfStoryPointForAllItems = calculateSumOfStoryPointForAllItems(reportBeanList);

                    plannedValues = calculatePlannedValuesDependingOnEffortType(minStartDate, maxEndDate,
                            reportingInterval, selectedEffortType);
                    earnedValues = calculateEarnedValuesDependingOnEffortType(plannedValues, reportingInterval,
                            GeneralUtils.createSetFromIntegerArr(selectedStatuses), selectedEffortType);

                    BurnDownChartBL.addZerosForEmptyIntervals(dateFrom, dateTo, reportingInterval, plannedValues,
                            false);
                    BurnDownChartBL.addZerosForEmptyIntervals(dateFrom, dateTo, reportingInterval, earnedValues,
                            false);
                }
                SortedMap<Date, Object> plannedDateValues = BurnDownChartBL.transformPeriodsToDates(plannedValues,
                        reportingInterval);
                SortedMap<Date, Object> plannedEarnedValues = BurnDownChartBL.transformPeriodsToDates(earnedValues,
                        reportingInterval);
                EarnedValueBL.addValueTypeToBeans(earnedValueTimeSliceMap, plannedDateValues, PLANNED_VALUE);
                EarnedValueBL.addValueTypeToBeans(earnedValueTimeSliceMap, plannedEarnedValues, EARNED_VALUE);
                Double maxValPlanned = getMaxPlannedValue(earnedValueTimeSliceMap);
                Double maxValEarned = getMaxEarnedValue(earnedValueTimeSliceMap);
                return convertResultMapToJSONData(earnedValueTimeSliceMap, maxValPlanned, maxValEarned,
                        reportingInterval, selectedEffortType, reportingInterval).toString();
            }
        }
        return null;
    }

    public Double getMaxPlannedValue(SortedMap<Date, EarnedValueTimeSlice> earnedValueTimeSliceMap) {
        Double maxValue = -1.0;
        for (Map.Entry<Date, EarnedValueTimeSlice> entry : earnedValueTimeSliceMap.entrySet()) {
            Double d1 = entry.getValue().getPlannedValue();
            if (Double.compare(d1, maxValue) > 0) {
                maxValue = entry.getValue().getPlannedValue();
            }
        }
        return maxValue;
    }

    public Double getMaxEarnedValue(SortedMap<Date, EarnedValueTimeSlice> earnedValueTimeSliceMap) {
        Double maxValue = -1.0;
        for (Map.Entry<Date, EarnedValueTimeSlice> entry : earnedValueTimeSliceMap.entrySet()) {
            if (entry.getValue().getEarnedvalue() != null) {
                Double d1 = entry.getValue().getEarnedvalue();
                if (Double.compare(d1, maxValue) > 0) {
                    maxValue = entry.getValue().getEarnedvalue();
                }
            }
        }
        return maxValue;
    }

    private String convertResultMapToJSONData(SortedMap<Date, EarnedValueTimeSlice> earnedValueTimeSliceMap,
            Double maxValPlanned, Double maxEarned, int reportingInterval, int effortType, Integer timeInterval) {
        StringBuilder local = new StringBuilder();
        local.append("[");
        boolean last = false;
        for (Map.Entry<Date, EarnedValueTimeSlice> entry : earnedValueTimeSliceMap.entrySet()) {
            local.append("{");
            JSONUtility.appendStringValue(local, "date",
                    getDateBasedOnReportInterval(entry.getKey(), reportingInterval));
            Double plannedVal = entry.getValue().getPlannedValue();
            if (effortType == EFFORT_TYPE.TIME) {
                plannedVal = maxValPlanned - entry.getValue().getPlannedValue();
            }
            JSONUtility.appendDoubleValue(local, "plannedValue", plannedVal, true);
            Double earnValue = 0.0;
            if (entry.getValue().getEarnedvalue() != null) {
                earnValue = entry.getValue().getEarnedvalue();

            }
            if (effortType == EFFORT_TYPE.TIME) {
                earnValue = maxEarned - earnValue;
            }

            int calendarInterval = EarnedValueDatasource.getCalendarInterval(timeInterval);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(calendarInterval, 1);
            if (DateTimeUtils.lessOrEqual(entry.getKey(), calendar.getTime())) {
                local.append(",");
                JSONUtility.appendDoubleValue(local, "earnedValue", earnValue, true);
            }
            local.append("},");
        }
        if (local != null && local.length() > 0) {
            if (local.toString().endsWith(",")) {
                local = new StringBuilder(local.substring(0, local.length() - 1));
            }
        }
        local.append("]");
        return local.toString();
    }

    private String getDateBasedOnReportInterval(Date date, int reportingInterval) {
        String formattedDate = null;
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int week = cal.get(Calendar.WEEK_OF_YEAR);
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH);
        if (reportingInterval == REPORTING_INTERVAL.DAILY) {
            SimpleDateFormat dtf = new SimpleDateFormat(ISO_FORMATTED_DATE);
            return dtf.format(date).toString();
        } else if (reportingInterval == REPORTING_INTERVAL.MONTHLY) {
            return year + "-" + month;
        } else if (reportingInterval == REPORTING_INTERVAL.WEEKLY) {
            return week + "/" + year;
        }
        return formattedDate;
    }

    public List<IntegerStringBean> getPossibleEffortTypes(Locale locale, String bundleName) {
        List<IntegerStringBean> result = new ArrayList<IntegerStringBean>();
        result.add(new IntegerStringBean(
                LocalizeUtil.getLocalizedText(PROPERTY_PARAMS.EFFORT_TYPE_EFFORT, locale, bundleName),
                new Integer(EFFORT_TYPE.TIME)));
        result.add(new IntegerStringBean(LocalizeUtil
                .getLocalizedText(PROPERTY_PARAMS.EFFORT_TYPE_NR_OF_ITEMS_IN_INTERVAL, locale, bundleName),
                new Integer(EFFORT_TYPE.NR_OF_ITEMS_IN_INTERVAL)));
        result.add(new IntegerStringBean(
                LocalizeUtil.getLocalizedText(PROPERTY_PARAMS.EFFORT_TYPE_STORY_POINTS, locale, bundleName),
                new Integer(EFFORT_TYPE.STORY_POINTS)));

        return result;
    }

    public List<IntegerStringBean> getPossibleReportingIntervals(Locale locale, String bundleName) {
        List<IntegerStringBean> result = new ArrayList<IntegerStringBean>();
        result.add(new IntegerStringBean(
                LocalizeUtil.getLocalizedText(PROPERTY_PARAMS.REPORTING_INTERVAL_DAILY, locale, bundleName),
                new Integer(REPORTING_INTERVAL.DAILY)));
        result.add(new IntegerStringBean(
                LocalizeUtil.getLocalizedText(PROPERTY_PARAMS.REPORTING_INTERVAL_WEEKLY, locale, bundleName),
                new Integer(REPORTING_INTERVAL.WEEKLY)));
        result.add(new IntegerStringBean(
                LocalizeUtil.getLocalizedText(PROPERTY_PARAMS.REPORTING_INTERVAL_MONTHLY, locale, bundleName),
                new Integer(REPORTING_INTERVAL.MONTHLY)));

        return result;
    }

    private List<IntegerStringBean> getPossibleCustomFieldsAsStoryPointValue() {
        List<TFieldBean> customFieldBeans = FieldBL.loadCustom();
        List<IntegerStringBean> result = new ArrayList<IntegerStringBean>();
        if (customFieldBeans != null) {
            for (TFieldBean fieldBean : customFieldBeans) {
                if (fieldBean.getFieldType()
                        .equalsIgnoreCase("com.aurel.track.fieldType.types.custom.CustomSelectSimple")) {
                    result.add(new IntegerStringBean(fieldBean.getName(), fieldBean.getObjectID()));
                }
            }
        }
        return result;
    }

    public int parseIntegerValue(Map configParameters, String fieldName, int defaultValue) {
        int result = defaultValue;
        try {
            result = Integer.parseInt((String) configParameters.get(fieldName));
        } catch (Exception e) {
            LOGGER.debug("There is no value set for field: " + fieldName + " The default value will be used: "
                    + defaultValue);
        }
        return result;
    }

    protected List<ReportBean> getReportBeanList(Integer datasourceType, Integer projectOrReleaseID,
            Integer filterID, Map<String, Object> contextMap, boolean includeOpen, boolean includeClosed,
            boolean includeSubs, TPersonBean personBean, Locale locale) throws TooManyItemsToLoadException {
        List<ReportBean> reportBeanList = null;
        Boolean fromIssueNavigator = (Boolean) contextMap.get(CONTEXT_ATTRIBUTE.FROM_ISSUE_NAVIGATOR);
        Integer dashboardProjectOrReleaseID = (Integer) contextMap
                .get(CONTEXT_ATTRIBUTE.DASHBOARD_PROJECT_RELEASE_ID);
        if (fromIssueNavigator != null && fromIssueNavigator.booleanValue()) {
            List<Integer> workItemIDs = (List<Integer>) contextMap.get(CONTEXT_ATTRIBUTE.WORKITEMIDS);
            if (workItemIDs != null && !workItemIDs.isEmpty()) {
                reportBeanList = LoadItemIDListItems.getReportBeansByWorkItemIDs(
                        GeneralUtils.createIntArrFromIntegerList(workItemIDs), false, personBean.getObjectID(),
                        locale, true, true, true, true, true, true, false, true, false);
            } else {
                QueryContext queryContext = ItemNavigatorBL.loadLastQuery(personBean.getObjectID(), locale);
                if (queryContext != null) {
                    reportBeanList = ItemNavigatorBL.executeQuery(personBean, locale, queryContext);
                }
            }
        } else {
            if (dashboardProjectOrReleaseID != null) {
                FilterUpperTO filterUpperTO = FilterUpperConfigUtil
                        .getByProjectReleaseID(dashboardProjectOrReleaseID, true, includeOpen, includeClosed);
                reportBeanList = LoadTreeFilterItems.getTreeFilterReportBeansForReport(filterUpperTO, null,
                        filterID, personBean, locale);
            } else {
                //saves the parameters into the database
                if (datasourceType == null) {
                    LOGGER.warn("No datasourceType was selected");
                    return null;
                }
                if (datasourceType.intValue() == DATASOURCE_TYPE.PROJECT_RELEASE) {
                    if (projectOrReleaseID == null) {
                        LOGGER.warn("No project/release was selected");
                        return null;
                    } else {
                        FilterUpperTO filterUpperTO = FilterUpperConfigUtil
                                .getByProjectReleaseID(projectOrReleaseID, true, includeOpen, includeClosed);
                        reportBeanList = LoadTreeFilterItems.getTreeFilterReportBeansForReport(filterUpperTO, null,
                                filterID, personBean, locale);
                    }
                } else {
                    if (filterID == null) {
                        LOGGER.warn("No filter was selected");
                        return null;
                    } else {
                        reportBeanList = FilterExecuterFacade.getSavedFilterReportBeanList(filterID, locale,
                                personBean, new LinkedList<ErrorData>(), null, null, true);
                    }
                }
            }
        }
        return ReportBeanLoader.addISOValuesToReportBeans(reportBeanList, personBean.getObjectID(), locale);
    }

    public SortedMap<Integer, SortedMap<Integer, Double>> calculatePlannedValuesDependingOnEffortType(
            Date minStartDate, Date maxEndDate, Integer timeInterval, Integer selectedEffortType) {

        SortedMap<Integer, SortedMap<Integer, Double>> yearToIntervalToPlannedValue = new TreeMap<Integer, SortedMap<Integer, Double>>();
        if (reportBeanWithHistoryList != null) {
            Calendar calendarStartDate = Calendar.getInstance();
            Calendar calendarEndDate = Calendar.getInstance();
            Calendar calendar = Calendar.getInstance();
            //to avoid that the last days of the year to be taken as the first
            //week of the now year but the year remains the old one
            int calendarInterval = EarnedValueDatasource.getCalendarInterval(timeInterval);
            for (ReportBean reportBean : reportBeanWithHistoryList) {
                TWorkItemBean workItemBean = reportBean.getWorkItemBean();
                Date startDate = workItemBean.getStartDate();
                Date endDate = workItemBean.getEndDate();
                if (startDate == null || endDate == null) {
                    continue;
                }

                calendarStartDate.setTime(dateFrom);
                calendarEndDate.setTime(dateTo);
                calendar.setTime(dateFrom);
                int yearValue = calendarStartDate.get(Calendar.YEAR);
                int intervalValue = calendarStartDate.get(calendarInterval);
                boolean isFirst = true;
                while (calendar.before(calendarEndDate) || isFirst) {
                    if (isFirst) {
                        isFirst = false;
                    } else {
                        calendar.add(calendarInterval, 1);
                    }
                    yearValue = calendar.get(Calendar.YEAR);
                    intervalValue = calendar.get(calendarInterval);
                    SortedMap<Integer, Double> intervalToPlannedValues = yearToIntervalToPlannedValue
                            .get(Integer.valueOf(yearValue));
                    if (intervalToPlannedValues == null) {
                        yearToIntervalToPlannedValue.put(new Integer(yearValue), new TreeMap<Integer, Double>());
                        intervalToPlannedValues = yearToIntervalToPlannedValue.get(Integer.valueOf(yearValue));
                    }
                    Double totalPlannedValueForInterval = intervalToPlannedValues
                            .get(Integer.valueOf(intervalValue));
                    if (totalPlannedValueForInterval == null) {
                        totalPlannedValueForInterval = 0.0;
                    }
                    if (DateTimeUtils.less(calendar.getTime(), endDate)) {
                        if (selectedEffortType == EFFORT_TYPE.NR_OF_ITEMS_IN_INTERVAL) {
                            totalPlannedValueForInterval += 1.0;
                        } else {
                            Integer storyPointValueID = getStoryPointValueID(workItemBean,
                                    customFieldIDForStoryPoint);
                            if (storyPointValueID != null) {
                                Integer storyPointValue = storyPointValueIDToValueMap.get(storyPointValueID);
                                if (storyPointValue != null) {
                                    totalPlannedValueForInterval += storyPointValue;
                                }
                            }
                        }
                    }
                    intervalToPlannedValues.put(Integer.valueOf(intervalValue), totalPlannedValueForInterval);
                }
            }
        }
        return yearToIntervalToPlannedValue;
    }

    public SortedMap<Integer, SortedMap<Integer, Double>> calculateEarnedValuesDependingOnEffortType(
            SortedMap<Integer, SortedMap<Integer, Double>> yearToIntervalToPlannedValue, Integer timeInterval,
            Set<Integer> finalStates, Integer selectedEffortType) {

        SortedMap<Integer, SortedMap<Integer, Double>> yearToIntervalToEarnedValue = new TreeMap<Integer, SortedMap<Integer, Double>>();

        if (reportBeanWithHistoryList != null) {
            Calendar calendarStartDate = Calendar.getInstance();
            Calendar calendarEndDate = Calendar.getInstance();
            Calendar calendar = Calendar.getInstance();
            //to avoid that the last days of the year to be taken as the first
            //week of the now year but the year remains the old one
            int calendarInterval = EarnedValueDatasource.getCalendarInterval(timeInterval);
            for (ReportBeanWithHistory reportBeanWithHistory : reportBeanWithHistoryList) {
                TWorkItemBean workItemBean = reportBeanWithHistory.getWorkItemBean();
                Date startDate = workItemBean.getStartDate();
                Date endDate = workItemBean.getEndDate();
                if (startDate == null || endDate == null) {
                    continue;
                }
                calendarStartDate.setTime(dateFrom);
                calendarEndDate.setTime(dateTo);

                Map<Integer, Map<Integer, HistoryValues>> historyMap = reportBeanWithHistory.getHistoryValuesMap();
                List<HistoryValues> historyValuesList = HistoryLoaderBL.getHistoryValuesList(historyMap, false);
                if (historyValuesList == null || historyValuesList.isEmpty()) {
                    continue;
                }
                //the first HistoryValue should be the most recent because of sorting in HistoryLoaderBL.getHistoryValuesList()
                HistoryValues historyValues = historyValuesList.get(0);
                if (!SystemFields.INTEGER_STATE.equals(historyValues.getFieldID())) {
                    //should never happen
                    continue;
                }
                Integer stateID = (Integer) historyValues.getNewValue();
                if (stateID == null) {
                    continue;
                }
                Date lastStateChangeDate = historyValues.getLastEdit();
                calendar.setTime(dateFrom);
                int yearValue = calendarStartDate.get(Calendar.YEAR);
                int intervalValue = calendarStartDate.get(calendarInterval);
                boolean isFirst = true;
                while (calendar.before(calendarEndDate) || isFirst) {
                    if (isFirst) {
                        isFirst = false;
                    } else {
                        calendar.add(calendarInterval, 1);
                    }
                    yearValue = calendar.get(Calendar.YEAR);

                    intervalValue = calendar.get(calendarInterval);
                    SortedMap<Integer, Double> intervalToPlannedValues = yearToIntervalToEarnedValue
                            .get(Integer.valueOf(yearValue));
                    if (intervalToPlannedValues == null) {
                        yearToIntervalToEarnedValue.put(new Integer(yearValue), new TreeMap<Integer, Double>());
                        intervalToPlannedValues = yearToIntervalToEarnedValue.get(Integer.valueOf(yearValue));
                    }
                    Double totalPlannedValueForInterval = intervalToPlannedValues
                            .get(Integer.valueOf(intervalValue));
                    if (totalPlannedValueForInterval == null) {
                        SortedMap<Integer, Double> firstIntervalToPlannedvalues = yearToIntervalToPlannedValue
                                .get(yearToIntervalToPlannedValue.firstKey());
                        totalPlannedValueForInterval = firstIntervalToPlannedvalues
                                .get(firstIntervalToPlannedvalues.firstKey());
                    }
                    if (DateTimeUtils.less(lastStateChangeDate, calendar.getTime())) {
                        if (finalStates.contains(stateID)) {
                            if (selectedEffortType == EFFORT_TYPE.NR_OF_ITEMS_IN_INTERVAL) {
                                totalPlannedValueForInterval -= 1.0;
                            } else {
                                Integer storyPointValueID = getStoryPointValueID(workItemBean,
                                        customFieldIDForStoryPoint);
                                if (storyPointValueID != null) {
                                    Integer storyPointValue = storyPointValueIDToValueMap.get(storyPointValueID);
                                    if (storyPointValue != null) {
                                        totalPlannedValueForInterval -= (double) storyPointValue;
                                    }
                                }
                            }
                        }
                    }
                    intervalToPlannedValues.put(Integer.valueOf(intervalValue), totalPlannedValueForInterval);
                }
            }
        }
        return yearToIntervalToEarnedValue;
    }

    private Integer[] getSelectedStatuses(Map configParameters) {
        String values = configParameters.get(CONFIGURATION_PARAMETERS.SELECTED_STATUS).toString();
        Integer[] integerValues = null;
        if (values != null) {
            String[] strArr = values.split(",");
            if (strArr != null && strArr.length > 0 && !"".equals(strArr[0])) {
                integerValues = new Integer[strArr.length];
                for (int i = 0; i < strArr.length; i++) {
                    try {
                        integerValues[i] = new Integer(strArr[i]);
                    } catch (Exception e) {
                        LOGGER.info("Converting the " + strArr[i] + " as the " + i
                                + "th parameter to Integer failed with " + e.getMessage(), e);
                        LOGGER.error(ExceptionUtils.getStackTrace(e), e);
                    }
                }
            }
        }
        return integerValues;
    }

    private HashMap<Integer, Integer> createStoryPointValueIDToValueMap(List<ReportBean> reportBeanList) {
        HashMap<Integer, Integer> storyPointValueIDToValue = new HashMap<Integer, Integer>();
        HashSet<Integer> valueIDs = new HashSet<Integer>();
        for (ReportBean reportBean : reportBeanList) {
            Integer storyPointValueID = getStoryPointValueID(reportBean.getWorkItemBean(),
                    customFieldIDForStoryPoint);
            if (storyPointValueID != null) {
                valueIDs.add(storyPointValueID);
            }
        }
        List<TOptionBean> optionBeanList = OptionBL.loadByKeys(GeneralUtils.createIntegerArrFromSet(valueIDs));
        for (TOptionBean tOptionBean : optionBeanList) {
            storyPointValueIDToValue.put(tOptionBean.getObjectID(), Integer.parseInt(tOptionBean.getLabel()));
        }
        return storyPointValueIDToValue;
    }

    private int calculateSumOfStoryPointForAllItems(List<ReportBean> reportBeanList) {
        int sum = 0;
        for (ReportBean reportBean : reportBeanList) {
            Integer storyPointValueID = getStoryPointValueID(reportBean.getWorkItemBean(),
                    customFieldIDForStoryPoint);
            if (storyPointValueID != null) {
                Integer storyPointValue = storyPointValueIDToValueMap.get(storyPointValueID);
                if (storyPointValue != null) {
                    sum += storyPointValue;
                }
            }
        }
        return sum;
    }

    private Integer getStoryPointValueID(TWorkItemBean workItemBean, Integer storyPointFieldID) {
        if (workItemBean.getAttribute(storyPointFieldID) != null) {
            Object[] values = (Object[]) workItemBean.getAttribute(storyPointFieldID);
            if (values.length > 0) {
                return (Integer) values[0];
            }
        }
        return null;
    }
}