Package org.libreplan.business.planner.entities

Source Code of org.libreplan.business.planner.entities.SpecificResourceAllocation$SpecificAssignmentsAllocator

/*
* 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.business.planner.entities;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.Validate;
import javax.validation.constraints.NotNull;
import javax.validation.Valid;
import org.joda.time.LocalDate;
import org.libreplan.business.calendars.entities.AvailabilityTimeLine;
import org.libreplan.business.calendars.entities.AvailabilityTimeLine.FixedPoint;
import org.libreplan.business.calendars.entities.AvailabilityTimeLine.Interval;
import org.libreplan.business.calendars.entities.Capacity;
import org.libreplan.business.calendars.entities.CombinedWorkHours;
import org.libreplan.business.calendars.entities.ICalendar;
import org.libreplan.business.common.ProportionalDistributor;
import org.libreplan.business.planner.entities.allocationalgorithms.ResourcesPerDayModification;
import org.libreplan.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.libreplan.business.resources.daos.IResourcesSearcher;
import org.libreplan.business.resources.entities.Criterion;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.scenarios.entities.Scenario;
import org.libreplan.business.util.deepcopy.OnCopy;
import org.libreplan.business.util.deepcopy.Strategy;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workingday.EffortDuration.IEffortFrom;
import org.libreplan.business.workingday.IntraDayDate;
import org.libreplan.business.workingday.IntraDayDate.PartialDay;
import org.libreplan.business.workingday.ResourcesPerDay;

/**
* Represents the relation between {@link Task} and a specific {@link Worker}.
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public class SpecificResourceAllocation extends
        ResourceAllocation<SpecificDayAssignment> implements IAllocatable {

    public static SpecificResourceAllocation create(Task task) {
        return create(new SpecificResourceAllocation(
                task));
    }

    /**
     * Creates a {@link SpecificResourceAllocation} for a
     * {@link LimitingResourceQueueElement}
     *
     * The process of creating a specific resource allocation for a queue
     * element is different as it's necessary to assign a resource and a number
     * of resources per day without allocating day assignments
     *
     * @param resource
     * @param task
     * @return
     */
    public static SpecificResourceAllocation createForLimiting(Resource resource,
            Task task) {
        assert resource.isLimitingResource();
        SpecificResourceAllocation result = create(new SpecificResourceAllocation(
                task));
        result.setResource(resource);
        result.setResourcesPerDayToAmount(1);
        return result;
    }

    @OnCopy(Strategy.SHARE)
    private Resource resource;

    private Set<SpecificDayAssignmentsContainer> specificDayAssignmentsContainers = new HashSet<SpecificDayAssignmentsContainer>();

    @Valid
    private Set<SpecificDayAssignmentsContainer> getSpecificDayAssignmentsContainers() {
        return new HashSet<SpecificDayAssignmentsContainer>(
                specificDayAssignmentsContainers);
    }

    public static SpecificResourceAllocation createForTesting(
            ResourcesPerDay resourcesPerDay, Task task) {
        return create(new SpecificResourceAllocation(
                resourcesPerDay, task));
    }

    public SpecificResourceAllocation() {
    }

    @Override
    protected SpecificDayAssignmentsContainer retrieveOrCreateContainerFor(
            Scenario scenario) {
        SpecificDayAssignmentsContainer retrieved = retrieveContainerFor(scenario);
        if (retrieved != null) {
            return retrieved;
        }
        SpecificDayAssignmentsContainer result = SpecificDayAssignmentsContainer
                .create(this, scenario);
        specificDayAssignmentsContainers.add(result);
        return result;
    }

    @Override
    protected SpecificDayAssignmentsContainer retrieveContainerFor(
            Scenario scenario) {
        Map<Scenario, SpecificDayAssignmentsContainer> containers = containersByScenario();
        return containers.get(scenario);
    }

    private SpecificResourceAllocation(ResourcesPerDay resourcesPerDay,
            Task task) {
        super(resourcesPerDay, task);
    }

    private SpecificResourceAllocation(Task task) {
        super(task);
    }

    @NotNull
    public Resource getResource() {
        return resource;
    }

    private Map<Scenario, SpecificDayAssignmentsContainer> containersByScenario() {
        Map<Scenario, SpecificDayAssignmentsContainer> result = new HashMap<Scenario, SpecificDayAssignmentsContainer>();
        for (SpecificDayAssignmentsContainer each : specificDayAssignmentsContainers) {
            assert !result.containsKey(each);
            result.put(each.getScenario(), each);
        }
        return result;
    }

    public void setResource(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void allocate(ResourcesPerDay resourcesPerDay) {
        Validate.notNull(resourcesPerDay);
        Validate.notNull(resource);
        new SpecificAssignmentsAllocator().allocate(resourcesPerDay);
    }

    @Override
    public IAllocateResourcesPerDay resourcesPerDayUntil(
            IntraDayDate endExclusive) {
        return new SpecificAssignmentsAllocator()
                .resourcesPerDayUntil(endExclusive);
    }

    @Override
    public IAllocateResourcesPerDay resourcesPerDayFromEndUntil(
            IntraDayDate start) {
        SpecificAssignmentsAllocator allocator = new SpecificAssignmentsAllocator();
        return allocator.resourcesPerDayFromEndUntil(start);
    }

    @Override
    public IAllocateEffortOnInterval fromStartUntil(IntraDayDate end) {
        return new SpecificAssignmentsAllocator().fromStartUntil(end);
    }

    @Override
    public IAllocateEffortOnInterval fromEndUntil(IntraDayDate start) {
        return new SpecificAssignmentsAllocator().fromEndUntil(start);
    }

    private final class SpecificAssignmentsAllocator extends
            AssignmentsAllocator {

        @Override
        public List<SpecificDayAssignment> distributeForDay(PartialDay day,
                EffortDuration effort) {
            return Arrays.asList(SpecificDayAssignment.create(day.getDate(),
                    effort, resource));
        }

        @Override
        protected AvailabilityTimeLine getResourcesAvailability() {
            return AvailabilityCalculator.getCalendarAvailabilityFor(resource);
        }

        @Override
        protected Capacity getCapacityAt(PartialDay day) {
            return day.limitCapacity(getAllocationCalendar()
                    .getCapacityWithOvertime(day.getDate()));
        }

    }

    public IEffortDistributor<SpecificDayAssignment> createEffortDistributor() {
        return new SpecificAssignmentsAllocator();
    }

    @Override
    public IAllocateEffortOnInterval onIntervalWithinTask(LocalDate start, LocalDate end) {
        return new SpecificAssignmentsAllocator().onIntervalWithinTask(start, end);
    }

    @Override
    public IAllocateEffortOnInterval onIntervalWithinTask(IntraDayDate start,
            IntraDayDate end) {
        return new SpecificAssignmentsAllocator().onIntervalWithinTask(start,
                end);
    }

    @Override
    public IAllocateEffortOnInterval onInterval(LocalDate startInclusive,
            LocalDate endExclusive) {
        return new SpecificAssignmentsAllocator().onInterval(startInclusive,
                endExclusive);
    }

    @Override
    public IAllocateEffortOnInterval onInterval(IntraDayDate start,
            IntraDayDate end) {
        return new SpecificAssignmentsAllocator().onInterval(start, end);
    }

    @Override
    protected ICalendar getCalendarGivenTaskCalendar(ICalendar taskCalendar) {
        return CombinedWorkHours.minOf(taskCalendar, getResource()
                .getCalendar());
    }

    @Override
    protected Class<SpecificDayAssignment> getDayAssignmentType() {
        return SpecificDayAssignment.class;
    }

    @Override
    public IAllocatable withPreviousAssociatedResources() {
        return this;
    }

    @Override
    public List<Resource> getAssociatedResources() {
        return Arrays.asList(resource);
    }

    @Override
    ResourceAllocation<SpecificDayAssignment> createCopy(Scenario scenario) {
        SpecificResourceAllocation result = create(getTask());
        result.resource = getResource();
        return result;
    }

    @Override
    public ResourcesPerDayModification withDesiredResourcesPerDay(
            ResourcesPerDay resourcesPerDay) {
        return ResourcesPerDayModification.create(this, resourcesPerDay);
    }

    @Override
    public List<Resource> querySuitableResources(
            IResourcesSearcher resourcesSearcher) {
        return Collections.singletonList(resource);
    }

    @Override
    protected void setItselfAsParentFor(SpecificDayAssignment dayAssignment) {
        dayAssignment.setSpecificResourceAllocation(this);
    }

    @Override
    public void makeAssignmentsContainersDontPoseAsTransientAnyMore() {
        for (SpecificDayAssignmentsContainer each : specificDayAssignmentsContainers) {
            each.dontPoseAsTransientObjectAnymore();
        }
    }

    @Override
    public void copyAssignments(Scenario from, Scenario to) {
        SpecificDayAssignmentsContainer fromContainer = retrieveOrCreateContainerFor(from);
        SpecificDayAssignmentsContainer toContainer = retrieveOrCreateContainerFor(to);
        toContainer.resetTo(fromContainer.getDayAssignments());
    }

    @Override
    protected void removePredecessorContainersFor(Scenario scenario) {
        Map<Scenario, SpecificDayAssignmentsContainer> byScenario = containersByScenario();
        for (Scenario each : scenario.getPredecessors()) {
            SpecificDayAssignmentsContainer container = byScenario.get(each);
            if (container != null) {
                specificDayAssignmentsContainers.remove(container);
            }
        }
    }

    @Override
    protected void removeContainersFor(Scenario scenario) {
        SpecificDayAssignmentsContainer container = containersByScenario().get(
                scenario);
        if (container != null) {
            specificDayAssignmentsContainers.remove(container);
        }
    }

    /**
     * It does an allocation using the provided {@link EffortDuration} in the
     * not consolidated part in interval from the first day not consolidated to
     * the end provided. All previous not consolidated assignments are removed.
     *
     * @param effortForNotConsolidatedPart
     * @param endExclusive
     */
    public void allocateWholeAllocationKeepingProportions(
            EffortDuration effortForNotConsolidatedPart, IntraDayDate end) {
        AllocationInterval interval = new AllocationInterval(
                getIntraDayStartDate(), end);

        List<DayAssignment> nonConsolidatedAssignments = interval
                .getNoConsolidatedAssignmentsOnInterval();
        ProportionalDistributor distributor = ProportionalDistributor
                .create(asSeconds(nonConsolidatedAssignments));

        EffortDuration[] effortsPerDay = asEfforts(distributor
                .distribute(effortForNotConsolidatedPart.getSeconds()));
        allocateTheWholeAllocation(
                interval,
                assignmentsForEfforts(nonConsolidatedAssignments, effortsPerDay));
    }

    private EffortDuration[] asEfforts(int[] secondsArray) {
        EffortDuration[] result = new EffortDuration[secondsArray.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = EffortDuration.seconds(secondsArray[i]);
        }
        return result;
    }

    private List<SpecificDayAssignment> assignmentsForEfforts(
            List<DayAssignment> assignments, EffortDuration[] newEffortsPerDay) {
        List<SpecificDayAssignment> result = new ArrayList<SpecificDayAssignment>();
        int i = 0;
        for (DayAssignment each : assignments) {
            EffortDuration durationForAssignment = newEffortsPerDay[i++];
            result.add(SpecificDayAssignment.create(each.getDay(),
                    durationForAssignment, resource));
        }
        return result;
    }

    private int[] asSeconds(List<DayAssignment> assignments) {
        int[] result = new int[assignments.size()];
        int i = 0;
        for (DayAssignment each : assignments) {
            result[i++] = each.getDuration().getSeconds();
        }
        return result;
    }

    public void overrideConsolidatedDayAssignments(
            SpecificResourceAllocation origin) {
        if (origin != null) {
            List<SpecificDayAssignment> originAssignments = origin
                    .getConsolidatedAssignments();
            resetAssignmentsTo(SpecificDayAssignment
                    .copyToAssignmentsWithoutParent(originAssignments));
        }
    }

    @Override
    public EffortDuration getAssignedEffort(Criterion criterion,
            final IntraDayDate startInclusive, final IntraDayDate endExclusive) {

        return EffortDuration.sum(
                getIntervalsRelatedWith(criterion, startInclusive.getDate(),
                        endExclusive.asExclusiveEnd()),
                new IEffortFrom<Interval>() {

                    @Override
                    public EffortDuration from(Interval each) {
                        FixedPoint intervalStart = (FixedPoint) each.getStart();
                        FixedPoint intervalEnd = (FixedPoint) each.getEnd();
                        return getAssignedDuration(
                                IntraDayDate.convert(intervalStart.getDate(), startInclusive),
                                IntraDayDate.convert(intervalEnd.getDate(), endExclusive));
                    }
                });
    }

    private List<Interval> getIntervalsRelatedWith(Criterion criterion,
            LocalDate startInclusive, LocalDate endExclusive) {
        Interval queryInterval = AvailabilityTimeLine.Interval.create(
                startInclusive, endExclusive);

        List<Interval> result = new ArrayList<Interval>();
        for (Interval each : getIntervalsThisAllocationInterferesWith(criterion)) {
            if (queryInterval.overlaps(each)) {
                result.add(queryInterval.intersect(each));
            }
        }
        return result;
    }

    private List<Interval> getIntervalsThisAllocationInterferesWith(
            Criterion criterion) {
        AvailabilityTimeLine availability = AvailabilityCalculator
                .getCriterionsAvailabilityFor(Collections.singleton(criterion),
                        resource);
        availability.invalidUntil(getStartDate());
        availability.invalidFrom(getEndDate());
        return availability.getValidPeriods();
    }

    public boolean interferesWith(Criterion criterion,
            LocalDate startInclusive, LocalDate endExclusive) {
        List<Interval> intervalsRelatedWith = getIntervalsRelatedWith(
                criterion, startInclusive, endExclusive);
        return !intervalsRelatedWith.isEmpty();
    }


}
TOP

Related Classes of org.libreplan.business.planner.entities.SpecificResourceAllocation$SpecificAssignmentsAllocator

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.