Package org.libreplan.web.planner.allocation

Source Code of org.libreplan.web.planner.allocation.AllocationRow

/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
*                         Desenvolvemento Tecnolóxico de Galicia
* 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.planner.allocation;

import static org.libreplan.business.workingday.EffortDuration.zero;
import static org.libreplan.web.I18nHelper._;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.calendars.entities.AvailabilityTimeLine;
import org.libreplan.business.calendars.entities.AvailabilityTimeLine.Interval;
import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.CapacityAvailable;
import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.CapacityResult;
import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.CapacityResult.IMatcher;
import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.ResourcesPerDayIsZero;
import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.ThereAreNoValidPeriods;
import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.ValidPeriodsDontHaveCapacity;
import org.libreplan.business.planner.entities.AssignedEffortForResource;
import org.libreplan.business.planner.entities.AssignedEffortForResource.IAssignedEffortForResource;
import org.libreplan.business.planner.entities.AssignedEffortForResource.WithTheLoadOf;
import org.libreplan.business.planner.entities.AssignmentFunction;
import org.libreplan.business.planner.entities.AssignmentFunction.AssignmentFunctionName;
import org.libreplan.business.planner.entities.CalculatedValue;
import org.libreplan.business.planner.entities.DerivedAllocation;
import org.libreplan.business.planner.entities.GenericResourceAllocation;
import org.libreplan.business.planner.entities.ResourceAllocation;
import org.libreplan.business.planner.entities.Task;
import org.libreplan.business.planner.entities.Task.ModifiedAllocation;
import org.libreplan.business.planner.entities.allocationalgorithms.AllocationModification;
import org.libreplan.business.planner.entities.allocationalgorithms.AllocationModification.IByType;
import org.libreplan.business.planner.entities.allocationalgorithms.EffortModification;
import org.libreplan.business.planner.entities.allocationalgorithms.ResourcesPerDayModification;
import org.libreplan.business.resources.daos.IResourcesSearcher;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.ResourceEnum;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workingday.EffortDuration.IEffortFrom;
import org.libreplan.business.workingday.ResourcesPerDay;
import org.libreplan.web.common.EffortDurationBox;
import org.libreplan.web.common.LenientDecimalBox;
import org.libreplan.web.common.Util;
import org.libreplan.web.planner.allocation.ResourceAllocationController.DerivedAllocationColumn;
import org.zkoss.zk.au.out.AuWrongValue;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.SimpleConstraint;
import org.zkoss.zul.SimpleListModel;

import com.igalia.java.zk.components.customdetailrowcomponent.Detail;

/**
* It connects the GUI widgets of the allocation row in the GUI with the
* {@link AllocationRow#transientAllocationBeingModified}.
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public abstract class AllocationRow {

    private static final ResourcesPerDay RESOURCES_PER_DAY_DEFAULT_VALUE = ResourcesPerDay
            .amount(1);

    public static final SimpleConstraint CONSTRAINT_FOR_RESOURCES_PER_DAY = new SimpleConstraint(
            SimpleConstraint.NO_EMPTY | SimpleConstraint.NO_NEGATIVE);

    private static final SimpleConstraint CONSTRAINT_FOR_HOURS_INPUT = new SimpleConstraint(
            SimpleConstraint.NO_EMPTY | SimpleConstraint.NO_NEGATIVE);

    private static final Log LOG = LogFactory.getLog(AllocationRow.class);

    public static EffortDuration sumAllConsolidatedEffort(
            Collection<? extends AllocationRow> rows) {
        return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() {

            @Override
            public EffortDuration from(AllocationRow each) {
                return each.getConsolidatedEffort();
            }
        });
    }

    public static EffortDuration sumAllTotalEffort(
            Collection<? extends AllocationRow> rows) {
        return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() {

            @Override
            public EffortDuration from(AllocationRow each) {
                return each.getTotalEffort();
            }

        });
    }

    public static EffortDuration sumAllOriginalEffort(
            Collection<? extends AllocationRow> rows) {
        return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() {
            @Override
            public EffortDuration from(AllocationRow each) {
                return each.getOriginalEffort();
            }
        });
    }

    public static EffortDuration sumAllEffortFromInputs(
            Collection<? extends AllocationRow> rows) {
        return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() {

            @Override
            public EffortDuration from(AllocationRow each) {
                return each.getEffortFromInput();
            }
        });
    }

    public static void assignEfforts(List<AllocationRow> rows,
            EffortDuration[] efforts) {
        int i = 0;
        for (AllocationRow each : rows) {
            each.effortInput.setValue(efforts[i++]);
        }
    }

    public static void unknownResourcesPerDay(List<AllocationRow> rows) {
        for (AllocationRow each : rows) {
            each.setUnknownResourcesPerDay();
        }
    }

    public static void assignResourcesPerDay(List<AllocationRow> rows,
            ResourcesPerDay[] resourcesPerDay) {
        int i = 0;
        for (AllocationRow each : rows) {
            each.setResourcesPerDayEditedValue(resourcesPerDay[i++]);
            each.clearRealResourcesPerDay();
        }
    }

    public static void updateUIWithModificationsDone(List<? extends AllocationRow> rows,
            List<? extends AllocationModification> modifications) {
        Validate.isTrue(rows.size() == modifications.size());
        Iterator<? extends AllocationModification> iterator = modifications
                .iterator();
        for (AllocationRow each : rows) {
            each.updateUIWithModificationsDone();
            each.clearRealResourcesPerDay();

            AllocationModification modification = iterator.next();
            if (!modification.satisfiesModificationRequested()) {
                each.warnObjectiveNotSatisfied(modification);
            }
        }
    }

    public static List<ResourcesPerDayModification> createAndAssociate(
            Task task, Collection<? extends AllocationRow> rows,
            Collection<? extends ResourceAllocation<?>> requestedToRemove) {
        List<ResourcesPerDayModification> result = new ArrayList<ResourcesPerDayModification>();
        for (AllocationRow each : rows) {
            ResourcesPerDayModification modification = each
                    .toResourcesPerDayModification(task);
            result.add(modification);
            each.associateAllocationToModify(modification.getBeingModified());
        }
        setCustomAssignedEffortForResource(rows, requestedToRemove);
        return result;
    }

    private static void setCustomAssignedEffortForResource(
            Collection<? extends AllocationRow> rows,
            Collection<? extends ResourceAllocation<?>> requestedToRemove) {

        List<ResourceAllocation<?>> allocationsToDiscount = getToDiscount(rows);
        allocationsToDiscount.addAll(requestedToRemove);

        final IAssignedEffortForResource effortForResource = AssignedEffortForResource
                .effortDiscounting(allocationsToDiscount);
        List<ResourceAllocation<?>> beingModified = AllocationRow
                .getBeingModified(rows);
        final WithTheLoadOf withTheLoadOf = AssignedEffortForResource
                .withTheLoadOf(beingModified);

        for (GenericResourceAllocation each : ResourceAllocation.getOfType(GenericResourceAllocation.class, beingModified)) {
            IAssignedEffortForResource custom = AssignedEffortForResource.sum(
                    withTheLoadOf.withoutConsidering(each), effortForResource);
            each.setAssignedEffortForResource(custom);
        }
    }

    private static List<ResourceAllocation<?>> getToDiscount(
            Collection<? extends AllocationRow> rows) {
        List<ResourceAllocation<?>> result = new ArrayList<ResourceAllocation<?>>();
        for (AllocationRow each : rows) {
            if (each.getOrigin() != null) {
                result.add(each.getOrigin());
            }
        }
        return result;
    }

    public static AllocationRow find(Collection<? extends AllocationRow> rows,
            ResourceAllocation<?> allocationBeingModified) {
        for (AllocationRow each : rows) {
            if (each.transientAllocationBeingModified == allocationBeingModified) {
                return each;
            }
        }
        return null;
    }

    public static List<EffortModification> createHoursModificationsAndAssociate(
            Task task, List<AllocationRow> currentRows,
            Collection<? extends ResourceAllocation<?>> requestedToRemove) {
        List<EffortModification> result = new ArrayList<EffortModification>();
        for (AllocationRow each : currentRows) {
            EffortModification hoursModification = each
                    .toHoursModification(task);
            result.add(hoursModification);
            each.associateAllocationToModify(hoursModification
                    .getBeingModified());
        }
        setCustomAssignedEffortForResource(currentRows, requestedToRemove);
        return result;
    }

    public static List<ModifiedAllocation> getModificationsDone(
            Collection<? extends AllocationRow> rows) {
        List<ModifiedAllocation> result = new ArrayList<ModifiedAllocation>();
        for (AllocationRow each : rows) {
            Validate.notNull(each.transientAllocationBeingModified);
            if (each.original != null) {
                result.add(new ModifiedAllocation(each.original,
                        each.transientAllocationBeingModified));
            }
        }
        return result;
    }

    public static List<ResourceAllocation<?>> getNewFrom(
            List<AllocationRow> rows) {
        List<ResourceAllocation<?>> result = new ArrayList<ResourceAllocation<?>>();
        for (AllocationRow each : rows) {
            Validate.notNull(each.transientAllocationBeingModified);
            if (each.original == null) {
                result.add(each.transientAllocationBeingModified);
            }
        }
        return result;
    }

    public static List<ResourceAllocation<?>> getBeingModified(
            Collection<? extends AllocationRow> rows) {
        List<ResourceAllocation<?>> result = new ArrayList<ResourceAllocation<?>>();
        for (AllocationRow each : rows) {
            if (each.transientAllocationBeingModified != null) {
                result.add(each.transientAllocationBeingModified);
            }
        }
        return result;
    }

    public static List<GenericAllocationRow> getGeneric(
            Collection<? extends AllocationRow> all) {
        List<GenericAllocationRow> result = new ArrayList<GenericAllocationRow>();
        for (AllocationRow each : all) {
            if (each.isGeneric()) {
                result.add((GenericAllocationRow) each);
            }
        }
        return result;
    }

    public static List<AllocationRow> toRows(
            Collection<? extends ResourceAllocation<?>> resourceAllocations,
            IResourcesSearcher searchModel) {
        List<AllocationRow> result = new ArrayList<AllocationRow>();
        result.addAll(GenericAllocationRow.toGenericAllocations(
                resourceAllocations, searchModel));
        result.addAll(SpecificAllocationRow
                .toSpecificAllocations(resourceAllocations));
        return result;
    }

    /**
     * The original allocation. If <code>null</code> this {@link AllocationRow}
     * represents a new allocation. Otherwise, it's the modification of an
     * existing allocation.
     */
    private final ResourceAllocation<?> original;

    private CalculatedValue currentCalculatedValue;

    /**
     * The allocation that is being modified, it's not the one stored in the
     * database, only a copy used to receive the ongoing changes being done in
     * the allocation form. Later, the modifications are retrieved via
     * {@link AllocationRow#getModificationsDone(Collection)} and the changes
     * can be merged into the {@link AllocationRow#original} allocation.
     *
     * @see AllocationResult
     * @see AllocationRow#getModificationsDone(Collection)
     */
    private ResourceAllocation<?> transientAllocationBeingModified;

    private String name;

    private EffortDurationBox effortInput = new EffortDurationBox();

    private final Decimalbox intendedResourcesPerDayInput = new LenientDecimalBox();

    private ResourcesPerDay editedValue;

    private final Label realResourcesPerDay = new Label();

    private Grid derivedAllocationsGrid;

    private Listbox assignmentFunctionListbox;

    public AllocationRow(CalculatedValue calculatedValue) {
        this.currentCalculatedValue = calculatedValue;
        this.original = null;
        setResourcesPerDayEditedValue(RESOURCES_PER_DAY_DEFAULT_VALUE);
        initialize();
    }

    public AllocationRow(ResourceAllocation<?> origin) {
        this.original = origin;
        this.currentCalculatedValue = origin.getTask().getCalculatedValue();
        setResourcesPerDayEditedValue(resourcesPerDayForInputFrom(origin));
        if (origin != null && !origin.areIntendedResourcesPerDaySatisfied()) {
            onDifferentRealResourcesPerDay(origin
                    .getNonConsolidatedResourcePerDay());
        }
        loadEffort();
        initialize();
    }

    private static ResourcesPerDay resourcesPerDayForInputFrom(
            ResourceAllocation<?> resourceAllocation) {
        CalculatedValue calculatedValue = resourceAllocation.getTask()
                .getCalculatedValue();
        return calculatedValue == CalculatedValue.RESOURCES_PER_DAY ? resourceAllocation
                .getNonConsolidatedResourcePerDay() : resourceAllocation
                .getIntendedResourcesPerDay();
    }

    private void initializeResourcesPerDayInput() {
        intendedResourcesPerDayInput
                .setConstraint(CONSTRAINT_FOR_RESOURCES_PER_DAY);
        intendedResourcesPerDayInput.setSclass("assigned-resources-input");
        Util.bind(intendedResourcesPerDayInput, new Util.Getter<BigDecimal>() {

            @Override
            public BigDecimal get() {
                return getResourcesPerDayEditedValue().getAmount();
            }

        }, new Util.Setter<BigDecimal>() {

            @Override
            public void set(BigDecimal value) {
                BigDecimal amount = value == null ? new BigDecimal(0) : value;
                setResourcesPerDayEditedValue(ResourcesPerDay
                        .amount(amount));
            }
        });
    }

    private void initialize() {
        initializeResourcesPerDayInput();
        effortInput.setSclass("assigned-hours-input");
        effortInput.setConstraint(constraintForHoursInput());
        loadEffort();

        assignmentFunctionListbox = new Listbox();
        assignmentFunctionListbox.setMold("select");
        assignmentFunctionListbox.setStyle("font-size: 10px");

        updateAssignmentFunctionListbox();
    }

    private void updateAssignmentFunctionListbox() {
        initializeAndAppendFlatFunction(assignmentFunctionListbox);

        AssignmentFunction function = getAssignmentFunction();
        if (function != null) {
            Listitem listitem = new Listitem(_(function.getName()));
            listitem.setDisabled(true);
            assignmentFunctionListbox.appendChild(listitem);
            assignmentFunctionListbox.setSelectedItem(listitem);
        }
    }

    private void initializeAndAppendFlatFunction(
            Listbox assignmentFunctionListbox2) {
        Listitem listitem = new Listitem(
                _(AssignmentFunctionName.FLAT.toString()));
        assignmentFunctionListbox.getChildren().clear();
        assignmentFunctionListbox.appendChild(listitem);
        assignmentFunctionListbox.setSelectedItem(listitem);
    }

    public abstract ResourcesPerDayModification toResourcesPerDayModification(
            Task task);

    public abstract EffortModification toHoursModification(Task task);

    public boolean isCreating() {
        return original == null;
    }

    public boolean isModifying() {
        return original != null;
    }

    public ResourceAllocation<?> getOrigin() {
        return original;
    }

    private void onDifferentRealResourcesPerDay(
            ResourcesPerDay realResourcesPerDay) {
        this.realResourcesPerDay.setSclass("assigned-resources-label");
        this.realResourcesPerDay
                .setTooltiptext(_(
                        "Only {0} resources per day were achieved for current allocation",
                        realResourcesPerDay.getAmount().toPlainString()));
        this.realResourcesPerDay.setValue(realResourcesPerDay.getAmount()
                .toPlainString());
    }

    private void clearRealResourcesPerDay() {
        this.realResourcesPerDay.setValue("");
    }

    public boolean hasDerivedAllocations() {
        return ! getDerivedAllocations().isEmpty();
    }

    public List<DerivedAllocation> getDerivedAllocations() {
        if (transientAllocationBeingModified != null) {
            return new ArrayList<DerivedAllocation>(
                    transientAllocationBeingModified
                    .getDerivedAllocations());
        } else if (original != null) {
            return new ArrayList<DerivedAllocation>(
                    original
                    .getDerivedAllocations());
        } else {
            return Collections.emptyList();
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ResourcesPerDay getResourcesPerDayEditedValue() {
        return this.editedValue;
    }

    public ResourcesPerDay getResourcesPerDayFromInput() {
        BigDecimal value = intendedResourcesPerDayInput.getValue();
        value = value != null ? value : BigDecimal.ZERO;
        return ResourcesPerDay.amount(value);
    }

    private void setResourcesPerDayEditedValue(ResourcesPerDay resourcesPerDay) {
        this.editedValue = resourcesPerDay;
        intendedResourcesPerDayInput.setValue(getAmount(resourcesPerDay));
    }

    private void setUnknownResourcesPerDay() {
        this.editedValue = null;
        this.intendedResourcesPerDayInput.setValue((BigDecimal) null);
        clearRealResourcesPerDay();
    }

    private BigDecimal getAmount(ResourcesPerDay resourcesPerDay) {
        return (resourcesPerDay != null) ? resourcesPerDay.getAmount()
                : new BigDecimal(0);
    }

    private void associateAllocationToModify(
            ResourceAllocation<?> allocationToModify) {
        Validate.notNull(allocationToModify);
        this.transientAllocationBeingModified = allocationToModify;
    }

    public abstract boolean isGeneric();

    public boolean isEmptyResourcesPerDay() {
        return getResourcesPerDayEditedValue() == null
                || getResourcesPerDayEditedValue().isZero();
    }

    public abstract List<Resource> getAssociatedResources();

    public EffortDurationBox getEffortInput() {
        return effortInput;
    }

    public Decimalbox getIntendedResourcesPerDayInput() {
        return intendedResourcesPerDayInput;
    }

    public Label getRealResourcesPerDay() {
        return realResourcesPerDay;
    }

    public void addListenerForInputChange(EventListener onChangeListener) {
        getEffortInput().addEventListener(Events.ON_CHANGE, onChangeListener);
        getIntendedResourcesPerDayInput().addEventListener(Events.ON_CHANGE,
                onChangeListener);
    }

    public void loadEffort() {
        effortInput.setValue(getEffort());
    }

    public void loadAssignmentFunctionName() {
        updateAssignmentFunctionListbox();
    }

    protected EffortDuration getEffortFromInput() {
        return effortInput.getValue() != null ? effortInput
                .getEffortDurationValue()
                : zero();
    }

    private EffortDuration getEffort() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified.getNonConsolidatedEffort();
        }
        if (original != null) {
            return original.getNonConsolidatedEffort();
        }
        return zero();
    }

    public void applyDisabledRules(CalculatedValue calculatedValue,
            boolean recommendedAllocation, boolean isAnyManual) {
        this.currentCalculatedValue = calculatedValue;
        effortInput
                .setDisabled(calculatedValue !=CalculatedValue.RESOURCES_PER_DAY                        || recommendedAllocation || isAnyManual);
        effortInput.setConstraint(constraintForHoursInput());
        intendedResourcesPerDayInput
                .setDisabled(calculatedValue == CalculatedValue.RESOURCES_PER_DAY                        || recommendedAllocation || isAnyManual);
        if (intendedResourcesPerDayInput.isDisabled()) {
            clearRealResourcesPerDay();
        }
        intendedResourcesPerDayInput
                .setConstraint(constraintForResourcesPerDayInput());
    }

    private AssignmentFunction getAssignmentFunction() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified.getAssignmentFunction();
        }
        if (original != null) {
            return original.getAssignmentFunction();
        }
        return null;
    }

    public boolean isAssignmentFunctionNotFlat() {
        return getAssignmentFunction() != null;
    }

    public boolean isAssignmentFunctionManual() {
        AssignmentFunction assignmentFunction = getAssignmentFunction();
        return (assignmentFunction != null) && assignmentFunction.isManual();
    }

    private Constraint constraintForHoursInput() {
        return (effortInput.isDisabled()) ? null : CONSTRAINT_FOR_HOURS_INPUT;
    }

    private Constraint constraintForResourcesPerDayInput() {
        return (intendedResourcesPerDayInput.isDisabled()) ? null
                : CONSTRAINT_FOR_RESOURCES_PER_DAY;
    }

    private void updateUIWithModificationsDone() {
        Clients.closeErrorBox(effortInput);
        Clients.closeErrorBox(intendedResourcesPerDayInput);

        effortInput.setValue(transientAllocationBeingModified
                .getAssignedEffort());
        loadResourcesPerDayFrom(transientAllocationBeingModified);
    }

    private void warnObjectiveNotSatisfied(AllocationModification modification) {
        modification.byType(new IByType<Void>() {

            @Override
            public Void onResourcesPerDay(
                    ResourcesPerDayModification modification) {

                ResourcesPerDay realResourcesPerDay = modification
                        .getBeingModified().getNonConsolidatedResourcePerDay();
                onDifferentRealResourcesPerDay(realResourcesPerDay);

                return null;
            }

            @Override
            public Void onHours(EffortModification modification) {
                EffortDuration goal = modification.getEffort();
                Clients.response(new AuWrongValue(effortInput, _(
                        "{0} cannot be fulfilled", goal.toFormattedString())));

                return null;
            }
        });
    }

    public void addListenerForHoursInputChange(EventListener listener) {
        effortInput.addEventListener(Events.ON_CHANGE, listener);
    }

    public void setEffortToInput(EffortDuration effort) {
        effortInput.setValue(effort);
    }

    public void addListenerForResourcesPerDayInputChange(
            EventListener resourcesPerDayRowInputChange) {
        intendedResourcesPerDayInput.addEventListener(Events.ON_CHANGE,
                resourcesPerDayRowInputChange);
    }

    public void reloadDerivedAllocationsGrid() {
        if (hasDerivedAllocations() && !(currentDetail instanceof Detail)) {
            replaceOld(currentDetail, createDetail());
        }
        reloadDerivedAllocationsData();
    }

    private void reloadDerivedAllocationsData() {
        if (derivedAllocationsGrid != null) {
            derivedAllocationsGrid.setModel(new SimpleListModel(
                    getDerivedAllocations()));
        }
    }

    private void replaceOld(Component oldDetail, Component newDetail) {
        Component parent = oldDetail.getParent();
        parent.insertBefore(newDetail, oldDetail);
        parent.removeChild(oldDetail);
    }

    private Component currentDetail;

    public Component createDetail() {
        if (!hasDerivedAllocations()) {
            return currentDetail = new Label();
        }
        Detail result = new Detail();
        createDerivedAllocationsGrid();
        result.appendChild(derivedAllocationsGrid);
        reloadDerivedAllocationsData();
        return currentDetail = result;
    }

    private void createDerivedAllocationsGrid() {
        if (derivedAllocationsGrid != null) {
            return;
        }
        derivedAllocationsGrid = new Grid();
        DerivedAllocationColumn.appendColumnsTo(derivedAllocationsGrid);
        derivedAllocationsGrid.setRowRenderer(DerivedAllocationColumn
                .createRenderer());
    }

    public boolean isSatisfied() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified.isSatisfied();
        } else if (original != null) {
            return original.isSatisfied();
        } else {
            return false;
        }
    }

    public EffortDuration getOriginalEffort() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified.getIntendedTotalAssigment();
        }
        if (original != null) {
            return original.getIntendedTotalAssigment();
        }
        return zero();
    }

    public EffortDuration getTotalEffort() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified.getAssignedEffort();
        }
        if (original != null) {
            return original.getAssignedEffort();
        }
        return zero();
    }

    public EffortDuration getConsolidatedEffort() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified.getConsolidatedEffort();
        }
        if (original != null) {
            return original.getConsolidatedEffort();
        }
        return zero();
    }

    public int getNonConsolidatedHours() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified.getNonConsolidatedHours();
        }
        if (original != null) {
            return original.getNonConsolidatedHours();
        }
        return 0;
    }

    public ResourcesPerDay getTotalResourcesPerDay() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified
                    .calculateResourcesPerDayFromAssignments();
        }
        if (original != null) {
            return original.calculateResourcesPerDayFromAssignments();
        }
        return ResourcesPerDay.amount(0);
    }

    public ResourcesPerDay getConsolidatedResourcesPerDay() {
        if (transientAllocationBeingModified != null) {
            return transientAllocationBeingModified
                    .getConsolidatedResourcePerDay();
        }
        if (original != null) {
            return original.getConsolidatedResourcePerDay();
        }
        return ResourcesPerDay.amount(0);
    }

    public void loadResourcesPerDay() {
        loadResourcesPerDayFrom(transientAllocationBeingModified != null ? transientAllocationBeingModified
                : original);
    }

    private void loadResourcesPerDayFrom(ResourceAllocation<?> allocation) {
        setResourcesPerDayEditedValue(extractEditedValueFrom(allocation));
    }

    private ResourcesPerDay extractEditedValueFrom(
            ResourceAllocation<?> allocation) {
        if (allocation == null) {
            return ResourcesPerDay.amount(0);
        }
        boolean useIntention = currentCalculatedValue != CalculatedValue.RESOURCES_PER_DAY;
        return useIntention ? allocation.getIntendedResourcesPerDay()
                : allocation.getNonConsolidatedResourcePerDay();
    }

    public abstract ResourceEnum getType();

    private org.zkoss.zul.Row findRow() {
        Component current = null;
        do {
            current = effortInput.getParent();
        } while (!(current instanceof org.zkoss.zul.Row));
        return (org.zkoss.zul.Row) current;
    }

    public void markNoCapacity(
            final ResourcesPerDayModification allocationAttempt,
            CapacityResult capacityResult) {
        final org.zkoss.zul.Row row = findRow();
        capacityResult.match(new IMatcher<Void>() {

            @Override
            public Void on(CapacityAvailable result) {
                LOG.warn("shouldn't have happened");
                return null;
            }

            @Override
            public Void on(ThereAreNoValidPeriods result) {
                List<Interval> calendarValidPeriods = result
                        .getSpecifiedCalendar()
                        .getAvailability().getValidPeriods();
                AvailabilityTimeLine otherAvailability = result
                        .getSpecifiedAdditionalAvailability();
                if (calendarValidPeriods.isEmpty()) {
                    throw new WrongValueException(row,
                            _("there are no valid periods for this calendar"));
                } else if (otherAvailability.getValidPeriods().isEmpty()) {
                    throw new WrongValueException(row, allocationAttempt
                            .getNoValidPeriodsMessage());
                } else {
                    throw new WrongValueException(row, allocationAttempt
                            .getNoValidPeriodsMessageDueToIntersectionMessage());
                }
            }

            @Override
            public Void on(ValidPeriodsDontHaveCapacity result) {
                EffortDuration sumReached = result.getSumReached();
                List<Interval> validPeriods = result.getValidPeriods();
                String firstLine = _(
                        "In the available periods {0} only {1} hours are available.",
                        validPeriods, sumReached.getHours());
                String secondLine = isGeneric() ? _("Periods available depend on the satisfaction of the criteria of resources and their calendars.")
                        : _("Periods available depend on resources' calendar.");
                throw new WrongValueException(effortInput, firstLine + "\n"
                        + secondLine);
            }

            @Override
            public Void on(ResourcesPerDayIsZero result) {
                throw new WrongValueException(intendedResourcesPerDayInput,
                        _("Resources per day are zero"));
            }
        });
    }

    public Listbox getAssignmentFunctionListbox() {
        return assignmentFunctionListbox;
    }

    public void resetAssignmentFunction() {
        if (transientAllocationBeingModified == null) {
            associateAllocationToModify(original);
        }
    }

}
TOP

Related Classes of org.libreplan.web.planner.allocation.AllocationRow

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.