/*
* 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.limiting.entities;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.joda.time.LocalDate;
import org.libreplan.business.planner.entities.DayAssignment;
import org.libreplan.business.planner.entities.GenericDayAssignment;
import org.libreplan.business.planner.entities.GenericResourceAllocation;
import org.libreplan.business.planner.entities.ResourceAllocation;
import org.libreplan.business.planner.entities.SpecificDayAssignment;
import org.libreplan.business.planner.entities.SpecificResourceAllocation;
import org.libreplan.business.planner.limiting.entities.Gap.GapOnQueue;
import org.libreplan.business.resources.entities.LimitingResourceQueue;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.workingday.EffortDuration;
public abstract class AllocationSpec {
public static AllocationSpec invalidOn(GapOnQueue gap) {
return new InvalidAllocationAttempt(gap);
}
public static AllocationSpec validOn(
LimitingResourceQueueElement element, GapOnQueue gap,
DateAndHour start,
DateAndHour endExclusive, int[] assignableHours) {
return new ValidAllocationAttempt(element, gap, start, endExclusive,
assignableHours);
}
private final GapOnQueue originalGap;
private List<LimitingResourceQueueElement> unscheduled = new ArrayList<LimitingResourceQueueElement>();
protected AllocationSpec(GapOnQueue originalGap) {
Validate.notNull(originalGap);
this.originalGap = originalGap;
}
public abstract boolean isValid();
public abstract List<DayAssignment> getAssignmentsFor(
ResourceAllocation<?> allocation, Resource resource)
throws IllegalStateException;
public abstract LimitingResourceQueueElement getElement()
throws IllegalStateException;
public abstract DateAndHour getStartInclusive()
throws IllegalStateException;
public abstract DateAndHour getEndExclusive() throws IllegalStateException;
public Gap getGap() {
return originalGap.getGap();
}
public LimitingResourceQueue getQueue() {
return originalGap.getOriginQueue();
}
public boolean isAppropriative() {
return !unscheduled.isEmpty();
}
public void setUnscheduledElements(
List<LimitingResourceQueueElement> queueElements) {
unscheduled.addAll(queueElements);
}
public List<LimitingResourceQueueElement> getUnscheduledElements() {
return unscheduled;
}
}
class InvalidAllocationAttempt extends AllocationSpec {
private static final String INVALID_ALLOCATION_ON_GAP = "invalid allocation on gap";
InvalidAllocationAttempt(GapOnQueue originalGap) {
super(originalGap);
}
@Override
public boolean isValid() {
return false;
}
@Override
public List<DayAssignment> getAssignmentsFor(
ResourceAllocation<?> allocation, Resource resource) {
throw new IllegalStateException(INVALID_ALLOCATION_ON_GAP);
}
@Override
public LimitingResourceQueueElement getElement()
throws IllegalStateException {
throw new IllegalStateException(INVALID_ALLOCATION_ON_GAP);
}
@Override
public DateAndHour getEndExclusive() throws IllegalStateException {
throw new IllegalStateException(INVALID_ALLOCATION_ON_GAP);
}
@Override
public DateAndHour getStartInclusive() throws IllegalStateException {
throw new IllegalStateException(INVALID_ALLOCATION_ON_GAP);
}
}
class ValidAllocationAttempt extends AllocationSpec {
private final LimitingResourceQueueElement element;
private final DateAndHour start;
private final DateAndHour end;
private final int[] assignableHours;
public ValidAllocationAttempt(LimitingResourceQueueElement element,
GapOnQueue gap, DateAndHour startInclusive,
DateAndHour endExclusive, int[] assignableHours) {
super(gap);
Validate.notNull(element);
Validate.notNull(startInclusive);
Validate.notNull(endExclusive);
Validate.notNull(assignableHours);
Validate.isTrue(endExclusive.isAfter(startInclusive));
this.element = element;
this.start = startInclusive;
this.end = endExclusive;
Validate.isTrue(assignableHours.length == toFiniteList(
start.daysUntil(end)).size());
this.assignableHours = assignableHours.clone();
}
private List<LocalDate> toFiniteList(Iterable<LocalDate> daysUntil) {
List<LocalDate> result = new ArrayList<LocalDate>();
for (LocalDate each : daysUntil) {
result.add(each);
}
return result;
}
@Override
public List<DayAssignment> getAssignmentsFor(
ResourceAllocation<?> allocation, Resource resource)
throws IllegalStateException {
List<LocalDate> days = toFiniteList(start.daysUntil(end));
assert assignableHours.length == days.size();
if (allocation instanceof SpecificResourceAllocation) {
return createSpecific(days,
(SpecificResourceAllocation) allocation, resource);
} else {
return createGeneric(days, (GenericResourceAllocation) allocation,
resource);
}
}
private List<DayAssignment> createSpecific(List<LocalDate> days,
SpecificResourceAllocation allocation, Resource resource) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
int i = 0;
for (LocalDate each : days) {
EffortDuration hours = EffortDuration.hours(assignableHours[i]);
result.add(SpecificDayAssignment.create(each, hours, resource));
i++;
}
return result;
}
private List<DayAssignment> createGeneric(List<LocalDate> days,
GenericResourceAllocation allocation, Resource resource) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
int i = 0;
for (LocalDate each : days) {
EffortDuration hours = EffortDuration.hours(assignableHours[i]);
result.add(GenericDayAssignment.create(each, hours, resource));
i++;
}
return result;
}
@Override
public LimitingResourceQueueElement getElement() {
return element;
}
@Override
public DateAndHour getEndExclusive() throws IllegalStateException {
return end;
}
@Override
public DateAndHour getStartInclusive() throws IllegalStateException {
return start;
}
@Override
public boolean isValid() {
return true;
}
}