/*
* 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.resources.entities;
import static org.libreplan.business.planner.limiting.entities.LimitingResourceQueueElement.isAfter;
import static org.libreplan.business.planner.limiting.entities.LimitingResourceQueueElement.isInTheMiddle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.libreplan.business.calendars.entities.CalendarAvailability;
import org.libreplan.business.calendars.entities.ResourceCalendar;
import org.libreplan.business.common.BaseEntity;
import org.libreplan.business.planner.limiting.entities.DateAndHour;
import org.libreplan.business.planner.limiting.entities.Gap;
import org.libreplan.business.planner.limiting.entities.Gap.GapOnQueue;
import org.libreplan.business.planner.limiting.entities.GapInterval;
import org.libreplan.business.planner.limiting.entities.InsertionRequirements;
import org.libreplan.business.planner.limiting.entities.LimitingResourceQueueElement;
/**
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public class LimitingResourceQueue extends BaseEntity {
private Resource resource;
private SortedSet<LimitingResourceQueueElement> limitingResourceQueueElements =
new TreeSet<LimitingResourceQueueElement>(new LimitingResourceQueueElementComparator());
private List<GapOnQueue> cachedGaps;
public static Collection<LimitingResourceQueue> queuesOf(
Collection<LimitingResourceQueueElement> queueElements) {
Set<LimitingResourceQueue> result = new HashSet<LimitingResourceQueue>();
for (LimitingResourceQueueElement each: queueElements) {
result.add(each.getLimitingResourceQueue());
}
return result;
}
public static LimitingResourceQueue create() {
return create(new LimitingResourceQueue());
}
protected LimitingResourceQueue() {
}
public Resource getResource() {
return resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
public void addLimitingResourceQueueElement(LimitingResourceQueueElement element) {
element.setLimitingResourceQueue(this);
limitingResourceQueueElements.add(element);
invalidCachedGaps();
}
public void removeLimitingResourceQueueElement(LimitingResourceQueueElement element) {
limitingResourceQueueElements.remove(element);
element.detach();
invalidCachedGaps();
}
private void invalidCachedGaps() {
cachedGaps = null;
}
public List<GapOnQueue> getGaps() {
if (cachedGaps == null) {
cachedGaps = calculateGaps();
}
return cachedGaps;
}
private List<GapOnQueue> calculateGaps() {
List<Gap> result = new ArrayList<Gap>();
DateAndHour previousEnd = null;
ResourceCalendar calendar = resource.getCalendar();
List<CalendarAvailability> activationPeriods = calendar.getCalendarAvailabilities();
for (LimitingResourceQueueElement each : limitingResourceQueueElements) {
DateAndHour startTime = each.getStartTime();
if (previousEnd == null || startTime.isAfter(previousEnd)) {
List<GapInterval> gapIntervals = GapInterval.
create(previousEnd, startTime).
delimitByActivationPeriods(activationPeriods);
if (!gapIntervals.isEmpty()) {
result.addAll(GapInterval.gapsOn(gapIntervals, resource));
}
}
previousEnd = each.getEndTime();
}
result.add(Gap.create(resource, previousEnd, null));
return GapOnQueue.onQueue(this, result);
}
public SortedSet<LimitingResourceQueueElement> getLimitingResourceQueueElements() {
return Collections.unmodifiableSortedSet(limitingResourceQueueElements);
}
/**
* @return the gaps that could potentially be valid for
* <code>requirements</code> ordered by start date
*/
public List<GapOnQueue> getGapsPotentiallyValidFor(
InsertionRequirements requirements) {
List<GapOnQueue> result = new ArrayList<GapOnQueue>();
for (GapOnQueue each : getGaps()) {
if (requirements.isPotentiallyValid(each.getGap())) {
result.add(each);
}
}
return result;
}
public List<LimitingResourceQueueElement> getElementsAfter(
LimitingResourceQueueElement element) {
List<LimitingResourceQueueElement> queueElements = new ArrayList<LimitingResourceQueueElement>(
limitingResourceQueueElements);
int position = Collections.binarySearch(queueElements, element,
LimitingResourceQueueElement.byStartTimeComparator());
assert position >= 0 : "the element must be in the list";
return queueElements.subList(position + 1, queueElements.size());
}
public List<LimitingResourceQueueElement> getElementsSince(DateAndHour time) {
List<LimitingResourceQueueElement> result = new ArrayList<LimitingResourceQueueElement>();
for (LimitingResourceQueueElement each: getLimitingResourceQueueElements()) {
if (isInTheMiddle(each, time) || isAfter(each, time)) {
result.add(each);
}
}
return result;
}
public void queueElementMoved(
LimitingResourceQueueElement limitingResourceQueueElement) {
invalidCachedGaps();
}
public String toString() {
return getResource() != null ? getResource().getName() : "";
}
}