Package org.onebusaway.transit_data_federation.impl.blocks

Source Code of org.onebusaway.transit_data_federation.impl.blocks.BlockCalendarServiceImpl

/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
* Copyright (C) 2011 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.transit_data_federation.impl.blocks;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.onebusaway.collections.Min;
import org.onebusaway.container.cache.Cacheable;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.calendar.ServiceInterval;
import org.onebusaway.transit_data_federation.services.ExtendedCalendarService;
import org.onebusaway.transit_data_federation.services.blocks.BlockCalendarService;
import org.onebusaway.transit_data_federation.services.blocks.BlockIndexService;
import org.onebusaway.transit_data_federation.services.blocks.BlockInstance;
import org.onebusaway.transit_data_federation.services.blocks.BlockLayoverIndex;
import org.onebusaway.transit_data_federation.services.blocks.BlockTripIndex;
import org.onebusaway.transit_data_federation.services.blocks.FrequencyBlockTripIndex;
import org.onebusaway.transit_data_federation.services.blocks.FrequencyServiceIntervalBlock;
import org.onebusaway.transit_data_federation.services.blocks.InstanceState;
import org.onebusaway.transit_data_federation.services.blocks.LayoverIntervalBlock;
import org.onebusaway.transit_data_federation.services.blocks.ServiceIntervalBlock;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockTripEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.FrequencyEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.TransitGraphDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
class BlockCalendarServiceImpl implements BlockCalendarService {

  private ExtendedCalendarService _calendarService;

  private BlockIndexService _blockIndexService;

  private TransitGraphDao _transitGraphDao;

  @Autowired
  public void setCalendarService(ExtendedCalendarService calendarService) {
    _calendarService = calendarService;
  }

  @Autowired
  public void setBlockIndexService(BlockIndexService blockIndexService) {
    _blockIndexService = blockIndexService;
  }

  @Autowired
  public void setTransitGraphDao(TransitGraphDao transitGraphDao) {
    _transitGraphDao = transitGraphDao;
  }

  /****
   * {@link BlockCalendarService} Interface
   ****/

  @Cacheable(isValueSerializable = false)
  @Override
  public BlockInstance getBlockInstance(AgencyAndId blockId, long serviceDate) {

    BlockEntry block = _transitGraphDao.getBlockEntryForId(blockId);

    if (block == null)
      throw new IllegalArgumentException("unknown block: " + blockId);

    List<BlockConfigurationEntry> configurations = block.getConfigurations();
    int index = 0;

    Date date = new Date(serviceDate);
    InstanceState state = new InstanceState(serviceDate);

    /**
     * See the specific contract for {@link BlockEntry#getConfigurations()}
     * about the sort order of configurations
     */
    for (BlockConfigurationEntry configuration : configurations) {
      if (allServiceIdsAreActiveForServiceDate(configuration, date)) {
        return new BlockInstance(configuration, state);
      }

      index++;
    }

    return null;
  }

  @Override
  public List<BlockInstance> getActiveBlocks(AgencyAndId blockId,
      long timeFrom, long timeTo) {

    List<BlockTripIndex> indices = _blockIndexService.getBlockTripIndicesForBlock(blockId);
    List<BlockLayoverIndex> layoverIndices = _blockIndexService.getBlockLayoverIndicesForBlock(blockId);
    List<FrequencyBlockTripIndex> frequencyIndices = _blockIndexService.getFrequencyBlockTripIndicesForBlock(blockId);

    return getActiveBlocksInTimeRange(indices, layoverIndices,
        frequencyIndices, timeFrom, timeTo);
  }

  @Override
  public List<BlockInstance> getClosestActiveBlocks(AgencyAndId blockId,
      long time) {

    Date timeAsDate = new Date(time);

    Min<BlockInstance> m = new Min<BlockInstance>();

    BlockEntry blockEntry = _transitGraphDao.getBlockEntryForId(blockId);
    for (BlockConfigurationEntry blockConfig : blockEntry.getConfigurations()) {
      List<Date> serviceDates = _calendarService.getDatesForServiceIdsAsOrderedList(blockConfig.getServiceIds());

      int index = index(Collections.binarySearch(serviceDates, timeAsDate));

      if (index > 0) {
        BlockInstance instance = new BlockInstance(blockConfig,
            serviceDates.get(index - 1).getTime());
        long delta = getTimeToBlockInstance(instance, time);
        m.add(delta, instance);
      }

      if (index < serviceDates.size()) {
        BlockInstance instance = new BlockInstance(blockConfig,
            serviceDates.get(index).getTime());
        long delta = getTimeToBlockInstance(instance, time);
        m.add(delta, instance);
      }
    }

    return m.getMinElements();
  }

  @Override
  public List<BlockInstance> getActiveBlocksInTimeRange(long timeFrom,
      long timeTo) {
    List<BlockTripIndex> indices = _blockIndexService.getBlockTripIndices();
    List<BlockLayoverIndex> layoverIndices = _blockIndexService.getBlockLayoverIndices();
    List<FrequencyBlockTripIndex> frequencyIndices = _blockIndexService.getFrequencyBlockTripIndices();
    return getActiveBlocksInTimeRange(indices, layoverIndices,
        frequencyIndices, timeFrom, timeTo);
  }

  @Override
  public List<BlockInstance> getActiveBlocksForAgencyInTimeRange(
      String agencyId, long timeFrom, long timeTo) {
    List<BlockTripIndex> indices = _blockIndexService.getBlockTripIndicesForAgencyId(agencyId);
    List<BlockLayoverIndex> layoverIndices = _blockIndexService.getBlockLayoverIndicesForAgencyId(agencyId);
    List<FrequencyBlockTripIndex> frequencyIndices = _blockIndexService.getFrequencyBlockTripIndicesForAgencyId(agencyId);
    return getActiveBlocksInTimeRange(indices, layoverIndices,
        frequencyIndices, timeFrom, timeTo);
  }

  @Override
  public List<BlockInstance> getActiveBlocksForRouteInTimeRange(
      AgencyAndId routeId, long timeFrom, long timeTo) {
    List<BlockTripIndex> indices = _blockIndexService.getBlockTripIndicesForRouteCollectionId(routeId);
    List<BlockLayoverIndex> layoverIndices = _blockIndexService.getBlockLayoverIndicesForRouteCollectionId(routeId);
    List<FrequencyBlockTripIndex> frequencyIndices = _blockIndexService.getFrequencyBlockTripIndicesForRouteCollectionId(routeId);
    return getActiveBlocksInTimeRange(indices, layoverIndices,
        frequencyIndices, timeFrom, timeTo);
  }

  @Override
  public List<BlockInstance> getActiveBlocksInTimeRange(
      Iterable<BlockTripIndex> indices,
      Iterable<BlockLayoverIndex> layoverIndices,
      Iterable<FrequencyBlockTripIndex> frequencyIndices, long timeFrom,
      long timeTo) {

    Set<BlockInstance> instances = new HashSet<BlockInstance>();

    for (BlockTripIndex index : indices)
      getActiveBlocksInTimeRange(index, timeFrom, timeTo, instances);

    for (BlockLayoverIndex index : layoverIndices)
      getActiveLayoversInTimeRange(index, timeFrom, timeTo, instances);

    for (FrequencyBlockTripIndex index : frequencyIndices)
      getActiveFrequencyBlocksInTimeRange(index, timeFrom, timeTo, instances);

    return new ArrayList<BlockInstance>(instances);
  }

  /****
   * Private Methods
   ****/

  private boolean allServiceIdsAreActiveForServiceDate(
      BlockConfigurationEntry configuration, Date serviceDate) {

    Set<Date> serviceDates = _calendarService.getDatesForServiceIds(configuration.getServiceIds());
    return serviceDates.contains(serviceDate);
  }

  /****
   *
   ****/

  private void getActiveBlocksInTimeRange(BlockTripIndex index, long timeFrom,
      long timeTo, Collection<BlockInstance> results) {

    Date dateFrom = new Date(timeFrom);
    Date dateTo = new Date(timeTo);

    handleBlockIndex(index, dateFrom, dateTo, results);
  }

  private Collection<BlockInstance> handleBlockIndex(BlockTripIndex index,
      Date timeFrom, Date timeTo, Collection<BlockInstance> instances) {

    List<BlockTripEntry> trips = index.getTrips();

    ServiceIntervalBlock serviceIntervalBlock = index.getServiceIntervalBlock();
    ServiceInterval serviceInterval = serviceIntervalBlock.getRange();

    Collection<Date> serviceDates = _calendarService.getServiceDatesWithinRange(
        index.getServiceIds(), serviceInterval, timeFrom, timeTo);

    for (Date serviceDate : serviceDates) {

      findBlockTripsInRange(serviceIntervalBlock, serviceDate, timeFrom,
          timeTo, trips, instances);
    }

    return instances;
  }

  private void findBlockTripsInRange(ServiceIntervalBlock intervals,
      Date serviceDate, Date timeFrom, Date timeTo, List<BlockTripEntry> trips,
      Collection<BlockInstance> instances) {

    int scheduledTimeFrom = (int) ((timeFrom.getTime() - serviceDate.getTime()) / 1000);
    int scheduledTimeTo = (int) ((timeTo.getTime() - serviceDate.getTime()) / 1000);

    int indexFrom = index(Arrays.binarySearch(intervals.getMaxDepartures(),
        scheduledTimeFrom));
    int indexTo = index(Arrays.binarySearch(intervals.getMinArrivals(),
        scheduledTimeTo));
   
    InstanceState state = new InstanceState(serviceDate.getTime());

    for (int in = indexFrom; in < indexTo; in++) {
      BlockTripEntry trip = trips.get(in);
      BlockConfigurationEntry block = trip.getBlockConfiguration();
      BlockInstance instance = new BlockInstance(block, state);
      instances.add(instance);
    }
  }

  /****
   *
   ****/

  private void getActiveLayoversInTimeRange(BlockLayoverIndex index,
      long timeFrom, long timeTo, Collection<BlockInstance> results) {

    Date dateFrom = new Date(timeFrom);
    Date dateTo = new Date(timeTo);

    handleLayoverIndex(index, dateFrom, dateTo, results);
  }

  private Collection<BlockInstance> handleLayoverIndex(BlockLayoverIndex index,
      Date timeFrom, Date timeTo, Collection<BlockInstance> instances) {

    List<BlockTripEntry> trips = index.getTrips();

    LayoverIntervalBlock layoverIntervalBlock = index.getLayoverIntervalBlock();
    ServiceInterval serviceInterval = layoverIntervalBlock.getRange();

    Collection<Date> serviceDates = _calendarService.getServiceDatesWithinRange(
        index.getServiceIds(), serviceInterval, timeFrom, timeTo);

    for (Date serviceDate : serviceDates) {

      findBlockLayoversInRange(layoverIntervalBlock, serviceDate, timeFrom,
          timeTo, trips, instances);
    }

    return instances;
  }

  private void findBlockLayoversInRange(LayoverIntervalBlock intervals,
      Date serviceDate, Date timeFrom, Date timeTo, List<BlockTripEntry> trips,
      Collection<BlockInstance> instances) {

    int scheduledTimeFrom = (int) ((timeFrom.getTime() - serviceDate.getTime()) / 1000);
    int scheduledTimeTo = (int) ((timeTo.getTime() - serviceDate.getTime()) / 1000);

    int indexFrom = index(Arrays.binarySearch(intervals.getEndTimes(),
        scheduledTimeFrom));
    int indexTo = index(Arrays.binarySearch(intervals.getStartTimes(),
        scheduledTimeTo));
   
    InstanceState state = new InstanceState(serviceDate.getTime());

    for (int in = indexFrom; in < indexTo; in++) {
      BlockTripEntry trip = trips.get(in);
      BlockConfigurationEntry block = trip.getBlockConfiguration();
      BlockInstance instance = new BlockInstance(block, state);
      instances.add(instance);
    }
  }

  /****
   * Frequency Block Indices
   ****/

  private void getActiveFrequencyBlocksInTimeRange(
      FrequencyBlockTripIndex index, long timeFrom, long timeTo,
      Collection<BlockInstance> results) {

    Date dateFrom = new Date(timeFrom);
    Date dateTo = new Date(timeTo);

    handleFrequencyBlockIndex(index, dateFrom, dateTo, results);
  }

  private Collection<BlockInstance> handleFrequencyBlockIndex(
      FrequencyBlockTripIndex index, Date timeFrom, Date timeTo,
      Collection<BlockInstance> instances) {

    List<BlockTripEntry> trips = index.getTrips();
    List<FrequencyEntry> frequencies = index.getFrequencies();

    FrequencyServiceIntervalBlock serviceIntervalBlock = index.getServiceIntervalBlock();
    ServiceInterval serviceInterval = serviceIntervalBlock.getRange();

    Collection<Date> serviceDates = _calendarService.getServiceDatesWithinRange(
        index.getServiceIds(), serviceInterval, timeFrom, timeTo);

    for (Date serviceDate : serviceDates) {

      findFrequencyBlockTripsInRange(serviceIntervalBlock, serviceDate,
          timeFrom, timeTo, trips, frequencies, instances);
    }

    return instances;
  }

  private void findFrequencyBlockTripsInRange(
      FrequencyServiceIntervalBlock serviceIntervalIndex, Date serviceDate,
      Date timeFrom, Date timeTo, List<BlockTripEntry> trips,
      List<FrequencyEntry> frequencies, Collection<BlockInstance> instances) {

    int scheduledTimeFrom = (int) ((timeFrom.getTime() - serviceDate.getTime()) / 1000);
    int scheduledTimeTo = (int) ((timeTo.getTime() - serviceDate.getTime()) / 1000);

    int indexFrom = index(Arrays.binarySearch(
        serviceIntervalIndex.getEndTimes(), scheduledTimeFrom));
    int indexTo = index(Arrays.binarySearch(
        serviceIntervalIndex.getStartTimes(), scheduledTimeTo));

    for (int in = indexFrom; in < indexTo; in++) {
      BlockTripEntry trip = trips.get(in);
      BlockConfigurationEntry block = trip.getBlockConfiguration();
      FrequencyEntry frequency = frequencies.get(in);
      InstanceState state = new InstanceState(serviceDate.getTime(), frequency);
      BlockInstance instance = new BlockInstance(block, state);
      instances.add(instance);
    }
  }

  /****
   *
   ****/

  private long getTimeToBlockInstance(BlockInstance instance, long time) {
    long serviceDate = instance.getServiceDate();
    BlockConfigurationEntry blockConfig = instance.getBlock();
    int n = blockConfig.getStopTimes().size();
    long from = serviceDate + blockConfig.getArrivalTimeForIndex(0) * 1000;
    long to = serviceDate + blockConfig.getDepartureTimeForIndex(n - 1) * 1000;
    return Math.abs((from + to) / 2 - time);
  }

  /****
   *
   ****/

  private int index(int index) {
    if (index < 0)
      return -(index + 1);
    return index;
  }

}
TOP

Related Classes of org.onebusaway.transit_data_federation.impl.blocks.BlockCalendarServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.