/* * This file is part of LibrePlan * * Copyright (C) 2012 Óscar González Fernández * * 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.business.planner.entities; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.joda.time.LocalDate; import org.libreplan.business.common.BaseEntity; import org.libreplan.business.resources.entities.Resource; import org.libreplan.business.workingday.EffortDuration; /** * This class contains methods to build an {@link IAssignedEffortForResource}. * * @author Oscar Gonzalez Fernandez <ogfernandez@gmail.com> */ public class AssignedEffortForResource { /** * It allows to know how much load a Resource has at the given day. It's * used by {@link GenericResourceAllocation} so it distributes new load * among the least loaded resources. The right object implementing this * interface is built using factory methods from * {@link AssignedEffortForResource}. * * @see AssignedEffortForResource#sum(IAssignedEffortForResource...) * @see AssignedEffortForResource#withTheLoadOf(Collection) */ public interface IAssignedEffortForResource { public EffortDuration getAssignedDurationAt(Resource resource, LocalDate day); } private AssignedEffortForResource() { // not instantiable } /** * It returns a new {@link IAssignedEffortForResource} that looks into * {@link Resource#dayAssignments} for knowing which load the * {@link Resource} has for a given day. * * Sometimes we have to discount the load of some allocations that are being * removed or changed. They can be provided to this method. * * @param allocations * The allocations whose load shouldn't be summed. * @return A {@link IAssignedEffortForResource} that calculates the load * associated for all allocations but the provided ones. */ public static IAssignedEffortForResource effortDiscounting(Collection<? extends BaseEntity> allocations) { return new AssignedEffortDiscounting(allocations); } /** * It creates a new {@link IAssignedEffortForResource} that sums all * provided {@link IAssignedEffortForResource}. Sometimes you have to * combine several {@link IAssignedEffortForResource} to calculate the right * effort. * @param assignedEffortForResources * The {@link IAssignedEffortForResource} to sum. * @return a {@link IAssignedEffortForResource} that returns the sum of * calling all provided <code>assignedEffortForResources</code>. */ public static IAssignedEffortForResource sum( final IAssignedEffortForResource... assignedEffortForResources) { return new IAssignedEffortForResource() { @Override public EffortDuration getAssignedDurationAt(Resource resource, LocalDate day) { EffortDuration result = EffortDuration.zero(); for (IAssignedEffortForResource each : assignedEffortForResources) { EffortDuration e = each .getAssignedDurationAt(resource, day); if (e != null) { result = result.plus(e); } } return result; } }; } /** * @see AssignedEffortForResource#sum(IAssignedEffortForResource...) */ public static IAssignedEffortForResource sum( Collection<? extends IAssignedEffortForResource> assignedEffortForResources) { return sum(assignedEffortForResources .toArray(new IAssignedEffortForResource[0])); } public static WithTheLoadOf withTheLoadOf( Collection<? extends ResourceAllocation<?>> allocations) { return new WithTheLoadOf(allocations); } /** * This class allows to specify the load of some {@link ResourceAllocation * resource allocations} which their {@link DayAssignment day assignments} * aren't associated to a Resource yet. Without this, their load wouldn't be * noticed. */ public static class WithTheLoadOf implements IAssignedEffortForResource { private final Set<? extends ResourceAllocation<?>> allocations; private final IAssignedEffortForResource implementation; public WithTheLoadOf( Collection<? extends ResourceAllocation<?>> allocations) { this.allocations = new HashSet<ResourceAllocation<?>>(allocations); this.implementation = sum(this.allocations); } @Override public EffortDuration getAssignedDurationAt(Resource resource, LocalDate day) { return implementation.getAssignedDurationAt(resource, day); } /** * It returns a {@link IAssignedEffortForResource} that returns the same * load as <code>this</code> but without the provided * <code>allocation</code>. When you're doing an allocation you don't * want to consider the allocation currently being done, so it's * excluded. */ public WithTheLoadOf withoutConsidering(ResourceAllocation<?> allocation) { Set<ResourceAllocation<?>> copy = new HashSet<ResourceAllocation<?>>( this.allocations); copy.remove(allocation); return new WithTheLoadOf(copy); } } private static class AssignedEffortDiscounting implements IAssignedEffortForResource { private final Map<Long, Set<BaseEntity>> allocations; AssignedEffortDiscounting(Collection<? extends BaseEntity> discountFrom) { this.allocations = BaseEntity.byId(discountFrom); } public EffortDuration getAssignedDurationAt(Resource resource, LocalDate day) { return resource.getAssignedDurationDiscounting(allocations, day); } } }