All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.model.calendar.impl.CalendarServiceDataFactoryImpl Maven / Gradle / Ivy

There is a newer version: 2.6.0
Show newest version
/* This file is based on code copied from project OneBusAway, see the LICENSE file for further information. */
package org.opentripplanner.model.calendar.impl;

import static java.util.stream.Collectors.groupingBy;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opentripplanner.model.calendar.CalendarServiceData;
import org.opentripplanner.model.calendar.ServiceCalendar;
import org.opentripplanner.model.calendar.ServiceCalendarDate;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * We perform initial date calculations in the timezone of the host jvm, which may be different than
 * the timezone of an agency with the specified service id. To my knowledge, the calculation should
 * work the same, which is to say I can't immediately think of any cases where the service dates
 * would be computed incorrectly.
 *
 * @author bdferris
 */
public class CalendarServiceDataFactoryImpl {

  private static final Logger LOG = LoggerFactory.getLogger(CalendarServiceDataFactoryImpl.class);

  private final Map> calendarDatesByServiceId;
  private final Map> calendarsByServiceId;
  private final Set serviceIds;

  private CalendarServiceDataFactoryImpl(
    Collection calendarDates,
    Collection serviceCalendars
  ) {
    this.calendarDatesByServiceId =
      calendarDates.stream().collect(groupingBy(ServiceCalendarDate::getServiceId));
    this.calendarsByServiceId =
      serviceCalendars.stream().collect(groupingBy(ServiceCalendar::getServiceId));
    this.serviceIds = merge(calendarDatesByServiceId.keySet(), calendarsByServiceId.keySet());
  }

  public static CalendarServiceData createCalendarServiceData(
    Collection calendarDates,
    Collection serviceCalendars
  ) {
    return new CalendarServiceDataFactoryImpl(calendarDates, serviceCalendars).createData();
  }

  /** package local to be unit testable */
  static  Set merge(Collection set1, Collection set2) {
    Set newSet = new HashSet<>();
    newSet.addAll(set1);
    newSet.addAll(set2);
    return newSet;
  }

  private CalendarServiceData createData() {
    CalendarServiceData data = new CalendarServiceData();

    int index = 0;

    for (FeedScopedId serviceId : serviceIds) {
      index++;

      LOG.debug("serviceId={} ({}/{})", serviceId, index, serviceIds.size());

      Set activeDates = getServiceDatesForServiceId(serviceId);
      List serviceDates = new ArrayList<>(activeDates);
      Collections.sort(serviceDates);

      data.putServiceDatesForServiceId(serviceId, serviceDates);
    }

    return data;
  }

  private Set getServiceDatesForServiceId(FeedScopedId serviceId) {
    Set activeDates = new HashSet<>();
    ServiceCalendar c = findCalendarForServiceId(serviceId);

    if (c != null) {
      addDatesFromCalendar(c, activeDates);
    }
    List dates = calendarDatesByServiceId.get(serviceId);
    if (dates != null) {
      for (ServiceCalendarDate cd : dates) {
        addAndRemoveDatesFromCalendarDate(cd, activeDates);
      }
    }
    return activeDates;
  }

  private ServiceCalendar findCalendarForServiceId(FeedScopedId serviceId) {
    List calendars = calendarsByServiceId.get(serviceId);

    if (calendars == null || calendars.isEmpty()) {
      return null;
    }
    if (calendars.size() == 1) {
      return calendars.get(0);
    }
    throw new MultipleCalendarsForServiceIdException(serviceId);
  }

  private void addDatesFromCalendar(ServiceCalendar calendar, Set activeDates) {
    LocalDate startDate = calendar.getPeriod().getStart();
    LocalDate endDate = calendar.getPeriod().getEnd();

    for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
      if (
        switch (date.getDayOfWeek()) {
          case MONDAY -> calendar.getMonday() == 1;
          case TUESDAY -> calendar.getTuesday() == 1;
          case WEDNESDAY -> calendar.getWednesday() == 1;
          case THURSDAY -> calendar.getThursday() == 1;
          case FRIDAY -> calendar.getFriday() == 1;
          case SATURDAY -> calendar.getSaturday() == 1;
          case SUNDAY -> calendar.getSunday() == 1;
        }
      ) {
        addServiceDate(activeDates, date);
      }
    }
  }

  private void addAndRemoveDatesFromCalendarDate(
    ServiceCalendarDate calendarDate,
    Set activeDates
  ) {
    LocalDate serviceDate = calendarDate.getDate();

    switch (calendarDate.getExceptionType()) {
      case ServiceCalendarDate.EXCEPTION_TYPE_ADD -> addServiceDate(activeDates, serviceDate);
      case ServiceCalendarDate.EXCEPTION_TYPE_REMOVE -> activeDates.remove(serviceDate);
      default -> LOG.warn(
        "unknown CalendarDate exception type: {}",
        calendarDate.getExceptionType()
      );
    }
  }

  private void addServiceDate(Set activeDates, LocalDate serviceDate) {
    activeDates.add(serviceDate);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy