package com.conveyal.r5.transit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;


public class FilteredPattern {

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

    /** Schedule-based (i.e. not frequency-based) trips running in a particular set of GTFS services */
    public List<TripSchedule> runningScheduledTrips = new ArrayList<>();

    /** Frequency-based trips active in a particular set of GTFS services */
    public List<TripSchedule> runningFrequencyTrips = new ArrayList<>();

    /** If no active schedule-based trip of this filtered pattern overtakes another. */
    public boolean noScheduledOvertaking;

    /**
     * Copy a TripPattern, ignoring fields not used in Raptor routing. The source pattern's trip schedules are
     * filtered to exclude trips not active in the supplied set of services, then divided into separate
     * scheduled and frequency trip lists. Finally, check the runningScheduledTrips for overtaking.
     */
    public FilteredPattern (TripPattern source, BitSet servicesActive) {
        for (TripSchedule schedule : source.tripSchedules) {
            if (servicesActive.get(schedule.serviceCode)) {
                if (schedule.headwaySeconds == null) {
                    runningScheduledTrips.add(schedule);
                } else {
                    runningFrequencyTrips.add(schedule);
                }
            }
        }

        // Check for overtaking
        // TODO invert loops, should be more efficient to do inner loop over contiguous arrays,
        //      also allows factoring out a method to check two TripSchedules for overtaking.
        noScheduledOvertaking = true;
        loopOverStops:
        for (int stopOffset = 0; stopOffset < source.stops.length; stopOffset++) {
            for (int i = 0; i < runningScheduledTrips.size() - 1; i++) {
                if (runningScheduledTrips.get(i).departures[stopOffset] >
                        runningScheduledTrips.get(i + 1).departures[stopOffset]
                ) {
                    LOG.warn(
                            "Overtaking: route {} pattern {} stop #{} time {}",
                            source.routeId,
                            source.originalId,
                            stopOffset,
                            runningScheduledTrips.get(i + 1).departures[stopOffset]
                    );
                    noScheduledOvertaking = false;
                    break loopOverStops;
                }
            }
        }
    }
}

@@ -1519,361 +1519,105 @@
 eck 
-for overtaking%0A        // TODO invert loops, should be more efficient to do inner loop over contiguous arrays,%0A        //      also allows factoring out a method to check two TripSchedules for overtaking.%0A        noScheduledOvertaking = true;%0A        loopOverStops:%0A        for (int stopOffset = 0; stopOffset %3C source.stops.length; stopOffset++) %7B%0A    
+whether any running trip on this pattern overtakes another%0A        noScheduledOvertaking = true;%0A
     
@@ -1677,28 +1677,24 @@
 - 1; i++) %7B%0A
-    
             
@@ -1696,16 +1696,26 @@
      if 
+(overtakes
 (running
@@ -1739,315 +1739,169 @@
 t(i)
-.departures%5BstopOffset%5D %3E%0A                        runningScheduledTrips.get(i + 1).departures%5BstopOffset%5D%0A                ) %7B%0A                    LOG.warn(%0A                            %22Overtaking: route %7B%7D pattern %7B%7D stop #%7B%7D time %7B%7D%22,%0A                            source.routeId,%0A                           
+, runningScheduledTrips.get(i + 1))) %7B%0A                noScheduledOvertaking = false;%0A                LOG.warn(%22Overtaking: route %7B%7D pattern %7B%7D%22, source.routeId,
  sou
@@ -1914,17 +1914,18 @@
 iginalId
-,
+);
 %0A       
@@ -1925,32 +1925,39 @@
                 
+break;%0A
             stop
@@ -1956,31 +1956,18 @@
     
-stopOffset,%0A   
+%7D%0A
         
     
@@ -1966,204 +1966,209 @@
     
-     
+%7D%0A
     
+%7D%0A%0A
     
-    runningScheduledTrips.get(i + 1).departures%5BstopOffset%5D%0A                    );%0A                    noScheduledOvertaking = false;%0A                    break loopOverStops;%0A        
+private static boolean overtakes (TripSchedule a, TripSchedule b) %7B%0A        for (int s = 0; s %3C a.departures.length; s++) %7B%0A            if (a.departures%5Bs%5D %3E b.departures%5Bs%5D) return true;%0A
     
@@ -2181,32 +2181,31 @@
         
-    %7D%0A   
+return false;%0A
     
- 
 %7D%0A
-    %7D
 %0A%7D%0A

transpose loops over trips and stops