func lookupJourneyRecords(line, bound, toStopSeq string, departureTime time.Time, method, mixedType string) []selectdb.JourneyRecord {
	toStopSeqNum, err := strconv.Atoi(toStopSeq)
	if err != nil {
		logger.GetLogger().Panic(err)
	}

	/* To stop seq should be greater than 0, since all valid journeys will have toStopSeq >= 1 */
	if toStopSeqNum == 0 {
		logger.GetLogger().Panic("Unexpected stop sequence 0 in toStopSeq")
	}

	fromStopSeqNum := toStopSeqNum - 1
	fromStop := selectdb.SelectStopWithStopSeq(line, bound, fromStopSeqNum)
	toStop := selectdb.SelectStopWithStopSeq(line, bound, toStopSeqNum)

	timeRanges, options := getTimeRangesAndOptions(method, line, bound, departureTime, mixedType)

	journeyRecords := selectdb.SelectJourneyHistory(fromStop, toStop, timeRanges, options)
	return journeyRecords
}
/* Returns the predictios given by the mixed method, also historic and and real time methods */
func PredictJourneyWithMixedData(mixedMethod Method, line, bound string, intermediateStops map[string]map[string]bool,
	intermediateStopsOrdered []string, departureTime time.Time) (map[string]map[string]map[string]int64, map[string]map[string]map[string]int64, map[string]map[string]map[string]int64, error) {
	historicMethod, realTimeMethod, _ := mixedMethod.Decompose()

	historicDateRange, historicOptions := setDateRangeAndOptions(historicMethod, line, bound, departureTime)
	historicData, _ := predictJourneyWithHistoricData(intermediateStops, intermediateStopsOrdered, departureTime, historicDateRange, historicOptions)

	_, realTimeOptions := setDateRangeAndOptions(realTimeMethod, line, bound, departureTime)
	realTimeData, _ := predictJourneyWithRealTimeData(intermediateStops, departureTime, realTimeOptions, nil)

	/* Get complete journey history entries for real time */
	if mixedMethod.IsDelayReverseLookupBased() {
		realTimeOptions["realtimemethod"] = "last"
		realTimeOptions["realtimecount"] = strconv.Itoa(maxDelayBusCountThreshold())
		realTimeOptions["slidingwindow"] = "120"
		realTimeOptions["norank"] = "true"
	}

	slidingWindow := SlidingWindow
	if realTimeOptions["slidingwindow"] != "" {
		slidingWindowInMinutes, _ := strconv.Atoi(realTimeOptions["slidingwindow"])
		slidingWindow = time.Duration(slidingWindowInMinutes) * time.Minute
	}
	timeRanges := map[time.Time]time.Time{
		departureTime.Add(-slidingWindow): departureTime,
	}

	/* Combine historic and real time data */
	predictionData := make(map[string]map[string]map[string]int64)

	/* Accumulator keeping track of time to each stop - to decide whether to use real time data */
	timeToStop := time.Duration(0)

ChooseHistoricOrRealTime:
	for fromStop, details := range intermediateStops {
		for toStop, _ := range details {
			historicFromStopDetails, historicExists := historicData[fromStop]
			realTimeFromStopDetails, realTimeExists := realTimeData[fromStop]
			realTimeJourneyHistory := selectdb.SelectJourneyHistory(fromStop, toStop, timeRanges, realTimeOptions)

			if historicExists && realTimeExists {
				historicEstimate := time.Duration(historicFromStopDetails[toStop]["estimate"]) * time.Second
				realTimeEstimate := time.Duration(realTimeFromStopDetails[toStop]["estimate"]) * time.Second

				/* Case 1: Delay lookup */
				if mixedMethod.IsDelayReverseLookupBased() {
					realTimeEstimates := journeyHistoryToRealTimeEstimates(realTimeJourneyHistory)
					shouldUseHistoric, delayBusCount, _ := HandleDelayReverseLookup(fromStop, toStop,
						departureTime, timeToStop, historicEstimate, realTimeEstimates)
					if shouldUseHistoric {
						historicFromStopDetails[toStop]["mixedType"] = 1
						predictionData[fromStop] = historicFromStopDetails
						timeToStop = timeToStop + historicEstimate
					} else {
						realTimeFromStopDetails[toStop]["mixedType"] = 2
						predictionData[fromStop] = realTimeFromStopDetails
						timeToStop = timeToStop + realTimeEstimate
					}
					predictionData[fromStop][toStop]["delayBusCount"] = int64(delayBusCount)
					continue
				}
				/* Case 2: Normal */
				/* Use real time estimate only if all of real time journey history lie above / below threshold */
				for i := len(realTimeJourneyHistory) - 1; i >= 0; i-- {
					realTimeEstimate := time.Duration(realTimeJourneyHistory[i].TimeTaken) * time.Second
					if historicEstimate-DelayThreshold < realTimeEstimate &&
						realTimeEstimate < historicEstimate+DelayThreshold {
						/* Use historic estimate if lying within range */
						historicFromStopDetails[toStop]["mixedType"] = 1
						predictionData[fromStop] = historicFromStopDetails
						timeToStop = timeToStop + historicEstimate
						continue ChooseHistoricOrRealTime
					}
				}
				/* Otherwise use real time estimate */
				realTimeFromStopDetails[toStop]["mixedType"] = 2
				predictionData[fromStop] = realTimeFromStopDetails
				timeToStop = timeToStop + realTimeEstimate
			}
		}
	}
	return predictionData, historicData, realTimeData, nil
}
/* 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
}