package com.conveyal.taui.models;

import com.conveyal.r5.analyst.scenario.AddTrips;

public abstract class AbstractTimetable {
    public String _id;

    /** Days of the week on which this service is active, 0 is Monday */
    public boolean monday, tuesday, wednesday, thursday, friday, saturday, sunday;

    /** allow naming entries for organizational purposes */
    public String name;

    /** start time (seconds since GTFS midnight) */
    public int startTime;

    /** end time for frequency-based trips (seconds since GTFS midnight) */
    public int endTime;

    /** headway for frequency-based patterns */
    public int headwaySecs;

    /** Should this frequency entry use exact times? */
    public boolean exactTimes;

    /** Phase at a stop that is in this modification */
    public String phaseAtStop;

    /**
     * Phase from a timetable (frequency entry) on another modification.
     * Syntax is `${modification._id}:${timetable._id}`
     */
    public String phaseFromTimetable;

    /** Phase from a stop that can be found in the phased from modification's stops */
    public String phaseFromStop;

    /** Amount of time to phase from the other lines frequency */
    public int phaseSeconds;

    public AddTrips.PatternTimetable toBaseR5Timetable () {
        AddTrips.PatternTimetable pt = new AddTrips.PatternTimetable();
        pt.entryId = _id;

        // Days
        pt.monday = monday;
        pt.tuesday = tuesday;
        pt.wednesday = wednesday;
        pt.thursday = thursday;
        pt.friday = friday;
        pt.saturday = saturday;
        pt.sunday = sunday;

        if (exactTimes) {
            int totalDepartures = (endTime - startTime) / headwaySecs;
            pt.firstDepartures = new int[totalDepartures];
            for (int i = 0, departure = startTime; departure < endTime; i++) {
                pt.firstDepartures[i] = departure;
                departure += headwaySecs;
            }
        } else {
            if (phaseAtStop != null) {
                pt.phaseAtStop = phaseAtStop;
                pt.phaseFromStop = phaseFromStop;
                pt.phaseSeconds = phaseSeconds;

                if (phaseFromTimetable != null && phaseFromTimetable.length() > 0) {
                    pt.phaseFromTimetable = phaseFromTimetable.split(":")[1];
                }
            }

            pt.startTime = startTime;
            pt.endTime = endTime;
            pt.headwaySecs = headwaySecs;
        }

        return pt;
    }
}

@@ -1621,47 +1621,498 @@
     
-if (exactTimes) %7B%0A            int total
+// Optionally convert the headway into a series of specific departure times regularly spaced over the time%0A        // window. This timetable should then be treated as scheduled, and should not be assigned randomized schedules.%0A        if (exactTimes) %7B%0A            // Integer division truncates toward zero, add one to make both the start and end times inclusive.%0A            // i.e. a zero-width time window with the same start and end time will still have one departure.%0A            int n
 Depa
@@ -2112,24 +2112,28 @@
 t nDeparture
+Time
 s = (endTime
@@ -2151,32 +2151,36 @@
 e) / headwaySecs
+ + 1
 ;%0A            pt
@@ -2210,13 +2210,9 @@
 int%5B
-total
+n
 Depa
@@ -2216,16 +2216,20 @@
 eparture
+Time
 s%5D;%0A    
@@ -2261,16 +2261,20 @@
 eparture
+Time
  = start
@@ -2279,25 +2279,30 @@
 rtTime; 
-d
+i %3C nD
 eparture
  %3C endTi
@@ -2297,18 +2297,13 @@
 ture
- %3C end
 Time
+s
 ; i+
@@ -2356,16 +2356,20 @@
 eparture
+Time
 ;%0A      
@@ -2387,16 +2387,20 @@
 eparture
+Time
  += head

terminate loop based on index, fixes #168