Package org.libreplan.web.users.dashboard

Source Code of org.libreplan.web.users.dashboard.PersonalTimesheetController

/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 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.users.dashboard;

import static org.libreplan.web.I18nHelper._;
import static org.libreplan.web.planner.tabs.MultipleTabsPlannerController.BREADCRUMBS_SEPARATOR;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.users.entities.UserRole;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.IndexController;
import org.libreplan.web.common.Level;
import org.libreplan.web.common.MessagesForUser;
import org.libreplan.web.common.Util;
import org.libreplan.web.common.components.bandboxsearch.BandboxSearch;
import org.libreplan.web.common.entrypoints.EntryPointsHandler;
import org.libreplan.web.common.entrypoints.EntryPointsHandler.ICapture;
import org.libreplan.web.common.entrypoints.IURLHandlerRegistry;
import org.libreplan.web.common.entrypoints.MatrixParameters;
import org.libreplan.web.security.SecurityUtils;
import org.springframework.util.Assert;
import org.zkoss.util.Locales;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.InputEvent;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Cell;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Column;
import org.zkoss.zul.Columns;
import org.zkoss.zul.Frozen;
import org.zkoss.zul.Image;
import org.zkoss.zul.Label;
import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.api.Div;
import org.zkoss.zul.api.Grid;
import org.zkoss.zul.api.Popup;

/**
* Controller for creation/edition of a personal timesheet
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
@SuppressWarnings("serial")
public class PersonalTimesheetController extends GenericForwardComposer
        implements IPersonalTimesheetController {

    private final static String EFFORT_DURATION_TEXTBOX_WIDTH = "30px";
    private final static String TOTAL_DURATION_TEXTBOX_WIDTH = "50px";

    private final static String WORK_REPORTS_URL = "/workreports/workReport.zul";

    private IPersonalTimesheetModel personalTimesheetModel;

    private IURLHandlerRegistry URLHandlerRegistry;

    private Grid timesheet;

    private Columns columns;

    private BandboxSearch orderElementBandboxSearch;

    private Button previousPeriod;

    private Button nextPeriod;

    private Component messagesContainer;

    private IMessagesForUser messagesForUser;

    private Label summaryTotalPersonalTimesheet;

    private Label summaryTotalOther;

    private Label summaryTotal;

    private Label summaryTotalCapacity;

    private Label summaryTotalExtraPerDay;

    private Label summaryTotalExtra;

    private Popup personalTimesheetPopup;

    private Label personalTimesheetPopupTask;

    private Label personalTimesheetPopupDate;

    private Div personalTimesheetPopupEffort;

    private Div personalTimesheetPopupFinished;

    @Resource
    private IPersonalTimesheetController personalTimesheetController;

    private RowRenderer rowRenderer = new RowRenderer() {

        private LocalDate first;
        private LocalDate last;

        @Override
        public void render(Row row, Object data) throws Exception {
            PersonalTimesheetRow personalTimesheetRow = (PersonalTimesheetRow) data;

            initPersonalTimesheetDates();

            switch (personalTimesheetRow.getType()) {
            case ORDER_ELEMENT:
                renderOrderElementRow(row,
                        personalTimesheetRow.getOrderElemement());
                break;
            case OTHER:
                renderOtherRow(row);
                break;
            case CAPACITY:
                renderCapacityRow(row);
                break;
            case TOTAL:
                renderTotalRow(row);
                break;
            case EXTRA:
                renderExtraRow(row);

                // This is the last row so we can load the info in the summary
                updateSummary();
                break;
            default:
                throw new IllegalStateException(
                        "Unknown PersonalTimesheetRow type: "
                                + personalTimesheetRow.getType());
            }
        }

        private void initPersonalTimesheetDates() {
            first = personalTimesheetModel.getFirstDay();
            last = personalTimesheetModel.getLastDate();
        }

        private void renderOrderElementRow(Row row, OrderElement orderElement) {
            Util.appendLabel(row, personalTimesheetModel.getOrder(orderElement)
                    .getName());
            Util.appendLabel(row, orderElement.getName());

            appendInputsForDays(row, orderElement);

            if (personalTimesheetModel.hasOtherReports()) {
                appendOtherColumn(row, orderElement);
            }

            appendTotalColumn(row, orderElement);
        }

        private void appendInputsForDays(Row row,
                final OrderElement orderElement) {
            for (LocalDate day = first; day.compareTo(last) <= 0; day = day
                    .plusDays(1)) {
                final LocalDate textboxDate = day;

                final Textbox textbox = new Textbox();
                textbox.setHflex("true");

                Util.bind(textbox, new Util.Getter<String>() {
                    @Override
                    public String get() {
                        EffortDuration effortDuration = personalTimesheetModel
                                .getEffortDuration(orderElement, textboxDate);
                        return effortDurationToString(effortDuration);
                    }
                }, new Util.Setter<String>() {
                    @Override
                    public void set(String value) {
                        EffortDuration effortDuration = effortDurationFromString(value);
                        if (effortDuration == null) {
                            throw new WrongValueException(textbox,
                                    _("Invalid Effort Duration"));
                        }
                        personalTimesheetModel.setEffortDuration(orderElement,
                                textboxDate, effortDuration);
                        markAsModified(textbox);
                        updateTotals(orderElement, textboxDate);
                    }

                    private void updateTotals(OrderElement orderElement,
                            LocalDate date) {
                        updateTotalColumn(orderElement);
                        updateTotalRow(date);
                        updateExtraRow(date);
                        updateTotalColumn();
                        updateTotalExtraColumn();
                        updateSummary();
                    }

                });

                EventListener openPersonalTimesheetPopup = new EventListener() {
                    @Override
                    public void onEvent(Event event) throws Exception {
                        openPersonalTimesheetPopup(textbox,
                                orderElement, textboxDate);
                    }

                };
                textbox.addEventListener(Events.ON_DOUBLE_CLICK,
                        openPersonalTimesheetPopup);
                textbox.addEventListener(Events.ON_OK,
                        openPersonalTimesheetPopup);

                if (personalTimesheetModel
                        .wasModified(orderElement, textboxDate)) {
                    markAsModified(textbox);
                }

                Cell cell = getCenteredCell(textbox);
                if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
                    setBackgroundNonCapacityCell(cell);
                }
                row.appendChild(cell);
            }

        }

        private void openPersonalTimesheetPopup(Textbox textbox,
                OrderElement orderElement, LocalDate textboxDate) {
            Textbox toFocus = setupPersonalTimesheetPopup(textbox,
                    orderElement, textboxDate);
            personalTimesheetPopup.open(textbox, "after_start");
            toFocus.setFocus(true);
        }

        private Textbox setupPersonalTimesheetPopup(final Textbox textbox,
                final OrderElement orderElement, final LocalDate textboxDate) {
            personalTimesheetPopupTask.setValue(orderElement.getName());
            personalTimesheetPopupDate.setValue(textboxDate.toString());

            personalTimesheetPopupEffort.getChildren().clear();
            Textbox effortTextbox = Util.bind(new Textbox(),
                    new Util.Getter<String>() {
                @Override
                public String get() {
                    EffortDuration effortDuration = personalTimesheetModel
                            .getEffortDuration(orderElement, textboxDate);
                    return effortDurationToString(effortDuration);
                }
            }, new Util.Setter<String>() {
                @Override
                public void set(String value) {
                    EffortDuration effortDuration = effortDurationFromString(value);
                    if (effortDuration == null) {
                        throw new WrongValueException(
                                personalTimesheetPopupEffort,
                                _("Invalid Effort Duration"));
                    }
                    Events.sendEvent(new InputEvent(Events.ON_CHANGE, textbox,
                            value));
                }
            });
            addOnOkEventToClosePopup(effortTextbox);
            personalTimesheetPopupEffort.appendChild(effortTextbox);

            personalTimesheetPopupFinished.getChildren().clear();
            Checkbox finishedCheckbox = Util.bind(new Checkbox(),
                    new Util.Getter<Boolean>() {
                        @Override
                        public Boolean get() {
                            return personalTimesheetModel.isFinished(
                                    orderElement, textboxDate);
                        }
                    }, new Util.Setter<Boolean>() {
                        @Override
                        public void set(Boolean value) {
                            personalTimesheetModel.setFinished(orderElement,
                                    textboxDate, value);
                            markAsModified(textbox);
                        }
                    });
            if (!finishedCheckbox.isChecked()) {
                finishedCheckbox.setDisabled(personalTimesheetModel
                        .isFinished(orderElement));
            }
            addOnOkEventToClosePopup(finishedCheckbox);
            personalTimesheetPopupFinished.appendChild(finishedCheckbox);

            return effortTextbox;
        }

        private boolean addOnOkEventToClosePopup(Component component) {
            return component.addEventListener(Events.ON_OK,
                    new EventListener() {
                @Override
                public void onEvent(Event event) throws Exception {
                    closePersonalTimesheetPopup();
                }
            });
        }

        private void markAsModified(final Textbox textbox) {
            textbox.setStyle("font-weight: bold");
        }

        private void appendOtherColumn(Row row, final OrderElement orderElement) {
            Textbox other = getDisabledTextbox(getOtherRowTextboxId(orderElement));
            other.setValue(effortDurationToString(personalTimesheetModel.getOtherEffortDuration(orderElement)));
            row.appendChild(getCenteredCell(other));
        }

        private void appendTotalColumn(Row row, final OrderElement orderElement) {
            row.appendChild(getCenteredCell(getDisabledTextbox(getTotalRowTextboxId(orderElement))));
            updateTotalColumn(orderElement);
        }

        private void updateTotalColumn(OrderElement orderElement) {
            EffortDuration effort = personalTimesheetModel
                    .getEffortDuration(orderElement);
            effort = effort.plus(personalTimesheetModel
                    .getOtherEffortDuration(orderElement));

            Textbox textbox = (Textbox) timesheet
                    .getFellow(getTotalRowTextboxId(orderElement));
            textbox.setValue(effortDurationToString(effort));
        }

        private void renderTotalRow(Row row) {
            appendLabelSpaningTwoColumns(row, _("Total"));
            appendTotalForDays(row);
            row.setSclass("total-row");
            appendTotalColumn(row);
        }

        private void appendLabelSpaningTwoColumns(Row row, String text) {
            Cell cell = new Cell();
            cell.setColspan(2);
            Label label = new Label(text);
            label.setStyle("font-weight: bold;");
            cell.appendChild(label);
            row.appendChild(cell);
        }

        private void appendTotalForDays(Row row) {
            for (LocalDate day = first; day.compareTo(last) <= 0; day = day
                    .plusDays(1)) {
                Cell cell = getCenteredCell(getDisabledTextbox(getTotalColumnTextboxId(day)));
                if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
                    setBackgroundNonCapacityCell(cell);
                }
                row.appendChild(cell);

                updateTotalRow(day);
            }
        }

        private void updateTotalRow(LocalDate date) {
            EffortDuration effort = personalTimesheetModel
                    .getEffortDuration(date);
            effort = effort.plus(personalTimesheetModel
                    .getOtherEffortDuration(date));

            Textbox textbox = (Textbox) timesheet
                    .getFellow(getTotalColumnTextboxId(date));
            textbox.setValue(effortDurationToString(effort));
        }

        private void appendTotalColumn(Row row) {
            Cell totalCell = getCenteredCell(getDisabledTextbox(getTotalTextboxId()));
            if (personalTimesheetModel.hasOtherReports()) {
                totalCell.setColspan(2);
            }
            row.appendChild(totalCell);
            updateTotalColumn();
        }

        private void updateTotalColumn() {
            EffortDuration effort = personalTimesheetModel
                    .getTotalEffortDuration();
            effort = effort.plus(personalTimesheetModel
                    .getTotalOtherEffortDuration());

            Textbox textbox = (Textbox) timesheet
                    .getFellow(getTotalTextboxId());
            textbox.setValue(effortDurationToString(effort));
        }

        private void renderOtherRow(Row row) {
            appendLabelSpaningTwoColumns(row, _("Other"));
            appendOtherForDaysAndTotal(row);
        }

        private void appendOtherForDaysAndTotal(Row row) {
            EffortDuration totalOther = EffortDuration.zero();

            for (LocalDate day = first; day.compareTo(last) <= 0; day = day
                    .plusDays(1)) {
                EffortDuration other = personalTimesheetModel
                        .getOtherEffortDuration(day);

                Cell cell = getCenteredCell(getDisabledTextbox(
                        getOtherColumnTextboxId(day), other));
                if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
                    setBackgroundNonCapacityCell(cell);
                }
                row.appendChild(cell);

                totalOther = totalOther.plus(other);
            }

            Cell totalOtherCell = getCenteredCell(getDisabledTextbox(
                    getTotalOtherTextboxId(), totalOther));
            totalOtherCell.setColspan(2);
            row.appendChild(totalOtherCell);
        }

        private void renderCapacityRow(Row row) {
            appendLabelSpaningTwoColumns(row, _("Capacity"));
            appendCapcityForDaysAndTotal(row);
        }

        private void appendCapcityForDaysAndTotal(Row row) {
            EffortDuration totalCapacity = EffortDuration.zero();

            for (LocalDate day = first; day.compareTo(last) <= 0; day = day
                    .plusDays(1)) {
                EffortDuration capacity = personalTimesheetModel
                        .getResourceCapacity(day);

                Cell cell = getCenteredCell(getDisabledTextbox(
                        getCapcityColumnTextboxId(day), capacity));
                if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
                    setBackgroundNonCapacityCell(cell);
                }
                row.appendChild(cell);

                totalCapacity = totalCapacity.plus(capacity);
            }

            Cell totalCapacityCell = getCenteredCell(getDisabledTextbox(
                    getTotalCapacityTextboxId(), totalCapacity));
            if (personalTimesheetModel.hasOtherReports()) {
                totalCapacityCell.setColspan(2);
            }
            row.appendChild(totalCapacityCell);
        }

        private void renderExtraRow(Row row) {
            appendLabelSpaningTwoColumns(row, _("Extra"));
            appendExtraForDays(row);
            appendTotalExtra(row);
        }

        private void appendExtraForDays(Row row) {
            for (LocalDate day = first; day.compareTo(last) <= 0; day = day
                    .plusDays(1)) {
                Cell cell = getCenteredCell(getDisabledTextbox(getExtraColumnTextboxId(day)));
                if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
                    setBackgroundNonCapacityCell(cell);
                }
                row.appendChild(cell);

                updateExtraRow(day);
            }

        }

        private void updateExtraRow(LocalDate date) {
            EffortDuration total = getEffortDuration(getTotalColumnTextboxId(date));
            EffortDuration capacity = getEffortDuration(getCapcityColumnTextboxId(date));

            EffortDuration extra = EffortDuration.zero();
            if (total.compareTo(capacity) > 0) {
                extra = total.minus(capacity);
            }

            Textbox textbox = (Textbox) timesheet
                    .getFellow(getExtraColumnTextboxId(date));
            textbox.setValue(effortDurationToString(extra));
        }

        private EffortDuration getEffortDuration(String textboxId) {
            String value = ((Textbox) timesheet.getFellow(textboxId))
                    .getValue();
            return effortDurationFromString(value);
        }

        private void appendTotalExtra(Row row) {
            Cell totalExtraCell = getCenteredCell(getDisabledTextbox(getTotalExtraTextboxId()));
            if (personalTimesheetModel.hasOtherReports()) {
                totalExtraCell.setColspan(2);
            }
            row.appendChild(totalExtraCell);
            updateTotalExtraColumn();
        }

        private void updateTotalExtraColumn() {
            EffortDuration totalExtra = EffortDuration.zero();
            for (LocalDate day = first; day.compareTo(last) <= 0; day = day
                    .plusDays(1)) {
                EffortDuration extra = getEffortDuration(getExtraColumnTextboxId(day));
                totalExtra = totalExtra.plus(extra);
            }

            Textbox textbox = (Textbox) timesheet
                    .getFellow(getTotalExtraTextboxId());
            textbox.setValue(effortDurationToString(totalExtra));
        }

        private Textbox getDisabledTextbox(String id) {
            Textbox textbox = new Textbox();
            textbox.setHflex("true");
            textbox.setId(id);
            textbox.setDisabled(true);
            return textbox;
        }

        private Textbox getDisabledTextbox(String id, EffortDuration effort) {
            Textbox textbox = getDisabledTextbox(id);
            textbox.setValue(effortDurationToString(effort));
            return textbox;
        }

        private Cell getCenteredCell(Component component) {
            Cell cell = new Cell();
            cell.setAlign("center");
            cell.appendChild(component);
            return cell;
        }

        private Cell getAlignLeftCell(Component component) {
            Cell cell = new Cell();
            cell.setAlign("left");
            cell.appendChild(component);
            return cell;
        }

        private void setBackgroundNonCapacityCell(Cell cell) {
            cell.setStyle("background-color: #FFEEEE");
        }

    };

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        comp.setAttribute("controller", this);

        setBreadcrumbs(comp);
        messagesForUser = new MessagesForUser(messagesContainer);

        checkUserComesFromEntryPointsOrSendForbiddenCode();

        URLHandlerRegistry.getRedirectorFor(IPersonalTimesheetController.class)
                .register(this, page);
    }

    private void adjustFrozenWidth() {
        // Hack to reduce frozen scrollarea
        Clients.evalJavaScript("jq('.z-frozen-inner div').width(jq('.totals-column').offset().left);");
    }

    private void checkUserComesFromEntryPointsOrSendForbiddenCode() {
        HttpServletRequest request = (HttpServletRequest) Executions
                .getCurrent().getNativeRequest();
        Map<String, String> matrixParams = MatrixParameters.extract(request);

        // If it doesn't come from a entry point
        if (matrixParams.isEmpty()) {
            Util.sendForbiddenStatusCodeInHttpServletResponse();
        }
    }

    private void setBreadcrumbs(Component comp) {
        Component breadcrumbs = comp.getPage().getFellow("breadcrumbs");
        if (breadcrumbs.getChildren() != null) {
            breadcrumbs.getChildren().clear();
        }
        breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
        breadcrumbs.appendChild(new Label(_("My account")));
        breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
        breadcrumbs.appendChild(new Label(_("My dashboard")));
        breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
        breadcrumbs.appendChild(new Label(_("Personal timesheet")));
    }

    @Override
    public void goToCreateOrEditForm(LocalDate date) {
        if (!SecurityUtils.isUserInRole(UserRole.ROLE_BOUND_USER)) {
            Util.sendForbiddenStatusCodeInHttpServletResponse();
        }

        personalTimesheetModel.initCreateOrEdit(date);
        initTimesheet(date);
    }

    @Override
    public void goToCreateOrEditFormForResource(LocalDate date,
            org.libreplan.business.resources.entities.Resource resource) {
        if (!SecurityUtils.isSuperuserOrUserInRoles(UserRole.ROLE_TIMESHEETS)) {
            Util.sendForbiddenStatusCodeInHttpServletResponse();
        }

        personalTimesheetModel.initCreateOrEdit(date, resource);
        initTimesheet(date);
    }

    private void initTimesheet(LocalDate date) {
        columns = new Columns();
        columns.setSizable(true);
        timesheet.getChildren().clear();
        timesheet.appendChild(columns);
        createColumns(date);

        Frozen frozen = new Frozen();
        frozen.setColumns(2);
        timesheet.appendChild(frozen);

        adjustFrozenWidth();
    }

    private void createColumns(LocalDate date) {
        createProjectAndTaskColumns();
        createColumnsForDays(date);
        if (personalTimesheetModel.hasOtherReports()) {
            createOtherColumn();
        }
        createTotalColumn();
    }

    private void createProjectAndTaskColumns() {
        Column project = new Column(_("Project"));
        project.setStyle("min-width:100px");
        columns.appendChild(project);

        Column task = new Column(_("Task"));
        task.setStyle("min-width:100px");

        columns.appendChild(project);
        columns.appendChild(task);
    }

    private void createColumnsForDays(LocalDate date) {
        LocalDate start = personalTimesheetModel
                .getPersonalTimesheetsPeriodicity().getStart(date);
        LocalDate end = personalTimesheetModel
                .getPersonalTimesheetsPeriodicity().getEnd(date);

        for (LocalDate day = start; day.compareTo(end) <= 0; day = day
                .plusDays(1)) {
            Column column = new Column(day.getDayOfMonth() + "");
            column.setAlign("center");
            column.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH);
            columns.appendChild(column);
        }
    }

    private void createOtherColumn() {
        Column other = new Column(_("Other"));
        other.setWidth(TOTAL_DURATION_TEXTBOX_WIDTH);
        other.setSclass("totals-column");
        other.setAlign("center");
        columns.appendChild(other);
    }

    private void createTotalColumn() {
        Column total = new Column(_("Total"));
        total.setWidth(TOTAL_DURATION_TEXTBOX_WIDTH);
        total.setSclass("totals-column");
        total.setAlign("center");
        columns.appendChild(total);
    }

    public String getTimesheetString() {
        return personalTimesheetModel.getTimesheetString();
    }

    public String getResource() {
        return personalTimesheetModel.getWorker().getShortDescription();
    }

    public List<PersonalTimesheetRow> getRows() {
        List<PersonalTimesheetRow> result = PersonalTimesheetRow
                .wrap(personalTimesheetModel
                .getOrderElements());
        if (personalTimesheetModel.hasOtherReports()) {
            result.add(PersonalTimesheetRow.createOtherRow());
        }
        result.add(PersonalTimesheetRow.createTotalRow());
        result.add(PersonalTimesheetRow.createCapacityRow());
        result.add(PersonalTimesheetRow.createExtraRow());
        return result;
    }

    public RowRenderer getRowRenderer() {
        return rowRenderer;
    }

    public void save() {
        personalTimesheetModel.save();
        String url = IndexController.USER_DASHBOARD_URL
                + "?timesheet_saved=" + personalTimesheetModel.getDate();
        if (!personalTimesheetModel.isCurrentUser()) {
            url = WORK_REPORTS_URL + "?timesheet_saved=true";
        }
        Executions.getCurrent().sendRedirect(url);
    }

    public void saveAndContinue() {
        personalTimesheetModel.save();
        if (personalTimesheetModel.isCurrentUser()) {
            goToCreateOrEditForm(personalTimesheetModel.getDate());
        } else {
            goToCreateOrEditFormForResource(personalTimesheetModel.getDate(),
                    personalTimesheetModel.getWorker());
        }
        messagesForUser.showMessage(Level.INFO, _("Personal timesheet saved"));
        Util.reloadBindings(timesheet);
    }

    public void cancel() {
        personalTimesheetModel.cancel();
        String url = IndexController.USER_DASHBOARD_URL;
        if (!personalTimesheetModel.isCurrentUser()) {
            url = WORK_REPORTS_URL;
        }
        Executions.getCurrent().sendRedirect(url);
    }

    public void addOrderElement() {
        OrderElement orderElement = (OrderElement) orderElementBandboxSearch
                .getSelectedElement();
        if (orderElement != null) {
            personalTimesheetModel.addOrderElement(orderElement);
            orderElementBandboxSearch.setSelectedElement(null);
            Util.reloadBindings(timesheet);
            adjustFrozenWidth();
        }
    }

    public boolean isFirstPeriod() {
        return personalTimesheetModel.isFirstPeriod();
    }

    public boolean isLastPeriod() {
        return personalTimesheetModel.isLastPeriod();
    }

    public void previousPeriod() {
        if (personalTimesheetModel.isModified()) {
            throw new WrongValueException(
                    previousPeriod,
                    _("There are unsaved changes in the current personal timesheet, please save before moving"));
        }
        sendToPersonalTimesheet(personalTimesheetModel.getPrevious());
    }

    public void nextPeriod() {
        if (personalTimesheetModel.isModified()) {
            throw new WrongValueException(
                    nextPeriod,
                    _("There are unsaved changes in the current personal timesheet, please save before moving"));
        }

        sendToPersonalTimesheet(personalTimesheetModel.getNext());
    }

    private void sendToPersonalTimesheet(final LocalDate date) {
        String capturePath = EntryPointsHandler.capturePath(new ICapture() {
            @Override
            public void capture() {
                personalTimesheetController.goToCreateOrEditForm(date);
            }
        });
        Executions.getCurrent().sendRedirect(capturePath);
    }

    public boolean isCurrentUser() {
        return personalTimesheetModel.isCurrentUser();
    }

    public boolean isNotCurrentUser() {
        return !personalTimesheetModel.isCurrentUser();
    }

    private static String getTotalRowTextboxId(final OrderElement orderElement) {
        return "textbox-total-row" + orderElement.getId();
    }

    private static String getTotalColumnTextboxId(LocalDate date) {
        return "textbox-total-column-" + date;
    }

    private static String getTotalTextboxId() {
        return "textbox-total";
    }

    private static String getOtherRowTextboxId(final OrderElement orderElement) {
        return "textbox-other-row" + orderElement.getId();
    }

    private static String getOtherColumnTextboxId(LocalDate date) {
        return "textbox-other-column-" + date;
    }

    private static String getTotalOtherTextboxId() {
        return "textbox-other-capacity";
    }

    private static String getCapcityColumnTextboxId(LocalDate date) {
        return "textbox-capacity-column-" + date;
    }

    private static String getTotalCapacityTextboxId() {
        return "textbox-total-capacity";
    }

    private static String getExtraColumnTextboxId(LocalDate date) {
        return "textbox-extra-column-" + date;
    }

    private static String getTotalExtraTextboxId() {
        return "textbox-total-extra";
    }

    private static String effortDurationToString(EffortDuration effort) {
        if (effort == null || effort.isZero()) {
            return "";
        }

        return effort.toFormattedString();
    }

    private static EffortDuration effortDurationFromString(String effort) {
        if (StringUtils.isBlank(effort)) {
            return EffortDuration.zero();
        }

        String decimalSeparator = ((DecimalFormat) DecimalFormat
                .getInstance(Locales.getCurrent()))
                .getDecimalFormatSymbols().getDecimalSeparator() + "";
        if (effort.contains(decimalSeparator) || effort.contains(".")) {
            try {
                effort = effort.replace(decimalSeparator, ".");
                double hours = Double.parseDouble(effort);
                return EffortDuration.fromHoursAsBigDecimal(new BigDecimal(
                        hours));
            } catch (NumberFormatException e) {
                return null;
            }
        }

        return EffortDuration.parseFromFormattedString(effort);
    }

    public void updateSummary() {
        EffortDuration total = getEffortDurationFromTextbox(getTotalTextboxId());
        EffortDuration other = EffortDuration.zero();
        if (personalTimesheetModel.hasOtherReports()) {
            other = getEffortDurationFromTextbox(getTotalOtherTextboxId());
        }
        EffortDuration capacity = getEffortDurationFromTextbox(getTotalCapacityTextboxId());
        EffortDuration extraPerDay = getEffortDurationFromTextbox(getTotalExtraTextboxId());

        EffortDuration timesheet = total.minus(other);
        EffortDuration extra = EffortDuration.zero();
        if (total.compareTo(capacity) > 0) {
            extra = total.minus(capacity);
        }

        if (personalTimesheetModel.hasOtherReports()) {
            summaryTotalPersonalTimesheet
                    .setValue(timesheet.toFormattedString());
            summaryTotalOther.setValue(other.toFormattedString());
        }

        summaryTotal.setValue(total.toFormattedString());
        summaryTotalCapacity.setValue(capacity.toFormattedString());
        summaryTotalExtraPerDay.setValue(extraPerDay.toFormattedString());
        summaryTotalExtra.setValue(extra.toFormattedString());
    }

    private EffortDuration getEffortDurationFromTextbox(String id) {
        return effortDurationFromString(((Textbox) timesheet.getFellow(id))
                .getValue());
    }

    public boolean hasOtherReports() {
        return personalTimesheetModel.hasOtherReports();
    }

    public void closePersonalTimesheetPopup() {
        personalTimesheetPopup.close();
    }

}

/**
* Simple class to represent the the rows in the personal timesheet grid.<br />
*
* This is used to mark the special rows like capacity and total.
*/
class PersonalTimesheetRow {
    enum PersonalTimesheetRowType {
        ORDER_ELEMENT, OTHER, CAPACITY, TOTAL, EXTRA
    };

    private PersonalTimesheetRowType type;
    private OrderElement orderElemement;

    public static PersonalTimesheetRow createOrderElementRow(
            OrderElement orderElemement) {
        PersonalTimesheetRow row = new PersonalTimesheetRow(
                PersonalTimesheetRowType.ORDER_ELEMENT);
        Assert.notNull(orderElemement);
        row.orderElemement = orderElemement;
        return row;
    }

    public static PersonalTimesheetRow createOtherRow() {
        return new PersonalTimesheetRow(PersonalTimesheetRowType.OTHER);
    }

    public static PersonalTimesheetRow createCapacityRow() {
        return new PersonalTimesheetRow(PersonalTimesheetRowType.CAPACITY);
    }

    public static PersonalTimesheetRow createTotalRow() {
        return new PersonalTimesheetRow(PersonalTimesheetRowType.TOTAL);
    }

    public static PersonalTimesheetRow createExtraRow() {
        return new PersonalTimesheetRow(PersonalTimesheetRowType.EXTRA);
    }

    public static List<PersonalTimesheetRow> wrap(
            List<OrderElement> orderElements) {
        List<PersonalTimesheetRow> result = new ArrayList<PersonalTimesheetRow>();
        for (OrderElement each : orderElements) {
            result.add(createOrderElementRow(each));
        }
        return result;
    }

    private PersonalTimesheetRow(PersonalTimesheetRowType type) {
        this.type = type;
    }

    public PersonalTimesheetRowType getType() {
        return type;
    }

    public OrderElement getOrderElemement() {
        return orderElemement;
    }

}
TOP

Related Classes of org.libreplan.web.users.dashboard.PersonalTimesheetController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.