class MyBusTracker::Service

Attributes

bus_stops[R]
name[R]
number[R]
operator[R]
ref[R]

Public Class Methods

new(client, appkey, mbt, service, number='') click to toggle source
# File lib/mybustracker.rb, line 26
def initialize(client, appkey, mbt,  service, number='')
  
  if number.empty? then
    raise MyBusTrackerException::Service, 'provide a bus service number'
  end
  
  @client, @appkey, @mbt = client, appkey, mbt
  
  @number, @name, @ref, relative_dests, operator  = \
      %i(mnemo name ref dests operator).map {|field| service[field]}      
  
  Thread.new{ fetch_bus_stops() }
  
end

Public Instance Methods

inspect() click to toggle source
# File lib/mybustracker.rb, line 41
def inspect()
  "<#<MyBusTracker::Service:%s @number=\"%s\">" % [self.object_id, @number]
end
query(times: 'next hour', from: nil, to: nil) click to toggle source

accepts a bus service number and returns the relative bus times

# File lib/mybustracker.rb, line 47
def query(times: 'next hour', from: nil, to: nil)
  
  #from ||=
  
  start_bus_stop1, start_bus_stop2 = find_bus_stop(from)
  end_bus_stop1, end_bus_stop2 = find_bus_stop(to)

  # get the bus times
  
  bus_times = get_bus_times(start_bus_stop1)            
  
  journey_times = get_stop_journeys(start_bus_stop1, bus_times, index: 0)
  return unless journey_times

  # select the bus stop end
  
  end_stop = journey_times.find do |x| 
    x[:stop_id] == end_bus_stop1[:stop_id] or 
        x[:stop_id] == end_bus_stop2[:stop_id]
  end
  
        
  if end_stop then
    start_bus_stop = start_bus_stop1
  else
    start_bus_stop = start_bus_stop2
    bus_times = get_bus_times(start_bus_stop2)
    
    unless end_stop
      journey_times = get_stop_journeys(start_bus_stop2, bus_times)
    end
    
    return unless journey_times
    # select the bus stop end

    end_stop = journey_times.find do |x|
      (x[:stop_id] == end_bus_stop1[:stop_id]) or 
          (x[:stop_id] == end_bus_stop2[:stop_id])
    end
    
  end
  
  stop_id = end_stop[:stop_id]      
  
  # get the other journeys
  # still todo
  journeys = [[journey_times[0][:time], end_stop[:time]]]
  journey = get_stop_journeys(start_bus_stop, bus_times, index: 1)      
  
  if journey then
    end_stop = journey.find {|x| x[:stop_id] == stop_id }

    journeys << [journey[0][:time], end_stop[:time]] 
  end
  
  # get the journeys for the given period
  #secs = journeys[1][0][:time] - journey_times[0][:time]
  
  from_times = journeys.map {|x| Time.strptime(x.first, "%H:%M").strftime("%-I:%M%P")}
  to_times = journeys.map {|x| Time.strptime(x.last, "%H:%M").strftime("%-I:%M%P")}

  tstart = Time.strptime(journeys[0][0],"%H:%M")
  tend = Time.strptime(journeys[0][-1],"%H:%M")
  travel_time = '~' + Subunit.new(units={minutes:60, hours:60}, \
                             seconds: tend - tstart).to_s(omit: [:seconds])
  
  index = journey_times.index journey_times.find {|x| x[:stop_id] == stop_id}
  stops = journey_times[0..index].map {|x| x[:stop_name] }
  
  {
    from: {bus_stop: start_bus_stop[:name], bus_stop_id: 
           start_bus_stop[:stop_id], times: from_times},
    to: {bus_stop: end_stop[:stop_name], bus_stop_id: end_stop[:stop_id], 
         times: to_times},
    stops: stops ,
    start: tstart.strftime("%-I:%M%P"), 
    end: tend.strftime("%-I:%M%P"),
    travel_time: travel_time
  }
  
end

Private Instance Methods

fetch_bus_stops() click to toggle source

returns all bus stops for outbound route (“R”)

# File lib/mybustracker.rb, line 173
def fetch_bus_stops()
  
  client, appkey, ref = @client, @appkey, @ref
  
  response = client.call(:get_dests, message: { key: appkey  })
  r = response.body

  response = client.call(:get_bus_stops, message: { key: appkey  })
  all_bus_stops = response.body[:bus_stops_response][:bus_stops][:list]

  r[:dests_response][:dests][:list][0].keys
  #=> [:ref, :operator_id, :name, :direction, :service]

  dest = r[:dests_response][:dests][:list].find do |d|
    d[:service] == ref and d[:direction] == 'R'
  end

  raw_bus_stops = all_bus_stops.select do |bus_stop|
    bus_stop[:dests][:list].include? dest[:ref]
  end

  c = ->(coord){ coord.to_f.round(4)}      

  response = client.call(:get_service_points, message: \
                        { key: appkey, ref: ref  })
  all_service_points = response.body[:service_points_response]\
      [:service_points][:list]      

  unsorted_bus_stops = []
  raw_bus_stops.each do |bus_stop|

    x, y = %i(x y).map {|field| bus_stop[field]}.map(&c)

    r = all_service_points.select do |point|
      [point[:x], point[:y]].map(&c) == [x, y]
    end

    r.each do |x|
      unsorted_bus_stops << [bus_stop[:name], 
                             bus_stop[:stop_id], x, x[:order].to_i ]
    end

  end
      
  # find the correct chainage by the most records
  h = unsorted_bus_stops.group_by {|x| x[2][:chainage]}
  a = h.map {|k,v| v.count {|x| x[2][:chainage] == k}}      

  @bus_stops = h.to_a[a.index(a.max)].last.sort_by(&:last).map(&:first)
  
end
find_bus_stop(address) click to toggle source
# File lib/mybustracker.rb, line 132
def find_bus_stop(address)
  
  @mbt.find_nearest_stops(address, limit: 2).map(&:first)
        
end
get_bus_times(start_bus_stop) click to toggle source
# File lib/mybustracker.rb, line 139
def get_bus_times(start_bus_stop)
  
  response = @client.call(:get_bus_times, message: { key: @appkey, 
           time_requests: {list: [{stop_id: start_bus_stop[:stop_id] }]} })
  
  response.body[:bus_times_response][:bus_times][:list].find do |bus_time|
    bus_time[:ref_service] == @ref
  end      
end
get_stop_journeys(start_bus_stop, bus_times, index: 0) click to toggle source
# File lib/mybustracker.rb, line 149
def get_stop_journeys(start_bus_stop, bus_times, index: 0)
  
  
  return unless bus_times
  
  # get the 1st journey id
  list = bus_times[:time_datas][:list]
       
  journey_id = list.is_a?(Array) ? list[index][:journey_id] : \
                  list[:journey_id]    
  response = @client.call(:get_journey_times, message: { key: @appkey, 
             journey_id: journey_id,  stop_id: start_bus_stop[:stop_id]  })

  return unless response.body[:journey_times_response][:journey_times]
  
  journey = response.body[:journey_times_response][:journey_times][:list]

  journey_times = journey[:journey_time_datas][:list]
                                         
  return journey_times
end