diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/limiting/entities/GapInterval.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/limiting/entities/GapInterval.java new file mode 100644 index 000000000..3936e6e13 --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/limiting/entities/GapInterval.java @@ -0,0 +1,129 @@ +/* + * This file is part of NavalPlan + * + * Copyright (C) 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 . + */ + +package org.navalplanner.business.planner.limiting.entities; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.joda.time.LocalDate; +import org.navalplanner.business.calendars.entities.CalendarAvailability; +import org.navalplanner.business.resources.entities.Resource; + +/** + * + * @author Diego Pino Garcia + * + * Represents the interval of time of a Gap. + * + * It's possible for a calendar assigned to a resource to define + * activation periods of time. This class is used to check if a gap is + * activated in a period of time. The method delimitByActivationPeriods + * returns the interval of time in which the gap in activated according + * to the calendar + * + * + */ +public class GapInterval { + + protected DateAndHour start; + + protected DateAndHour end; + + public static GapInterval create(DateAndHour start, DateAndHour end) { + return new GapInterval(start, end); + } + + public static Collection gapsOn( + List intervals, Resource resource) { + List result = new ArrayList(); + for (GapInterval each: intervals) { + result.add(each.gapOn(resource)); + } + return result; + } + + public GapInterval(DateAndHour start, DateAndHour end) { + this.start = start; + this.end = end; + } + + public List delimitByActivationPeriods( + List activationPeriods) { + List result = new ArrayList(); + for (CalendarAvailability interval: activationPeriods) { + GapInterval gapInterval = delimitByInterval(interval); + if (gapInterval != null) { + result.add(gapInterval); + } + } + return result; + } + + private GapInterval delimitByInterval(CalendarAvailability interval) { + LocalDate start = interval.getStartDate(); + LocalDate end = interval.getEndDate(); + + LocalDate newStart = max(start, interval.getStartDate()); + LocalDate newEnd = min(end, interval.getEndDate()); + if (newEnd != null && newStart.isAfter(newEnd)) { + // The period of time is not valid, as it's not period of time + // activated according to calendar + return null; + } + return GapInterval.create(DateAndHour.from(newStart), + newEnd != null ? DateAndHour.from(newEnd) : null); + } + + private LocalDate max(LocalDate date1, LocalDate date2) { + if (date1 == null && date2 == null) { + return null; + } + if (date1 != null && date2 == null) { + return date1; + } + if (date1 == null && date2 != null) { + return date2; + } + return date1.isAfter(date2) ? date1 : date2; + } + + private LocalDate min(LocalDate date1, LocalDate date2) { + if (date1 == null && date2 == null) { + return null; + } + if (date1 != null && date2 == null) { + return date1; + } + if (date1 == null && date2 != null) { + return date2; + } + return date1.isBefore(date2) || date1.isEqual(date2) ? date1 : date2; + } + + public Gap gapOn(Resource resource) { + return Gap.create(resource, start, end); + } + + public String toString() { + return String.format("[%s, %s]", start, end); + } + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/LimitingResourceQueue.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/LimitingResourceQueue.java index d39e12a07..51924830a 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/LimitingResourceQueue.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/LimitingResourceQueue.java @@ -33,10 +33,13 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import org.navalplanner.business.calendars.entities.CalendarAvailability; +import org.navalplanner.business.calendars.entities.ResourceCalendar; import org.navalplanner.business.common.BaseEntity; import org.navalplanner.business.planner.limiting.entities.DateAndHour; import org.navalplanner.business.planner.limiting.entities.Gap; import org.navalplanner.business.planner.limiting.entities.Gap.GapOnQueue; +import org.navalplanner.business.planner.limiting.entities.GapInterval; import org.navalplanner.business.planner.limiting.entities.InsertionRequirements; import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement; /** @@ -104,10 +107,18 @@ public class LimitingResourceQueue extends BaseEntity { private List calculateGaps() { List result = new ArrayList(); DateAndHour previousEnd = null; + ResourceCalendar calendar = resource.getCalendar(); + List activationPeriods = calendar.getCalendarAvailabilities(); + for (LimitingResourceQueueElement each : limitingResourceQueueElements) { DateAndHour startTime = each.getStartTime(); if (previousEnd == null || startTime.isAfter(previousEnd)) { - result.add(Gap.create(resource, previousEnd, startTime)); + List gapIntervals = GapInterval. + create(previousEnd, startTime). + delimitByActivationPeriods(activationPeriods); + if (!gapIntervals.isEmpty()) { + result.addAll(GapInterval.gapsOn(gapIntervals, resource)); + } } previousEnd = each.getEndTime(); }