/*
* 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.business.planner.entities;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.joda.time.LocalDate;
import org.libreplan.business.calendars.entities.AvailabilityTimeLine;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.planner.chart.ContiguousDaysLine;
import org.libreplan.business.planner.chart.ContiguousDaysLine.OnDay;
import org.libreplan.business.planner.chart.ResourceLoadChartData;
import org.libreplan.business.planner.entities.DayAssignment.FilterType;
import org.libreplan.business.resources.entities.IAssignmentsOnResourceCalculator;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.workingday.EffortDuration;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Diego Pino García <dpino@igalia.com>
*/
@Component
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class OrderResourceLoadCalculator implements IOrderResourceLoadCalculator {
private Order order;
private IAssignmentsOnResourceCalculator assignmentsOnResourceCalculator;
private ContiguousDaysLine<List<DayAssignment>> orderAssignments;
private ContiguousDaysLine<List<DayAssignment>> filteredAssignments;
private ContiguousDaysLine<EffortDuration> maxCapacityOnResources;
private ContiguousDaysLine<EffortDuration> orderLoad;
private ContiguousDaysLine<EffortDuration> allLoad;
private ContiguousDaysLine<EffortDuration> orderOverload;
private ContiguousDaysLine<EffortDuration> allOverload;
@Override
public void setOrder(Order order,
IAssignmentsOnResourceCalculator assignmentsOnResourceCalculator) {
this.order = order;
this.assignmentsOnResourceCalculator = assignmentsOnResourceCalculator;
initializeValues();
}
private void initializeValues() {
orderAssignments = null;
filteredAssignments = null;
maxCapacityOnResources = null;
orderLoad = null;
allLoad = null;
orderOverload = null;
allOverload = null;
}
@Override
public ContiguousDaysLine<EffortDuration> getMaxCapacityOnResources() {
if (maxCapacityOnResources == null) {
maxCapacityOnResources = getOrderAssignments()
.transform(ResourceLoadChartData
.extractAvailabilityOnAssignedResources());
}
return maxCapacityOnResources;
}
private ContiguousDaysLine<List<DayAssignment>> getOrderAssignments() {
if (orderAssignments == null) {
List<DayAssignment> orderDayAssignments = order
.getDayAssignments(FilterType.WITHOUT_DERIVED);
orderAssignments = ContiguousDaysLine.byDay(orderDayAssignments);
}
return orderAssignments;
}
@Override
public ContiguousDaysLine<EffortDuration> getOrderLoad() {
if (orderLoad == null) {
orderLoad = getOrderAssignments()
.transform(ResourceLoadChartData.extractLoad());
}
return orderLoad;
}
@Override
public ContiguousDaysLine<EffortDuration> getAllLoad() {
if (allLoad == null) {
allLoad = getFilteredAssignments()
.transform(ResourceLoadChartData.extractLoad());
}
return allLoad;
}
private ContiguousDaysLine<List<DayAssignment>> getFilteredAssignments() {
if (filteredAssignments == null) {
ContiguousDaysLine<List<DayAssignment>> allAssignments = allAssignments(getOrderAssignments());
filteredAssignments = filterAllAssignmentsByOrderResources(
allAssignments, getOrderAssignments());
}
return filteredAssignments;
}
private ContiguousDaysLine<List<DayAssignment>> filterAllAssignmentsByOrderResources(
ContiguousDaysLine<List<DayAssignment>> allAssignments,
ContiguousDaysLine<List<DayAssignment>> orderAssignments) {
List<DayAssignment> filteredAssignments = new ArrayList<DayAssignment>();
Iterator<OnDay<List<DayAssignment>>> iterator = orderAssignments
.iterator();
while (iterator.hasNext()) {
OnDay<List<DayAssignment>> onDay = iterator.next();
Set<Resource> resources = getResources(onDay.getValue());
filteredAssignments.addAll(filterAssignmentsByResource(
allAssignments.get(onDay.getDay()), resources));
}
return ContiguousDaysLine.byDay(filteredAssignments);
}
private List<DayAssignment> filterAssignmentsByResource(
List<DayAssignment> list, Set<Resource> resources) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
for (DayAssignment each : list) {
if (resources.contains(each.getResource())) {
result.add(each);
}
}
return result;
}
private Set<Resource> getResources(List<DayAssignment> dayAssignments) {
Set<Resource> resources = new HashSet<Resource>();
for (DayAssignment each : dayAssignments) {
resources.add(each.getResource());
}
return resources;
}
private ContiguousDaysLine<List<DayAssignment>> allAssignments(
ContiguousDaysLine<List<DayAssignment>> orderAssignments) {
if (orderAssignments.isNotValid()) {
return ContiguousDaysLine.<List<DayAssignment>> invalid();
}
return allAssignmentsOnResourcesAt(orderAssignments.getStart(),
orderAssignments.getEndExclusive());
}
private ContiguousDaysLine<List<DayAssignment>> allAssignmentsOnResourcesAt(
LocalDate startInclusive, LocalDate endExclusive) {
AvailabilityTimeLine.Interval interval = AvailabilityTimeLine.Interval
.create(startInclusive, endExclusive);
List<DayAssignment> resourcesDayAssignments = new ArrayList<DayAssignment>();
for (Resource resource : order.getResources(FilterType.WITHOUT_DERIVED)) {
resourcesDayAssignments.addAll(insideInterval(interval,
assignmentsOnResourceCalculator.getAssignments(resource)));
}
return ContiguousDaysLine.byDay(resourcesDayAssignments);
}
private List<DayAssignment> insideInterval(
AvailabilityTimeLine.Interval interval,
List<DayAssignment> assignments) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
for (DayAssignment each : assignments) {
if (interval.includes(each.getDay())) {
result.add(each);
}
}
return result;
}
@Override
public ContiguousDaysLine<EffortDuration> getOrderOverload() {
if (orderOverload == null) {
orderOverload = getOrderAssignments()
.transform(ResourceLoadChartData.extractOverload());
}
return orderOverload;
}
@Override
public ContiguousDaysLine<EffortDuration> getAllOverload() {
if (allOverload == null) {
allOverload = getFilteredAssignments()
.transform(ResourceLoadChartData.extractOverload());
}
return allOverload;
}
}