ItEr49S10CUVisualizacionResponsabilidadesTRaballoNaPlanificacionItEr48S10: Changing the way hours are distributed.

If some row cannot be satisfied the whole hours are distributed among
the remaining ones and so on.
This commit is contained in:
Óscar González Fernández 2010-02-23 21:05:47 +01:00
parent dcb1b1aba5
commit 41576f6bb5

View file

@ -29,6 +29,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.ResourceAllocation;
@ -57,29 +58,30 @@ public abstract class AllocatorForSpecifiedResourcesPerDayAndHours {
}
public LocalDate untilAllocating(int hoursToAllocate) {
LocalDate start = LocalDate.fromDateFields(task.getStartDate());
int i = 0;
int maxDaysElapsed = 0;
for (Integer each : hoursForEachAllocation(hoursToAllocate)) {
ResourcesPerDayModification currentAllocation = allocations.get(i);
int daysElapsedForCurrent = untilAllocating(currentAllocation, each);
for (HoursPerAllocation each : hoursPerAllocation(start,
hoursToAllocate)) {
int daysElapsedForCurrent = untilAllocating(start, each.allocation,
each.hours);
maxDaysElapsed = Math.max(maxDaysElapsed, daysElapsedForCurrent);
i++;
}
setAssignmentsForEachAllocation();
LocalDate start = LocalDate.fromDateFields(task.getStartDate());
return start.plusDays(maxDaysElapsed);
}
private int untilAllocating(
private List<HoursPerAllocation> hoursPerAllocation(LocalDate start,
int toBeAssigned) {
return new HoursPerAllocationCalculator(allocations)
.calculateHoursPerAllocation(start, toBeAssigned);
}
private int untilAllocating(LocalDate start,
ResourcesPerDayModification resourcesPerDayModification,
Integer hoursToAllocate) {
int hoursRemaining = hoursToAllocate;
LocalDate start = new LocalDate(task.getStartDate().getTime());
if (!thereAreAvailableHoursFrom(start, resourcesPerDayModification,
hoursToAllocate)) {
markUnsatisfied(resourcesPerDayModification.getBeingModified());
return 0;
}
int day = 0;
while (hoursRemaining > 0) {
LocalDate current = start.plusDays(day);
@ -126,65 +128,130 @@ public abstract class AllocatorForSpecifiedResourcesPerDayAndHours {
return DayAssignment.sum(newAssignments);
}
private List<Integer> hoursForEachAllocation(int toBeAssigned) {
BigDecimal[] limits = new BigDecimal[allocations.size()];
BigDecimal sumAll = sumAll();
for (int i = 0; i < limits.length; i++) {
BigDecimal amount = allocations.get(i).getGoal()
.getAmount();
limits[i] = amount.divide(sumAll, RoundingMode.DOWN).multiply(
new BigDecimal(toBeAssigned));
}
final int remainder = toBeAssigned - sumIntegerParts(limits);
return distributeRemainder(limits, remainder);
}
private static class HoursPerAllocation {
final int hours;
private List<Integer> distributeRemainder(BigDecimal[] decimals,
final int remainder) {
for (int i = 0; i < remainder; i++) {
int position = positionOfBiggestDecimalPart(decimals);
decimals[position] = new BigDecimal(
decimals[position].intValue() + 1);
}
return asIntegers(decimals);
}
final ResourcesPerDayModification allocation;
private List<Integer> asIntegers(BigDecimal[] decimals) {
Integer[] result = new Integer[decimals.length];
for (int i = 0; i < result.length; i++) {
result[i] = decimals[i].intValue();
private HoursPerAllocation(int hours,
ResourcesPerDayModification allocation) {
this.hours = hours;
this.allocation = allocation;
}
return Arrays.asList(result);
}
private int positionOfBiggestDecimalPart(BigDecimal[] decimals) {
int result = 0;
BigDecimal currentBiggestDecimalPart = new BigDecimal(0);
for (int i = 0; i < decimals.length; i++) {
BigDecimal fractionalPart = decimals[i].subtract(new BigDecimal(
decimals[i].intValue()));
if (currentBiggestDecimalPart.compareTo(fractionalPart) < 0) {
currentBiggestDecimalPart = fractionalPart;
result = i;
public static List<HoursPerAllocation> wrap(
List<ResourcesPerDayModification> allocations,
List<Integer> hours) {
Validate.isTrue(hours.size() == allocations.size());
int i = 0;
List<HoursPerAllocation> result = new ArrayList<HoursPerAllocation>();
for(i = 0; i < allocations.size(); i++){
result.add(new HoursPerAllocation(hours.get(i), allocations
.get(i)));
}
return result;
}
return result;
}
private int sumIntegerParts(BigDecimal[] decimals) {
int sum = 0;
for (BigDecimal decimal : decimals) {
sum += decimal.intValue();
}
return sum;
}
private class HoursPerAllocationCalculator {
private List<ResourcesPerDayModification> allocations;
private BigDecimal sumAll() {
BigDecimal result = new BigDecimal(0);
for (ResourcesPerDayModification r : allocations) {
result = result.add(r.getGoal().getAmount());
private HoursPerAllocationCalculator(
List<ResourcesPerDayModification> allocations) {
this.allocations = new ArrayList<ResourcesPerDayModification>(
allocations);
}
return result;
public List<HoursPerAllocation> calculateHoursPerAllocation(
LocalDate start, int toAssign) {
do {
List<Integer> hours = calculateHours(toAssign);
List<HoursPerAllocation> result = HoursPerAllocation.wrap(
allocations, hours);
List<ResourcesPerDayModification> unsatisfied = getUnsatisfied(
start, result);
if (unsatisfied.isEmpty()) {
return result;
}
for (ResourcesPerDayModification each : unsatisfied) {
markUnsatisfied(each.getBeingModified());
}
allocations.removeAll(unsatisfied);
} while (true);
}
private List<ResourcesPerDayModification> getUnsatisfied(
LocalDate start, List<HoursPerAllocation> hoursPerAllocations) {
List<ResourcesPerDayModification> cannotSatisfy = new ArrayList<ResourcesPerDayModification>();
for (HoursPerAllocation each : hoursPerAllocations) {
if (!thereAreAvailableHoursFrom(start, each.allocation,
each.hours)) {
cannotSatisfy.add(each.allocation);
}
}
return cannotSatisfy;
}
private List<Integer> calculateHours(int toAssign) {
BigDecimal[] limits = new BigDecimal[allocations.size()];
BigDecimal sumAll = sumAll();
for (int i = 0; i < limits.length; i++) {
BigDecimal amount = allocations.get(i).getGoal().getAmount();
limits[i] = amount.divide(sumAll, RoundingMode.DOWN).multiply(
new BigDecimal(toAssign));
}
final int remainder = toAssign - sumIntegerParts(limits);
return distributeRemainder(limits, remainder);
}
private List<Integer> distributeRemainder(BigDecimal[] decimals,
final int remainder) {
for (int i = 0; i < remainder; i++) {
int position = positionOfBiggestDecimalPart(decimals);
decimals[position] = new BigDecimal(decimals[position]
.intValue() + 1);
}
return asIntegers(decimals);
}
private List<Integer> asIntegers(BigDecimal[] decimals) {
Integer[] result = new Integer[decimals.length];
for (int i = 0; i < result.length; i++) {
result[i] = decimals[i].intValue();
}
return Arrays.asList(result);
}
private int positionOfBiggestDecimalPart(BigDecimal[] decimals) {
int result = 0;
BigDecimal currentBiggestDecimalPart = new BigDecimal(0);
for (int i = 0; i < decimals.length; i++) {
BigDecimal fractionalPart = decimals[i]
.subtract(new BigDecimal(decimals[i].intValue()));
if (currentBiggestDecimalPart.compareTo(fractionalPart) < 0) {
currentBiggestDecimalPart = fractionalPart;
result = i;
}
}
return result;
}
private int sumIntegerParts(BigDecimal[] decimals) {
int sum = 0;
for (BigDecimal decimal : decimals) {
sum += decimal.intValue();
}
return sum;
}
private BigDecimal sumAll() {
BigDecimal result = new BigDecimal(0);
for (ResourcesPerDayModification r : allocations) {
result = result.add(r.getGoal().getAmount());
}
return result;
}
}
}