/* Returns the expected arrival times given vehicleId and naptanId pairs */
func SelectNextBusesByVehicleStopPairs(vehiclesStopsMap map[string]string) []NextBus {
	var nextBuses []NextBus

	innerQueries := make([]string, 0)

	for vehicleId, naptanId := range vehiclesStopsMap {
		innerQueries = append(innerQueries,
			fmt.Sprintf("SELECT line, bound, naptan_id, vehicle_id, expected_arrival_time, already_departed "+
				"FROM next_buses "+
				"WHERE vehicle_id='%v' AND naptan_id='%v'",
				vehicleId, naptanId))
	}

	dbconn.AcquireLock()
	err := db.Select(&nextBuses, strings.Join(innerQueries, " UNION ALL "))
	dbconn.ReleaseLock()

	if err != nil {
		logger.GetLogger().Panic(err)
	}

	/* Set time zone to UTC */
	for i, v := range nextBuses {
		nextBuses[i].ExpectedArrivalTime = v.ExpectedArrivalTime.In(timezone.Get())
	}
	return nextBuses
}
/* Returns the next buses that are approaching a stop given a line and bound after a certain time */
func SelectNextBuses(lineBoundCombination map[string]string, naptanId string, arrivingAfter time.Time) []NextBus {
	var nextBuses []NextBus

	innerQueries := make([]string, 0)

	for line, bound := range lineBoundCombination {
		innerQueries = append(innerQueries,
			fmt.Sprintf("SELECT line, bound, naptan_id, vehicle_id, expected_arrival_time, already_departed "+
				"FROM next_buses "+
				"WHERE naptan_id='%v' AND line='%v' AND bound='%v' AND expected_arrival_time>=TIMESTAMP '%v'",
				naptanId, line, bound, toPsqlTimeStamp(arrivingAfter)))
	}

	sql := fmt.Sprintf("SELECT line, bound, naptan_id, vehicle_id, expected_arrival_time, already_departed "+
		"FROM (%v) AS all_next_buses ORDER BY expected_arrival_time",
		strings.Join(innerQueries, " UNION ALL "))

	logger.GetLogger().Info(sql)
	dbconn.AcquireLock()
	err := db.Select(&nextBuses, sql)
	dbconn.ReleaseLock()

	if err != nil {
		logger.GetLogger().Panic(err)
	}

	/* Set time zone to UTC */
	for i, v := range nextBuses {
		nextBuses[i].ExpectedArrivalTime = v.ExpectedArrivalTime.In(timezone.Get())
	}
	return nextBuses
}
func parseTime(timeStamp string) time.Time {
	t, err := time.Parse(timeFormatString, timeStamp)
	if err != nil {
		logger.GetLogger().Panic(err)
	}
	return t.In(timezone.Get())
}
func parseISOTime(isoFormattedTimeStamp string) time.Time {
	t, err := time.Parse(time.RFC3339Nano, isoFormattedTimeStamp)
	if err != nil {
		logger.GetLogger().Panic(err)
	}
	return t.In(timezone.Get())
}
func TestFetchActualJourneyTimes(t *testing.T) {
	hammersmith := "490007705G"
	kingsCross := "490001171G"
	startTime := time.Date(2016, time.March, 15, 0, 0, 0, 0, time.UTC)
	endTime := time.Now().In(timezone.Get())

	FetchActualJourneyTimes("10", "outbound", hammersmith, kingsCross, startTime, endTime)
}
/* Checks whether a timestamp is in the past */
func timeStampHasPassedBy(timeStamp string, duration time.Duration) bool {
	tflFormatString := "2006-01-02T15:04:05.999Z"

	ts, err := time.Parse(tflFormatString, timeStamp)
	if err != nil {
		logger.GetLogger().Panic(err)
	}

	return ts.Before(time.Now().In(timezone.Get()).Add(-1 * duration))
}
func main() {
	/* List of neighbouring stops to plot their variation of journey times */
	exhibitionRoad := "490006691W"
	royalAlbertHall := "490011750W"
	savoyStreet := "490011938U"
	bedfordStreet := "490003112J"
	regentStreet := "490011515Z"
	picadillyCircus := "490000179C"
	waterloo := "490014270P"
	lancasterPlace := "490008932T"
	marbleArch := "490000144R"
	dorchesterHotel := "490006111S1"
	heathrowParkThistleHotel := "490008019E"
	pinglestoneClose := "490007897E"
	rochesterWay := "490014366S"
	elthamCemetery := "490006536S"
	eastCroydon := "490001089E6"
	lunarHouse := "490017825WN"
	nutfieldClose := "490010463S"
	whiteHartLaneRailwayStation := "490001335D"

	templatePath := "../analysis/template/journeytime.html"

	journeys := map[string]string{
		exhibitionRoad:           royalAlbertHall,
		savoyStreet:              bedfordStreet,
		regentStreet:             picadillyCircus,
		waterloo:                 lancasterPlace,
		marbleArch:               dorchesterHotel,
		heathrowParkThistleHotel: pinglestoneClose,
		rochesterWay:             elthamCemetery,
		eastCroydon:              lunarHouse,
		nutfieldClose:            whiteHartLaneRailwayStation,
	}

	start := time.Date(2016, time.February, 13, 0, 0, 0, 0, time.UTC)
	end := time.Now().In(timezone.Get())
	gap := 24 * time.Hour

	interval := 1 * time.Hour
	dates := make([]time.Time, 0)
	for d := start; d.Before(end); d = d.Add(gap) {
		dates = append(dates, d)
	}
	wr, err := os.Create("../../../../../charts/londonJourneyTimePlot.html")

	if err != nil {
		logger.GetLogger().Panic(err)
	}

	analysis.JourneyTimePlot(journeys, dates, interval, wr, templatePath)
}
/* Returns map (vehicleId => (
	   "direction" => bound, "naptanId" => naptanId,
	   "timeStamp" => timeStamp, "expectedArrival" => expectedArrival))
for each bus tracked */
func parseStreamArrivalsFromResponse(response *http.Response) <-chan map[string]map[string]string {
	out := make(chan map[string]map[string]string)

	go func() {
		var predictionArray []json.Number
		dec := json.NewDecoder(response.Body)

		for dec.More() {
			err := dec.Decode(&predictionArray)
			if err != nil {
				logger.GetLogger().Panic(err)
			}

			if len(predictionArray) == 0 {
				logger.GetLogger().Panic("Unexpected empty prediction array")
			}

			responseType, _ := predictionArray[0].Int64()
			switch responseType {
			/* Response type 1 corresponds to prediction array.
			   Parse prediction array */
			case 1:
				if len(predictionArray) != 6 {
					logger.GetLogger().Info("Expected prediction array to have length 5, but got %v. Prediction array: %v",
						len(predictionArray), predictionArray)
				}

				naptanId := predictionArray[1].String()
				visitNumber := predictionArray[2].String()
				directionId, _ := predictionArray[3].Int64()
				vehicleId := predictionArray[4].String()
				expectedArrivalUnixEpoch, _ := predictionArray[5].Int64()

				result := make(map[string]map[string]string)
				bundle := make(map[string]string)
				bundle["naptanId"] = naptanId
				bundle["visitNumber"] = visitNumber
				bundle["direction"] = directionIdToBound(directionId, predictionArray)
				bundle["timeStamp"] = toTflTimeStamp(time.Now().In(timezone.Get()))
				bundle["expectedArrival"] = toTflTimeStamp(time.Unix(0, expectedArrivalUnixEpoch))
				result[vehicleId] = bundle

				out <- result
			default:
				logger.GetLogger().Error("Encountered non-prediction array: %v", predictionArray)
				continue
			}
		}
	}()
	return out
}
func TestDeleteOldLogs(t *testing.T) {
	days := 1

	DeleteOldLogs(days)

	names := listFiles(logDir)
	for _, name := range names {
		logFileTime := parseLogFileForTime(name)
		if logFileTime.Before(time.Now().In(timezone.Get()).Add(
			time.Duration(days*-24) * time.Hour)) {
			t.Fatalf("Failed to delete log file %v which is older than %v days", name, days)
		}
	}
}
func main() {
	/* List of neighbouring stops to plot their variation of journey times */
	oxfordCircusStation := "490010689OJ"
	tottenhamCourtRoadStation := "490000235V"
	edithGrove := "490005076W"
	worldsEndHealthCentre := "490009370W"
	museumStreet := "490010131W"
	cambridgeCircus := "490004695S"
	cephasStreet := "490004945S"
	darlingRow := "490005965S"
	monumentStation := "490000148K"
	greatTowerStreet := "490007418E"
	grosvenorGardens := "490014050R"
	victoria := "490014051V"
	beechfieldRoad := "490003812E"
	catfordBridgeStation := "490001053M"
	gerraldPlace := "490016425WA"
	denmarkStreet := "490004695A"
	blackbirdCross := "490004051W"
	kingsDrive := "490004331S"
	parkHouse := "490010777W"
	hamptonCourtGardens := "490007727B"

	templatePath := "../analysis/template/journeytime_v2.html"

	journeys := map[string]string{
		oxfordCircusStation: tottenhamCourtRoadStation,
		edithGrove:          worldsEndHealthCentre,
		museumStreet:        cambridgeCircus,
		cephasStreet:        darlingRow,
		monumentStation:     greatTowerStreet,
		grosvenorGardens:    victoria,
		beechfieldRoad:      catfordBridgeStation,
		gerraldPlace:        denmarkStreet,
		blackbirdCross:      kingsDrive,
		parkHouse:           hamptonCourtGardens,
	}

	start := time.Date(2016, time.May, 1, 0, 0, 0, 0, time.UTC)
	end := time.Now().In(timezone.Get())

	wr, err := os.Create("../../../../../charts/londonJourneyTimePlot_v2.html")

	if err != nil {
		logger.GetLogger().Panic(err)
	}

	analysis.JourneyTimePlot2(journeys, start, end, wr, templatePath)
}
func nextBusHandler(w http.ResponseWriter, r *http.Request) {
	/* Extract fields in GET request */
	stopsStrCommaDelimited := r.URL.Query().Get("stops")
	numRouteOptionsPerStopCommaDelimited := r.URL.Query().Get("numRouteOptionsPerStop")
	lineBoundCombinationsCommaDelimited := r.URL.Query().Get("lineBoundCombinations")

	/* Map of target buses => target stop
	map (vehicleId => naptanId) */
	counter := 0
	numRouteOptionsPerStopArr := strings.Split(numRouteOptionsPerStopCommaDelimited, ",")
	lineBoundCombinationsArr := strings.Split(lineBoundCombinationsCommaDelimited, ",")
	stops := strings.Split(stopsStrCommaDelimited, ",")
	stopNextBusesMap := make(map[string][]TflNextBus)
	for i, stop := range stops {
		lineBoundCombinations := make(map[string]string)
		numRouteOptions, err := strconv.Atoi(numRouteOptionsPerStopArr[i])
		if err != nil {
			writeError(w, err)
		}

		for i := 0; i < numRouteOptions; i++ {
			/* Extract line bound combination for stop */
			line := lineBoundCombinationsArr[counter]
			counter++
			bound := lineBoundCombinationsArr[counter]
			counter++
			lineBoundCombinations[line] = bound

		}
		/* Find next buses */
		nextBuses := selectdb.SelectNextBuses(lineBoundCombinations, stop, time.Now().In(timezone.Get()))
		tflNextBuses := make([]TflNextBus, len(nextBuses))
		for i, nextBus := range nextBuses {
			tflNextBuses[i] = TflNextBus{
				Line:                nextBus.Line,
				Bound:               nextBus.Bound,
				VehicleId:           nextBus.VehicleId,
				ExpectedArrivalTime: formatISOTime(nextBus.ExpectedArrivalTime),
				AlreadyDeparted:     nextBus.AlreadyDeparted,
			}
		}
		addToNextBusesCurrentLocations(&tflNextBuses)
		stopNextBusesMap[stop] = tflNextBuses
	}

	/* Write HTML output */
	writeNextBusesDetails(w, stopNextBusesMap)
}
func removeIfOld(dir, name string, days int) {

	logFileTime, err := parseLogFileForTime(name)

	if err != nil {
		logger.GetLogger().Error(err.Error())
		return
	}

	if logFileTime.Before(time.Now().In(timezone.Get()).Add(
		time.Duration(days*-24) * time.Hour)) {
		err := os.Remove(filepath.Join(dir, name))
		if err != nil {
			logger.GetLogger().Panic(err)
		}
		logger.GetLogger().Info("Removed log file %v", name)
	}
}
/* Returns all expected terminus departures after now */
func SelectAllTerminusDepartures() []TerminusDeparture {
	var terminusDepartures []TerminusDeparture

	dbconn.AcquireLock()
	err := db.Select(&terminusDepartures,
		"SELECT line, bound, naptan_id, vehicle_id, expected_departure_time "+
			"FROM terminus_departures "+
			"WHERE expected_departure_time >= now() AT TIME ZONE 'utc'")
	dbconn.ReleaseLock()

	if err != nil {
		logger.GetLogger().Panic(err)
	}

	/* Adjust time zone to UTC */
	for i, v := range terminusDepartures {
		terminusDepartures[i].ExpectedDepartureTime = v.ExpectedDepartureTime.In(timezone.Get())
	}

	return terminusDepartures
}
func TestAutoCorrelationPlot(t *testing.T) {
	exhibitionRoad := "490006691W"
	royalAlbertHall := "490011750W"

	templatePath := "template/autocorrelation.html"

	journeys := map[string]string{
		exhibitionRoad: royalAlbertHall,
	}

	startTime := time.Date(2016, time.February, 13, 11, 0, 0, 0, time.UTC)
	endTime := time.Now().In(timezone.Get()).Add(-1 * time.Hour)
	interval := 1 * time.Hour
	wr, err := os.Create("plots/sample_autocorrelation.html")

	if err != nil {
		t.Fatal(err)
	}

	AutoCorrelationPlot(journeys, startTime, endTime, interval, wr, templatePath)
}
/* Returns map[string]map[string]map[string]int
   ( map : fromStop =>
   		(map : toStop =>
   			(map : "estimate" => estimate in seconds
   			       "stddev" => standard deviation in seconds
   			       "delayBusCount" => bus count as evidence of delay
   			       "delayExpectedToLast" => how long delay is expected to last in seconds
   			 )
   		)
   	)
   	the estimated journey times, standard deviation, between map of neighbouring stops
   	for mixed, historic and real time.
*/
func getEstimates(adjacentStops map[string]map[string]bool) (map[string]map[string]map[string]int, map[string]map[string]map[string]int, map[string]map[string]map[string]int) {
	departureTime := time.Now().In(timezone.Get())

	timeRanges := map[time.Time]time.Time{
		departureTime.AddDate(0, 0, -7).Add(-30 * time.Minute):  departureTime.AddDate(0, 0, -7).Add(30 * time.Minute),
		departureTime.AddDate(0, 0, -14).Add(-30 * time.Minute): departureTime.AddDate(0, 0, -14).Add(30 * time.Minute),
		departureTime.AddDate(0, 0, -21).Add(-30 * time.Minute): departureTime.AddDate(0, 0, -21).Add(30 * time.Minute),
	}

	realTimeEstimates := make(map[string]map[string]map[string]int)
	mixedEstimates := make(map[string]map[string]map[string]int)

	/* Select historic and real time estimates from database */
	historicEstimates := selectdb.SelectHistoricEstimates(timeRanges)
	realTimeData := selectdb.SelectRealTimeEstimates(realTimeWindow)

	/* Combine historic and real time data */
	for fromStop, fromStopDetails := range historicEstimates {
		for toStop, historicDetails := range fromStopDetails {
			historicEstimate := time.Duration(historicDetails["estimate"]) * time.Second

			/* Extract real time data and lookup delay characteristics, skip for cases lacking real time estimate */
			delayBusCount := 0
			realTimeFromStopDetails, exists := realTimeData[fromStop]
			if !exists {
				continue
			}
			realTimeDetails, exists := realTimeFromStopDetails[toStop]
			if !exists {
				continue
			}
			realTimeCount, _ := realTimeDetails["count"]
			if realTimeCount < 3 {
				continue
			}
			realTimeRecords := make([]time.Duration, realTimeCount)
			for i := 1; i <= realTimeCount; i++ {
				// Since real time records are already reversed, reverse it again for ascending order in time,
				// so that handleDelayReverseLookup will work fine
				realTimeRecord := time.Duration(realTimeDetails[strconv.Itoa(realTimeCount+1-i)]) * time.Second
				realTimeRecords[i-1] = realTimeRecord
			}

			/* Calculate real time estimate using last three buses averaged */
			realTimeLastThreeInSeconds := make([]float64, 3)
			for j := 0; j < 3; j++ {
				realTimeLastThreeInSeconds[j] = realTimeRecords[len(realTimeRecords)-1-j].Seconds()
			}
			realTimeEstimateInSeconds, _ := statistics.Mean(realTimeLastThreeInSeconds)
			_, exists = realTimeEstimates[fromStop]
			if !exists {
				realTimeEstimates[fromStop] = make(map[string]map[string]int)
				mixedEstimates[fromStop] = make(map[string]map[string]int)
			}
			realTimeEstimates[fromStop][toStop] = map[string]int{
				"estimate": int(realTimeEstimateInSeconds),
			}

			/* Get mixed estimates below */

			shouldUseHistoric, delayBusCount, delayExpectedToLast := performanceeval.HandleDelayReverseLookup(
				fromStop, toStop, departureTime, delayLastingThreshold, historicEstimate, realTimeRecords)

			if shouldUseHistoric {
				mixedEstimates[fromStop][toStop] = historicEstimates[fromStop][toStop]
				mixedEstimates[fromStop][toStop]["delayBusCount"] = delayBusCount
			} else {
				mixedEstimates[fromStop][toStop] = map[string]int{
					"estimate":            int(realTimeEstimateInSeconds),
					"delayBusCount":       delayBusCount,
					"delayExpectedToLast": int(delayExpectedToLast.Seconds()),
					"delay":               1,
				}
			}
		}
	}
	return mixedEstimates, historicEstimates, realTimeEstimates
}
/* Returns timestamp in psql format of current time */
func getCurrentPsqlTimeStamp() string {
	psqlFormatString := "2006-01-02 15:04:05"
	return time.Now().In(timezone.Get()).Format(psqlFormatString)
}
/* Delay characteristics represented by map
   fromId => (toId => (day of week => (time of day => (delayThreshold => (numBuses => expected lasting time))))) */
func computeDelayCharacteristics(adjacentStops map[string]map[string]bool) map[string]map[string]map[int]map[int]map[time.Duration]map[int]time.Duration {
	delayCharacteristics := make(map[string]map[string]map[int]map[int]map[time.Duration]map[int]time.Duration)

	/* Channel for delay characteristics */
	ch := make(chan map[string]map[string]map[int]map[int]map[time.Duration]map[int]time.Duration)

	lineBounds := selectdb.SelectLineBoundsServingMultipleAdjacentStops(adjacentStops)

	for fromStop, details := range adjacentStops {
		fromStopDelayCharacteristics := make(map[string]map[int]map[int]map[time.Duration]map[int]time.Duration)
		for toStop, _ := range details {
			go func(fromStop, toStop string) {

				/* Form time ranges - Compute for the weekday/weekend of yesterday */
				timeRanges := make(map[time.Time]time.Time)
				endOfYesterday := time.Now().In(timezone.Get()).Truncate(24 * time.Hour)
				startOfYesterday := endOfYesterday.AddDate(0, 0, -1)
				weekday := startOfYesterday.Weekday()
				for _, day := range daysToLookBack {
					timeRanges[startOfYesterday.AddDate(0, 0, -day)] = endOfYesterday.AddDate(0, 0, -day)
				}

				/* Select journey history */
				journeyHistory := selectdb.SelectJourneyHistory(fromStop, toStop, timeRanges, nil)
				times := make([]time.Time, len(journeyHistory))
				actualDurations := make([]time.Duration, len(journeyHistory))

				for i, record := range journeyHistory {
					times[i] = record.ToTimestamp
					actualDurations[i] = time.Duration(record.TimeTaken) * time.Second
				}

				/* Select historic journey times */
				var line, bound string
				for k, v := range lineBounds[fromStop][toStop] {
					line = k
					bound = v
				}
				/* Generate times at intervals for prediction efficiency */
				timesAtIntervals := make([]time.Time, 0)
				for startTime, endTime := range timeRanges {
					for t := startTime.Round(predictionInterval); t.Before(endTime.Add(predictionInterval)); t = t.Add(predictionInterval) {
						timesAtIntervals = append(timesAtIntervals, t)
					}
				}
				historicTimes := PredictJourneyTimes(line, bound, fromStop, toStop, timesAtIntervals, DefaultHistoric(), nil)
				historicDurations := make([]time.Duration, len(journeyHistory))
				for i, t := range times {
					historicDurations[i] = historicTimes[t.Round(predictionInterval)]
				}

				delayCharacteristics := map[string]map[string]map[int]map[int]map[time.Duration]map[int]time.Duration{
					fromStop: map[string]map[int]map[int]map[time.Duration]map[int]time.Duration{
						toStop: computeDelayCharacteristicsForStopPair(fromStop, toStop, weekday, times, actualDurations, historicDurations),
					},
				}
				updateDelayCharacteristics(delayCharacteristics)
				ch <- delayCharacteristics
			}(fromStop, toStop)

			fromStopDelayCharacteristics[toStop] = nil
			// fromStopDelayCharacteristics[toStop] = computeDelayCharacteristicsForStopPair(fromStop, toStop, times, actualDurations, historicDurations)

		}
		// delayCharacteristics[fromStop] = fromStopDelayCharacteristics
		delayCharacteristics[fromStop] = fromStopDelayCharacteristics
	}

	for _, v := range adjacentStops {
		for range v {
			<-ch
			/*entry := <-ch
			delayCharacteristics[entry.fromStop][entry.toStop] = entry.entry
			updateDelayCharacteristics(delayCharacteristics)*/
		}
	}
	return delayCharacteristics
}
/* Given a timestamp, decides whether its estimate is trustworthy based on how recent
   the timestamp is */
func isRecentEstimate(t time.Time) bool {
	threshold := 5 * time.Minute
	return !t.Before(time.Now().In(timezone.Get()).Add(-1 * threshold))
}
/* Change the predictions inside directions to use our own predictions */
func (directions *TflDirections) UpdatePredictions(isDeparting bool, departureOrArrivalTime time.Time) error {
	journeys := &directions.Journeys
	for i := 0; i < len(*journeys); i++ {
		/* Counter for keeping track of times for prediction */
		cumulativeTime := departureOrArrivalTime
		if !isDeparting {
			/* Approximate departure time for arriving case by subtracting tfl estimate */
			cumulativeTime = departureOrArrivalTime.Add(-time.Duration((*journeys)[i].TflDuration) * time.Minute)
		}
		initialTime := cumulativeTime

		legs := &(*journeys)[i].Legs
		for j := 0; j < len(*legs); j++ {
			leg := &(*legs)[j]
			leg.DepartureTime = formatISOTime(cumulativeTime)
			if leg.Mode.Id == "bus" {
				var line string
				var bound string
				var stopPoints []string

				lineBoundCombination := make(map[string]string)

				/* Update naptan ids and coordinates of intermediate stops */
				for i, routeOption := range leg.RouteOptions {
					var err error
					line = routeOption.LineIdentifier.Id
					stopPoints, bound, err = searchIntermediateStops(line, leg.DeparturePoint.IcsCode, leg.ArrivalPoint.IcsCode)

					if err != nil {
						/* Bus may not be Tfl operated (e.g. bus 555 to Heathrow). In such case skip. */
						continue
					}

					/* Add bound to struct */
					leg.RouteOptions[i].LineIdentifier.Bound = bound
					lineBoundCombination[line] = bound
				}

				/* If no stop points found, invalidate journey for removal afterwards*/
				if len(stopPoints) == 0 {
					(*journeys)[i].IsInvalid = true
					continue
				}

				leg.IntermediateStops = make([]TflStopPoint, len(stopPoints))

				details := selectdb.SelectMultipleStops(stopPoints)
				for i, naptanId := range stopPoints {
					latitude, _ := strconv.ParseFloat(details[naptanId]["latitude"], 64)
					longitude, _ := strconv.ParseFloat(details[naptanId]["longitude"], 64)
					leg.IntermediateStops[i] = TflStopPoint{
						Name:      details[naptanId]["name"],
						NaptanId:  naptanId,
						Latitude:  latitude,
						Longitude: longitude,
					}
				}

				/* Update bus prediction */
				newPrediction, historicBasedPrediction, realTimeBasedPrediction, newPredictionAdjacentStops, err := updateBusPrediction(line, bound, stopPoints, cumulativeTime)
				if err == nil {
					leg.DurationInMinutes = int(newPrediction.Minutes())
					leg.HistoricDurationInMinutes = int(historicBasedPrediction.Minutes())
					leg.RealTimeDurationInMinutes = int(realTimeBasedPrediction.Minutes())
				}

				/* Update next bus arrivals */
				fromStop := leg.IntermediateStops[0].NaptanId
				nextBuses := selectdb.SelectNextBuses(lineBoundCombination, fromStop, time.Now().In(timezone.Get()))
				leg.NextBuses = make([]TflNextBus, len(nextBuses))
				for i, nextBus := range nextBuses {
					leg.NextBuses[i] = TflNextBus{
						Line:                nextBus.Line,
						Bound:               nextBus.Bound,
						VehicleId:           nextBus.VehicleId,
						ExpectedArrivalTime: formatISOTime(nextBus.ExpectedArrivalTime),
						AlreadyDeparted:     nextBus.AlreadyDeparted,
					}
				}
				addToNextBusesCurrentLocations(&leg.NextBuses)

				/* Find out next bus frequency */
				averageWaitTime, minWaitTime, maxWaitTime, err := selectdb.SelectAverageWaitTimes(lineBoundCombination, initialTime)
				if err != nil {
					logger.GetLogger().Error(err.Error())
				}
				leg.FrequencyLow = int(minWaitTime.Minutes())
				leg.FrequencyHigh = int(maxWaitTime.Minutes())

				nextBusFlag := false
				if len(nextBuses) > 0 {
					/* Find first bus that is going to arrive and the user is able to catch */
					for _, nextBus := range nextBuses {
						nextBusTime := nextBus.ExpectedArrivalTime
						if nextBusTime.After(cumulativeTime) {
							leg.TimeToNextBus = int(nextBusTime.Sub(cumulativeTime).Minutes())
							cumulativeTime = nextBusTime
							nextBusFlag = true
							break
						}
					}
				}
				if len(nextBuses) == 0 || (len(nextBuses) > 0 && !nextBusFlag) {
					/* Handle special case if lack of next buses, use average wait times instead */
					leg.TimeToNextBus = int(averageWaitTime.Minutes())
					cumulativeTime = cumulativeTime.Add(averageWaitTime)
				}

				/* Update cumulative time */
				leg.IntermediateStops[0].ExpectedArrival = int(cumulativeTime.Sub(initialTime).Minutes())
				for i := 0; i < len(stopPoints)-1; i++ {
					fromStop := stopPoints[i]
					toStop := stopPoints[i+1]
					cumulativeTime = cumulativeTime.Add(newPredictionAdjacentStops[fromStop][toStop])
					leg.IntermediateStops[i+1].ExpectedArrival = int(cumulativeTime.Sub(initialTime).Minutes())
				}
			} else {
				cumulativeTime = cumulativeTime.Add(time.Duration(leg.DurationInMinutes) * time.Minute)
			}
		}
	}

	/* Remove invalid journeys */
	for i := len(*journeys) - 1; i >= 0; i-- {
		if (*journeys)[i].IsInvalid {
			*journeys = append((*journeys)[:i], (*journeys)[i+1:]...)
		}
	}
	return nil
}
/* Checks whether timestamp has passed */
func timeStampHasPassed(tflFormat string) bool {
	return parseTflTimeStamp(tflFormat).Before(time.Now().In(timezone.Get()))
}